// new data from network.. this effectively means we have a fork.. // can we implement merge rules? // Temporarily: only appending with new version nr at end. // this will very likely lead to corrupted stream if any real // concurrent usage of the drive occurs. // TODO: Needs A LOT of work. async Task <bool> TryMergeAsync(NetworkEvent evt, WALContent walContent) { var newData = await _service .LoadAsync(evt.SequenceNr - 1) .ToListAsync(); switch (evt) { case NetworkFileContentSet e when IsUnresolvableConflict(e, newData): return(false); case NetworkFileItemCreated e: break; case NetworkFileContentCleared e: break; case NetworkItemCopied e: break; case NetworkItemMoved e: break; case NetworkDirectoryItemCreated e: break; case NetworkItemRemoved e: break; case NetworkItemRenamed e: break; case null: throw new ArgumentNullException(nameof(evt)); default: throw new NotImplementedException(evt.GetType().Name); } // naively just try apply the remote changes var caughtUp = await _materializer.Materialize(newData.ToAsyncEnumerable()); if (!caughtUp) { return(false); } walContent.SequenceNr = newData.Max(c => c.SequenceNr) + 1; return(await Upload(walContent)); }
async Task <SAFENetworkContext> RequireContextAsync(RootName root, string apiKey = null) { if (root == null) { throw new ArgumentNullException(nameof(root)); } if (!_contextCache.TryGetValue(root, out SAFENetworkContext result)) { var(stream, store) = await DbFactory.GetDriveDbsAsync(root, apiKey, _secretKey); _sequenceNr = new SequenceNr(); var localState = new Memory.MemoryGateway(); var driveCache = new Memory.SAFENetworkDriveCache(store, localState); var network = new SAFENetworkEventService(stream, store, _secretKey); var materializer = new DriveMaterializer(root, localState, _sequenceNr); var conflictHandler = new VersionConflictHandler(network, materializer); var driveWriter = new DriveWriter(root, driveCache, _sequenceNr); var dbName = Utils.Scrambler.Obfuscate(root.Value, _secretKey); var transactor = new EventTransactor(driveWriter, new DiskWALTransactor(dbName, conflictHandler.Upload), _secretKey); _contextCache.Add(root, result = new SAFENetworkContext(transactor, new DriveReader(driveCache))); var _ = driveCache.GetDrive(root, apiKey, _parameters); // needs to be loaded // We need to wait for all events in local WAL to have been persisted to network // before we materialize new events from network. transactor.Start(_cancellation); // start uploading to network while (DiskWALTransactor.AnyInQueue(dbName)) // wait until queue is empty { await Task.Delay(500); // beware, this will - currently - spin eternally if there is an unresolved version conflict } // (todo: should load snapshot + all events since) var allEvents = network.LoadAsync(fromVersion: 0); // load all events from network (since we don't store it locally) var isMaterialized = await materializer.Materialize(allEvents); // recreate the filesystem locally in memory if (!isMaterialized) { throw new InvalidDataException("Could not materialize network filesystem!"); } } return(result); }