Example #1
0
        public DriveWriter(RootName root, SAFENetworkDriveCache gateway, SequenceNr sequenceNr)
        {
            _root       = root;
            _localState = gateway;
            _sequenceNr = sequenceNr;
            _apply      = new ConcurrentDictionary <Type, Func <LocalEvent, object> >();
            var applyMethods = GetAllMethods(this.GetType())
                               .Where(m => m.Name == "Apply");

            foreach (var m in applyMethods)
            {
                _apply[m.GetParameters().First().ParameterType] = new Func <LocalEvent, object>((e) => m.Invoke(this, new object[] { e }));
            }
        }
        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);
        }