| 307 | |
| 308 | |
| 309 | Future<Nothing> LogStorageProcess::apply(const list<Log::Entry>& entries) |
| 310 | { |
| 311 | VLOG(2) << "Applying operations (" << entries.size() << " entries)"; |
| 312 | |
| 313 | // Only read and apply entries past our index. |
| 314 | foreach (const Log::Entry& entry, entries) { |
| 315 | if (index.isNone() || index.get() < entry.position) { |
| 316 | // Parse the Operation from the Log::Entry. |
| 317 | Operation operation; |
| 318 | |
| 319 | google::protobuf::io::ArrayInputStream stream( |
| 320 | entry.data.data(), |
| 321 | entry.data.size()); |
| 322 | |
| 323 | if (!operation.ParseFromZeroCopyStream(&stream)) { |
| 324 | return Failure("Failed to deserialize Operation"); |
| 325 | } |
| 326 | |
| 327 | switch (operation.type()) { |
| 328 | case Operation::SNAPSHOT: { |
| 329 | CHECK(operation.has_snapshot()); |
| 330 | |
| 331 | // Add or update (override) the snapshot. |
| 332 | Snapshot snapshot(entry.position, operation.snapshot().entry()); |
| 333 | snapshots.put(snapshot.entry.name(), snapshot); |
| 334 | break; |
| 335 | } |
| 336 | |
| 337 | case Operation::DIFF: { |
| 338 | CHECK(operation.has_diff()); |
| 339 | |
| 340 | Option<Snapshot> snapshot = |
| 341 | snapshots.get(operation.diff().entry().name()); |
| 342 | |
| 343 | CHECK_SOME(snapshot); |
| 344 | |
| 345 | Try<Snapshot> patched = snapshot->patch(operation.diff()); |
| 346 | |
| 347 | if (patched.isError()) { |
| 348 | return Failure("Failed to apply the diff: " + patched.error()); |
| 349 | } |
| 350 | |
| 351 | // Replace the snapshot with the patched snapshot. |
| 352 | snapshots.put(patched->entry.name(), patched.get()); |
| 353 | break; |
| 354 | } |
| 355 | |
| 356 | case Operation::EXPUNGE: { |
| 357 | CHECK(operation.has_expunge()); |
| 358 | snapshots.erase(operation.expunge().name()); |
| 359 | break; |
| 360 | } |
| 361 | |
| 362 | default: |
| 363 | return Failure("Unknown operation: " + stringify(operation.type())); |
| 364 | } |
| 365 | |
| 366 | index = entry.position; |