/// <summary> /// Returns the list of names of all existing classes /// </summary> public Task<List<string>> AvailableClasses(IFdbReadOnlyTransaction tr) { return tr.GetRange(this.Subspace.Keys.ToRange(FdbTuple.Create("class"))) .Where(kvp => { int _; return Int32.TryParse(kvp.Value.ToAscii(), out _); }) // (step 3) .Select(kvp => this.Subspace.Keys.Decode<string>(kvp.Key)) .ToListAsync(); }
public IAsyncEnumerable <KeyValuePair <TKey, TValue> > All([NotNull] IFdbReadOnlyTransaction trans, FdbRangeOptions options = null) { if (trans == null) { throw new ArgumentNullException(nameof(trans)); } return(trans .GetRange(this.Subspace.ToRange(), options) .Select(this.DecodeItem)); }
private Task <long> SlowCountAsync(IFdbReadOnlyTransaction trans, int level, Slice beginKey, Slice endKey) { if (level == -1) { return(Task.FromResult <long>(beginKey.IsPresent ? 1 : 0)); } return(trans .GetRange(this.Subspace.Encode(level, beginKey), this.Subspace.Encode(level, endKey)) .Select(kv => DecodeCount(kv.Value)) .SumAsync()); }
/// <summary>Get the value of the last item in the Vector.</summary> public Task <T> BackAsync(IFdbReadOnlyTransaction tr) { if (tr == null) { throw new ArgumentNullException(nameof(tr)); } return(tr .GetRange(this.Subspace.ToRange()) .Select((kvp) => this.Encoder.DecodeValue(kvp.Value) !) .LastOrDefaultAsync()); }
public static IAsyncEnumerable <KeyValuePair <Slice, Slice> > MergeSort <TKey>([NotNull] this IFdbReadOnlyTransaction trans, [NotNull] IEnumerable <KeySelectorPair> ranges, [NotNull] Func <KeyValuePair <Slice, Slice>, TKey> keySelector, IComparer <TKey> keyComparer = null) { //TODO: Range options ? Contract.NotNull(trans, nameof(trans)); Contract.NotNull(ranges, nameof(ranges)); Contract.NotNull(keySelector, nameof(keySelector)); trans.EnsureCanRead(); return(new MergeSortAsyncIterator <KeyValuePair <Slice, Slice>, TKey, KeyValuePair <Slice, Slice> >( ranges.Select(range => trans.GetRange(range, new FdbRangeOptions { Mode = FdbStreamingMode.Iterator })),
public IAsyncEnumerable <(TValue Value, long Count)> GetCounts([NotNull] IFdbReadOnlyTransaction trans, TKey key) { var range = KeyRange.StartsWith(this.Subspace.Keys.EncodePartial(key)); var query = trans .GetRange(range) .Select(kvp => (Value: this.Subspace.Keys.Decode(kvp.Key).Item2, Count: kvp.Value.ToInt64())); return(this.AllowNegativeValues ? query : query.Where(x => x.Count > 0)); }
/// <summary>Returns the number of items in the set.</summary> /// <param name="trans"></param> /// <returns></returns> public Task <long> SizeAsync(IFdbReadOnlyTransaction trans) { if (trans == null) { throw new ArgumentNullException(nameof(trans)); } return(trans .GetRange(this.Subspace.Partition.ByKey(MAX_LEVELS - 1).ToRange()) .Select(kv => DecodeCount(kv.Value)) .SumAsync()); }
private static async Task PrintRankedSet(FdbRankedSet rs, IFdbReadOnlyTransaction tr) { var sb = new StringBuilder(); for (int l = 0; l < 6; l++) { sb.AppendFormat("Level {0}:\r\n", l); await tr.GetRange(rs.Subspace.Partition(l).ToRange()).ForEachAsync((kvp) => { sb.AppendFormat("\t{0} = {1}\r\n", rs.Subspace.Unpack(kvp.Key), kvp.Value.ToInt64()); }); } Console.WriteLine(sb.ToString()); }
private static async Task PrintRankedSet(FdbRankedSet rs, IFdbReadOnlyTransaction tr) { var sb = new StringBuilder(); for (int l = 0; l < 6; l++) { sb.AppendFormat("Level {0}:\r\n", l); await tr.GetRange(rs.Subspace.Partition.ByKey(l).Keys.ToRange()).ForEachAsync((kvp) => { sb.AppendFormat("\t{0} = {1}\r\n", rs.Subspace.Keys.Unpack(kvp.Key), kvp.Value.ToInt64()); }); } Log(sb.ToString()); }
public IFdbAsyncEnumerable <TValue> Get([NotNull] IFdbReadOnlyTransaction trans, TKey key) { if (trans == null) { throw new ArgumentNullException("trans"); } var range = FdbKeyRange.StartsWith(this.Location.Partial.Keys.Encode(key)); if (this.AllowNegativeValues) { return(trans .GetRange(range) .Select(kvp => this.Location.Keys.Decode(kvp.Key).Item2)); } else { return(trans .GetRange(range) .Where(kvp => kvp.Value.ToInt64() > 0) // we need to filter out zero or negative values (possible artefacts) .Select(kvp => this.Location.Keys.Decode(kvp.Key).Item2)); } }
public static IFdbAsyncEnumerable <TResult> MergeSort <TKey, TResult>(this IFdbReadOnlyTransaction trans, IEnumerable <FdbKeySelectorPair> ranges, Func <KeyValuePair <Slice, Slice>, TKey> keySelector, Func <KeyValuePair <Slice, Slice>, TResult> resultSelector, IComparer <TKey> keyComparer = null) { //TODO: Range options ? trans.EnsureCanRead(); return(new FdbMergeSortIterator <KeyValuePair <Slice, Slice>, TKey, TResult>( ranges.Select(range => trans.GetRange(range, new FdbRangeOptions { Mode = FdbStreamingMode.Iterator })), default(int?), keySelector, resultSelector, keyComparer )); }
public static IFdbAsyncEnumerable <KeyValuePair <Slice, Slice> > Intersect <TKey>(this IFdbReadOnlyTransaction trans, IEnumerable <FdbKeySelectorPair> ranges, Func <KeyValuePair <Slice, Slice>, TKey> keySelector, IComparer <TKey> keyComparer = null) { //TODO: Range options ? trans.EnsureCanRead(); return(new FdbIntersectIterator <KeyValuePair <Slice, Slice>, TKey, KeyValuePair <Slice, Slice> >( ranges.Select(range => trans.GetRange(range, new FdbRangeOptions { Mode = FdbStreamingMode.Iterator })), default(int?), keySelector, TaskHelpers.Cache <KeyValuePair <Slice, Slice> > .Identity, keyComparer )); }
/// <summary>Get the value of the counter. /// Not recommended for use with read/write transactions when the counter is being frequently updated (conflicts will be very likely). /// </summary> public async Task <long> GetTransactional(IFdbReadOnlyTransaction trans) { if (trans == null) { throw new ArgumentNullException("trans"); } long total = 0; await trans .GetRange(this.Subspace.ToRange()) .ForEachAsync((kvp) => { checked { total += this.Encoder.DecodeValue(kvp.Value); } }) .ConfigureAwait(false); return(total); }
public IFdbAsyncEnumerable <KeyValuePair <TValue, long> > GetCounts([NotNull] IFdbReadOnlyTransaction trans, TKey key) { var range = FdbKeyRange.StartsWith(this.Location.Partial.Keys.Encode(key)); var query = trans .GetRange(range) .Select(kvp => new KeyValuePair <TValue, long>(this.Location.Keys.Decode(kvp.Key).Item2, kvp.Value.ToInt64())); if (this.AllowNegativeValues) { return(query); } else { return(query.Where(kvp => kvp.Value > 0)); } }
public static IFdbAsyncEnumerable <KeyValuePair <Slice, Slice> > Except <TKey>([NotNull] this IFdbReadOnlyTransaction trans, IEnumerable <KeySelectorPair> ranges, Func <KeyValuePair <Slice, Slice>, TKey> keySelector, IComparer <TKey> keyComparer = null) { //TODO: Range options ? Contract.NotNull(trans, nameof(trans)); Contract.NotNull(ranges, nameof(ranges)); Contract.NotNull(keySelector, nameof(keySelector)); trans.EnsureCanRead(); return(new FdbExceptIterator <KeyValuePair <Slice, Slice>, TKey, KeyValuePair <Slice, Slice> >( ranges.Select(range => trans.GetRange(range, new FdbRangeOptions { Mode = FdbStreamingMode.Iterator })), default(int?), keySelector, (kv) => kv, keyComparer )); }
public async Task <long?> Rank(IFdbReadOnlyTransaction trans, Slice key) { if (trans == null) { throw new ArgumentNullException(nameof(trans)); } if (key.IsNull) { throw new ArgumentException("Empty key not allowed in set", nameof(key)); } if (!(await ContainsAsync(trans, key).ConfigureAwait(false))) { return(default(long?)); } long r = 0; var rankKey = Slice.Empty; for (int level = MAX_LEVELS - 1; level >= 0; level--) { var lss = this.Subspace.Partition.ByKey(level); long lastCount = 0; var kcs = await trans.GetRange( KeySelector.FirstGreaterOrEqual(lss.Encode(rankKey)), KeySelector.FirstGreaterThan(lss.Encode(key)) ).ToListAsync().ConfigureAwait(false); foreach (var kc in kcs) { rankKey = lss.Decode <Slice>(kc.Key); lastCount = DecodeCount(kc.Value); r += lastCount; } r -= lastCount; if (rankKey == key) { break; } } return(r); }
public FdbRangeQuery <TId> LookupGreaterThan([NotNull] IFdbReadOnlyTransaction trans, TValue value, bool orEqual, bool reverse = false) { var prefix = this.Location.Partial.EncodeKey(value); if (!orEqual) { prefix = FdbKey.Increment(prefix); } var space = new FdbKeySelectorPair( FdbKeySelector.FirstGreaterThan(prefix), this.Location.ToSelectorPair().End ); return(trans .GetRange(space, new FdbRangeOptions { Reverse = reverse }) .Select((kvp) => this.Location.DecodeKey(kvp.Key).Item2)); }
private static async Task PrintVector <T>(FdbVector <T> vector, IFdbReadOnlyTransaction tr) { bool first = true; var sb = new StringBuilder(); await tr.GetRange(vector.Subspace.Keys.ToRange()).ForEachAsync((kvp) => { if (!first) { sb.Append(", "); } else { first = false; } sb.Append(vector.Subspace.Keys.DecodeLast <long>(kvp.Key) + ":" + kvp.Value.ToAsciiOrHexaString()); }); Console.WriteLine("> Vector: (" + sb.ToString() + ")"); }
public FdbRangeQuery <TId> LookupLessThan([NotNull] IFdbReadOnlyTransaction trans, TValue value, bool orEqual, bool reverse = false) { var prefix = this.Subspace.Keys.EncodePartial(value); if (orEqual) { prefix = FdbKey.Increment(prefix); } var space = new KeySelectorPair( KeySelector.FirstGreaterOrEqual(this.Subspace.ToRange().Begin), KeySelector.FirstGreaterThan(prefix) ); return(trans .GetRange(space, new FdbRangeOptions { Reverse = reverse }) .Select((kvp) => this.Subspace.Keys.Decode(kvp.Key).Item2)); }
private static async Task PrintVector <T>(FdbVector <T> .State vector, IFdbReadOnlyTransaction tr) { bool first = true; var sb = new StringBuilder(); await tr.GetRange(vector.Subspace.ToRange()).ForEachAsync((kvp) => { if (!first) { sb.Append(", "); } else { first = false; } sb.Append($"{vector.Subspace.DecodeLast<long>(kvp.Key)}:{kvp.Value:P}"); }); Log("> Vector: (" + sb.ToString() + ")"); }
/// <summary>Return the list the names of all fields of an hashset</summary> /// <param name="trans">Transaction that will be used for this request</param> /// <param name="id">Unique identifier of the hashset</param> /// <returns>List of all fields. If the list is empty, the hashset does not exist</returns> public Task <List <string> > GetKeys(IFdbReadOnlyTransaction trans, IVarTuple id) { //note: As of Beta2, FDB does not have a fdb_get_range that only return the keys. That means that we will have to also read the values from the db, in order to just get the names of the fields :( //TODO: find a way to optimize this ? if (trans == null) { throw new ArgumentNullException(nameof(trans)); } if (id == null) { throw new ArgumentNullException(nameof(id)); } var prefix = GetKey(id); return(trans .GetRange(KeyRange.StartsWith(prefix)) .Select((kvp) => ParseFieldKey(TuPack.Unpack(kvp.Key))) .ToListAsync()); }
/// <summary>Return the list the names of all fields of an hashset</summary> /// <param name="trans">Transaction that will be used for this request</param> /// <param name="id">Unique identifier of the hashset</param> /// <returns>List of all fields. If the list is empty, the hashset does not exist</returns> public Task <List <string> > GetKeys(IFdbReadOnlyTransaction trans, ITuple id, CancellationToken cancellationToken = default(CancellationToken)) { //note: As of Beta2, FDB does not have a fdb_get_range that only return the keys. That means that we will have to also read the values from the db, in order to just get the names of the fields :( //TODO: find a way to optimize this ? if (trans == null) { throw new ArgumentNullException(nameof(trans)); } if (id == null) { throw new ArgumentNullException(nameof(id)); } var prefix = GetKey(id); var results = new Dictionary <string, Slice>(StringComparer.OrdinalIgnoreCase); return(trans .GetRange(KeyRange.StartsWith(prefix)) .Select((kvp) => ParseFieldKey(STuple.Unpack(kvp.Key))) .ToListAsync(cancellationToken)); }
/// <summary>Get the value of the counter. /// Not recommended for use with read/write transactions when the counter is being frequently updated (conflicts will be very likely). /// </summary> public async Task <long> GetTransactional(IFdbReadOnlyTransaction trans) { if (trans == null) { throw new ArgumentNullException(nameof(trans)); } var subspace = await this.Location.Resolve(trans); if (subspace == null) { throw new InvalidOperationException($"Location '{this.Location} referenced by High Contention Counter Layer was not found."); } long total = 0; await trans .GetRange(subspace.ToRange()) .ForEachAsync((kvp) => { checked { total += this.Encoder.DecodeValue(kvp.Value); } }) .ConfigureAwait(false); return(total); }
public async Task <Slice> GetNthAsync(IFdbReadOnlyTransaction trans, long rank) { if (rank < 0) { return(Slice.Nil); } long r = rank; var key = Slice.Empty; for (int level = MAX_LEVELS - 1; level >= 0; level--) { var lss = this.Subspace.Partition.ByKey(level); var kcs = await trans.GetRange(lss.Encode(key), lss.ToRange().End).ToListAsync().ConfigureAwait(false); if (kcs.Count == 0) { break; } foreach (var kc in kcs) { key = lss.Decode <Slice>(kc.Key); long count = DecodeCount(kc.Value); if (key.IsPresent && r == 0) { return(key); } if (count > r) { break; } r -= count; } } return(Slice.Nil); }
public static async Task DumpSubspace(IFdbReadOnlyTransaction tr, IKeySubspace subspace) { Assert.That(tr, Is.Not.Null); Assert.That(subspace, Is.Not.Null); FdbTest.Log($"Dumping content of {subspace} at {subspace.GetPrefix():K}:"); int count = 0; await tr .GetRange(KeyRange.StartsWith(subspace.GetPrefix())) .ForEachAsync((kvp) => { var key = subspace.ExtractKey(kvp.Key, boundCheck: true); ++count; string keyDump; try { // attempts decoding it as a tuple keyDump = TuPack.Unpack(key).ToString() !; } catch (Exception) { // not a tuple, dump as bytes keyDump = "'" + key.ToString() + "'"; } FdbTest.Log("- " + keyDump + " = " + kvp.Value.ToString()); }); if (count == 0) { FdbTest.Log("> empty !"); } else { FdbTest.Log("> Found " + count + " values"); } }
public static async Task DumpSubspace([NotNull] IFdbReadOnlyTransaction tr, [NotNull] IFdbSubspace subspace) { Assert.That(tr, Is.Not.Null); Console.WriteLine("Dumping content of subspace " + subspace.ToString() + " :"); int count = 0; await tr .GetRange(KeyRange.StartsWith(subspace.Key)) .ForEachAsync((kvp) => { var key = subspace.ExtractKey(kvp.Key, boundCheck: true); ++count; string keyDump = null; try { // attemps decoding it as a tuple keyDump = key.ToTuple().ToString(); } catch (Exception) { // not a tuple, dump as bytes keyDump = "'" + key.ToString() + "'"; } Console.WriteLine("- " + keyDump + " = " + kvp.Value.ToString()); }); if (count == 0) { Console.WriteLine("> empty !"); } else { Console.WriteLine("> Found " + count + " values"); } }
private Task <List <KeyValuePair <Slice, Slice> > > GetItemsAsync([NotNull] IFdbReadOnlyTransaction tr, int numItems) { var range = this.QueueItem.Keys.ToRange(); return(tr.GetRange(range, limit: numItems, reverse: false).ToListAsync()); }
private Task<long> SlowCountAsync(IFdbReadOnlyTransaction trans, int level, Slice beginKey, Slice endKey) { if (level == -1) { return Task.FromResult<long>(beginKey.IsPresent ? 1 : 0); } return trans .GetRange(this.Subspace.Pack(level, beginKey), this.Subspace.Pack(level, endKey)) .Select(kv => DecodeCount(kv.Value)) .SumAsync(); }
/// <summary> /// Read from the blob, starting at <paramref name="offset"/>, retrieving up to <paramref name="n"/> bytes (fewer then n bytes are returned when the end of the blob is reached). /// </summary> public async Task <Slice> ReadAsync([NotNull] IFdbReadOnlyTransaction trans, long offset, int n) { if (trans == null) { throw new ArgumentNullException("trans"); } if (offset < 0) { throw new ArgumentNullException("offset", "Offset cannot be less than zero"); } long?size = await GetSizeAsync(trans).ConfigureAwait(false); if (size == null) { return(Slice.Nil); // not found } if (offset >= size.Value) { return(Slice.Empty); } // read all chunks matching the segment we need, and copy them in our buffer var buffer = new byte[Math.Min(n, size.Value - offset)]; await trans .GetRange( FdbKeySelector.LastLessOrEqual(DataKey(offset)), FdbKeySelector.FirstGreaterOrEqual(DataKey(offset + n)) ) .ForEachAsync((chunk) => { // get offset of this chunk long chunkOffset = DataKeyOffset(chunk.Key); Slice chunkData = chunk.Value; checked { // intersect chunk bounds with output int delta = (int)(chunkOffset - offset); int start = delta; int end = delta + chunkData.Count; if (start < 0) { start = 0; } if (end > n) { end = n; } // compute the relative offsets in the chunk int rStart = start - delta; int rEnd = end - delta; var intersect = chunkData[rStart, rEnd]; if (intersect.IsPresent) { // copy the data that fits intersect.CopyTo(buffer, start); } } }) .ConfigureAwait(false); return(new Slice(buffer, 0, buffer.Length)); }
/// <summary>Get the value of the counter. /// Not recommended for use with read/write transactions when the counter is being frequently updated (conflicts will be very likely). /// </summary> public async Task<long> GetTransactional(IFdbReadOnlyTransaction trans) { if (trans == null) throw new ArgumentNullException("trans"); long total = 0; await trans .GetRange(this.Subspace.ToRange()) .ForEachAsync((kvp) => { checked { total += this.Encoder.DecodeValue(kvp.Value); } }) .ConfigureAwait(false); return total; }
public static FdbRangeQuery <KeyValuePair <Slice, Slice> > GetRangeStartsWith(this IFdbReadOnlyTransaction trans, [NotNull] FdbSubspace subspace, FdbRangeOptions options = null) { Contract.Requires(trans != null && subspace != null); return(trans.GetRange(FdbKeyRange.StartsWith(subspace.Key), options)); }
public virtual FdbRangeQuery <KeyValuePair <Slice, Slice> > GetRange(KeySelector beginInclusive, KeySelector endInclusive, FdbRangeOptions options = null) { return(m_transaction.GetRange(beginInclusive, endInclusive, options)); }
/// <summary>Returns the list of names and nodes of all children of the specified node</summary> private IFdbAsyncEnumerable<KeyValuePair<string, FdbSubspace>> SubdirNamesAndNodes(IFdbReadOnlyTransaction tr, FdbSubspace node) { Contract.Requires(tr != null && node != null); var sd = node.Partition(SUBDIRS); return tr .GetRange(sd.ToRange()) .Select(kvp => new KeyValuePair<string, FdbSubspace>( sd.UnpackSingle<string>(kvp.Key), NodeWithPrefix(kvp.Value) )); }
/// <summary> /// Read from the blob, starting at <paramref name="offset"/>, retrieving up to <paramref name="n"/> bytes (fewer then n bytes are returned when the end of the blob is reached). /// </summary> public async Task<Slice> ReadAsync(IFdbReadOnlyTransaction trans, long offset, int n) { if (trans == null) throw new ArgumentNullException("trans"); if (offset < 0) throw new ArgumentNullException("offset", "Offset cannot be less than zero"); long? size = await GetSizeAsync(trans).ConfigureAwait(false); if (size == null) return Slice.Nil; // not found if (offset >= size.Value) return Slice.Empty; // read all chunks matching the segment we need, and copy them in our buffer var buffer = new byte[Math.Min(n, size.Value - offset)]; await trans .GetRange( FdbKeySelector.LastLessOrEqual(DataKey(offset)), FdbKeySelector.FirstGreaterOrEqual(DataKey(offset + n)) ) .ForEachAsync((chunk) => { // get offset of this chunk long chunkOffset = DataKeyOffset(chunk.Key); Slice chunkData = chunk.Value; checked { // intersect chunk bounds with output int delta = (int)(chunkOffset - offset); int start = delta; int end = delta + chunkData.Count; if (start < 0) start = 0; if (end > n) end = n; // compute the relative offsets in the chunk int rStart = start - delta; int rEnd = end - delta; var intersect = chunkData[rStart, rEnd]; if (intersect.IsPresent) { // copy the data that fits intersect.CopyTo(buffer, start); } } }) .ConfigureAwait(false); return new Slice(buffer, 0, buffer.Length); }
private Task <KeyValuePair <Slice, Slice> > GetFirstItemAsync([NotNull] IFdbReadOnlyTransaction tr) { var range = this.QueueItem.Keys.ToRange(); return(tr.GetRange(range).FirstOrDefaultAsync()); }
private Task <List <KeyValuePair <Slice, Slice> > > GetWaitingPopsAsync([NotNull] IFdbReadOnlyTransaction tr, int numPops) { var range = this.ConflictedPop.Keys.ToRange(); return(tr.GetRange(range, limit: numPops, reverse: false).ToListAsync()); }
/// <summary>Return the list the names of all fields of an hashset</summary> /// <param name="trans">Transaction that will be used for this request</param> /// <param name="id">Unique identifier of the hashset</param> /// <returns>List of all fields. If the list is empty, the hashset does not exist</returns> public Task<List<string>> GetKeys(IFdbReadOnlyTransaction trans, IFdbTuple id, CancellationToken cancellationToken = default(CancellationToken)) { //note: As of Beta2, FDB does not have a fdb_get_range that only return the keys. That means that we will have to also read the values from the db, in order to just get the names of the fields :( //TODO: find a way to optimize this ? if (trans == null) throw new ArgumentNullException("trans"); if (id == null) throw new ArgumentNullException("id"); var prefix = GetKey(id); var results = new Dictionary<string, Slice>(StringComparer.OrdinalIgnoreCase); return trans .GetRange(FdbKeyRange.StartsWith(prefix)) .Select((kvp) => ParseFieldKey(FdbTuple.Unpack(kvp.Key))) .ToListAsync(cancellationToken); }
private async Task<bool> IsPrefixFree(IFdbReadOnlyTransaction tr, Slice prefix) { Contract.Requires(tr != null); // Returns true if the given prefix does not "intersect" any currently // allocated prefix (including the root node). This means that it neither // contains any other prefix nor is contained by any other prefix. if (prefix.IsNullOrEmpty) return false; if (await NodeContainingKey(tr, prefix).ConfigureAwait(false) != null) return false; return await tr .GetRange( this.NodeSubspace.Pack(prefix), this.NodeSubspace.Pack(FdbKey.Increment(prefix)) ) .NoneAsync() .ConfigureAwait(false); }
private async Task<FdbSubspace> NodeContainingKey(IFdbReadOnlyTransaction tr, Slice key) { Contract.Requires(tr != null); // Right now this is only used for _is_prefix_free(), but if we add // parent pointers to directory nodes, it could also be used to find a // path based on a key. if (this.NodeSubspace.Contains(key)) return this.RootNode; var kvp = await tr .GetRange( this.NodeSubspace.ToRange().Begin, this.NodeSubspace.Pack(key) + FdbKey.MinValue ) .LastOrDefaultAsync() .ConfigureAwait(false); if (kvp.Key.HasValue) { var prevPrefix = this.NodeSubspace.UnpackFirst<Slice>(kvp.Key); if (key.StartsWith(prevPrefix)) { return NodeWithPrefix(prevPrefix); } } return null; }
/// <summary>Return all fields of an hashset</summary> /// <param name="trans">Transaction that will be used for this request</param> /// <param name="id">Unique identifier of the hashset</param> /// <returns>Dictionary containing, for all fields, their associated values</returns> public async Task<IDictionary<string, Slice>> GetAsync(IFdbReadOnlyTransaction trans, IFdbTuple id) { if (trans == null) throw new ArgumentNullException("trans"); if (id == null) throw new ArgumentNullException("id"); var prefix = GetKey(id); var results = new Dictionary<string, Slice>(StringComparer.OrdinalIgnoreCase); await trans .GetRange(FdbKeyRange.StartsWith(prefix)) .ForEachAsync((kvp) => { string field = this.Subspace.UnpackLast<string>(kvp.Key); results[field] = kvp.Value; }) .ConfigureAwait(false); return results; }