Beispiel #1
0
        /// <summary>
        /// Transfers the data with the key and entry to the local store.
        /// </summary>
        /// <param name="entry"></param>
        /// <param name="value"></param>
        /// <param name="dht"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        async Task TransferAsync(IKsStoreEntry <TKey> entry, KsHashTableValue value, KsHashTableEntry dht, CancellationToken cancellationToken)
        {
            foreach (var uri in dht.Endpoints)
            {
                // we can't pull the value from ourselves, move to secondaries
                if (uri == options.Value.Uri)
                {
                    continue;
                }

                var client = clients.Get(uri);
                if (client == null)
                {
                    throw new KsException($"Could not obtain client for remote host: '{uri}'");
                }

                // existing token if we're resuming an operation after failure
                var t = await entry.GetOwnerTokenAsync(cancellationToken);

                var v = await client.ShiftLockAsync(entry.Key, t, cancellationToken);

                // current owner returns no value, must not really own it, nothing to transfer
                if (v == null)
                {
                    return;
                }

                // track down owner by following forwards
                while (v.Value.ForwardUri != null)
                {
                    client = clients.Get(v.Value.ForwardUri);
                    v      = await client.ShiftLockAsync(entry.Key, t, cancellationToken);
                }

                if (v.Value.Data == null)
                {
                    throw new KsException("Data not retrieved.");
                }
                if (v.Value.Data == null)
                {
                    throw new KsException("Data retrieved, but not token.");
                }

                // update local entry with latest information
                await entry.SetOwnerTokenAsync(t = v.Value.Token);

                await entry.SetAsync(v.Value.Data);

                // finalize shift on remote node and publish entry
                await client.ShiftAsync(entry.Key, t, options.Value.Uri, cancellationToken);

                await hashtable.AddAsync(entry.Key, new KsHashTableValue(Serialize(new KsHashTableEntry(new[] { options.Value.Uri })), value.Version + 1, TimeSpan.FromDays(1)));

                // we succeeded, exit loop
                break;
            }

            // zero out lock token if we successfully complete process
            await entry.SetOwnerTokenAsync(null);
        }
Beispiel #2
0
        /// <summary>
        /// Executes the given function after ensuring ownership of the key.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key"></param>
        /// <param name="func"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        async Task <T> Access <T>(TKey key, Func <IKsStoreEntry <TKey>, CancellationToken, Task <T> > func, bool shift, CancellationToken cancellationToken)
        {
            await using var entry = await store.OpenAsync(key, cancellationToken);

            var v = await hashtable.GetAsync(key, cancellationToken);

            // value is unknown to the system
            if (v == null)
            {
                // initial publish of DHT record
                v = new KsHashTableValue(Serialize(new KsHashTableEntry(new[] { options.Value.Uri })), 1, TimeSpan.FromDays(1));
                await hashtable.AddAsync(key, v, cancellationToken);

                return(await func(entry, cancellationToken));
            }

            // try to transfer object until transfer succeeds
            if (shift)
            {
                var e = Deserialize(v.Value.Data);
                while (e.Endpoints.Length == 0 || e.Endpoints[0] != options.Value.Uri)
                {
                    await TransferAsync(entry, v.Value, e, cancellationToken);

                    v = await hashtable.GetAsync(key, cancellationToken);

                    e = Deserialize(v.Value.Data);
                }
            }

            return(await func(entry, cancellationToken));
        }