/// <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); }
async Task <KsHostShiftLockResult> ShiftLockAsyncImpl(IKsStoreEntry <TKey> entry, string token, CancellationToken cancellationToken) { // freeze var f = await entry.FreezeAsync(token, TimeSpan.FromSeconds(5), cancellationToken); if (f.ForwardUri != null) { return(new KsHostShiftLockResult(null, null, f.ForwardUri)); } // get existing value var d = await entry.GetAsync(f.Token, cancellationToken); if (d.ForwardUri != null) { return(new KsHostShiftLockResult(null, null, d.ForwardUri)); } return(new KsHostShiftLockResult(f.Token, d.Data, null)); }
async Task <byte[]> GetAsyncImpl(IKsStoreEntry <TKey> entry, CancellationToken cancellationToken) { var r = await entry.GetAsync(null, cancellationToken); return(r.Data); }
async Task ShiftAsyncImpl(IKsStoreEntry <TKey> entry, string token, Uri forwardUri, CancellationToken cancellationToken) { await hashtable.RemoveAsync(entry.Key, CancellationToken.None); await entry.ForwardAsync(token, forwardUri, CancellationToken.None); }