Exemple #1
0
        /// <summary>
        /// Signup a student to a class
        /// </summary>
        public async Task Signup(IFdbTransaction tr, string s, string c)
        {
            var rec = AttendsKey(s, c);

            if ((await tr.GetAsync(rec)).IsPresent)
            {             // already signed up
                return;
            }
            int seatsLeft = Int32.Parse((await tr.GetAsync(ClassKey(c))).ToStringAscii());

            if (seatsLeft <= 0)
            {
                throw new InvalidOperationException("No remaining seats");
            }

            var classes = await tr.GetRange(AttendsKeys(s)).ToListAsync();

            if (classes.Count >= 5)
            {
                throw new InvalidOperationException("Too many classes");
            }

            tr.Set(ClassKey(c), Slice.FromStringAscii((seatsLeft - 1).ToString()));
            tr.Set(rec, Slice.Empty);
        }
        private async Task <KeyValuePair <Slice, Slice> > FindRandomItem(IFdbTransaction tr, IDynamicKeySubspace ring)
        {
            var range = ring.Keys.ToRange();

            // start from a random position around the ring
            Slice key = ring.Keys.Encode(GetRandomId());

            // We want to find the next item in the clockwise direction. If we reach the end of the ring, we "wrap around" by starting again from the start
            // => So we do find_next(key <= x < MAX) and if that does not produce any result, we do a find_next(MIN <= x < key)

            // When the ring only contains a few items (or is empty), there is more than 50% change that we wont find anything in the first read.
            // To reduce the latency for this case, we will issue both range reads at the same time, and discard the second one if the first returned something.
            // This should reduce the latency in half when the ring is empty, or when it contains only items before the random key.

            var candidate = await tr.GetRange(key, range.End).FirstOrDefaultAsync();

            if (!candidate.Key.IsPresent)
            {
                candidate = await tr.GetRange(range.Begin, key).FirstOrDefaultAsync();
            }

            return(candidate);
        }
Exemple #3
0
            /// <summary>Get and pops the last item off the Vector.</summary>
            public async Task <(T Value, bool HasValue)> PopAsync(IFdbTransaction tr)
            {
                if (tr == null)
                {
                    throw new ArgumentNullException(nameof(tr));
                }

                var keyRange = this.Subspace.ToRange();

                // Read the last two entries so we can check if the second to last item
                // is being represented sparsely. If so, we will be required to set it
                // to the default value
                var lastTwo = await tr
                              .GetRange(keyRange, new FdbRangeOptions { Reverse = true, Limit = 2 })
                              .ToListAsync()
                              .ConfigureAwait(false);

                // Vector was empty
                if (lastTwo.Count == 0)
                {
                    return(default);
Exemple #4
0
        /// <summary>Get and pops the last item off the Vector.</summary>
        public async Task <Optional <T> > PopAsync([NotNull] IFdbTransaction tr)
        {
            if (tr == null)
            {
                throw new ArgumentNullException("tr");
            }

            var keyRange = this.Subspace.Keys.ToRange();

            // Read the last two entries so we can check if the second to last item
            // is being represented sparsely. If so, we will be required to set it
            // to the default value
            var lastTwo = await tr
                          .GetRange(keyRange, new FdbRangeOptions { Reverse = true, Limit = 2 })
                          .ToListAsync()
                          .ConfigureAwait(false);

            // Vector was empty
            if (lastTwo.Count == 0)
            {
                return(default(Optional <T>));
            }

            //note: keys are reversed so indices[0] = last, indices[1] = second to last
            var indices = lastTwo.Select(kvp => this.Subspace.Keys.DecodeFirst <long>(kvp.Key)).ToList();

            if (indices[0] == 0)
            {             // Vector has size one
                //pass
            }
            else if (lastTwo.Count == 1 || indices[0] > indices[1] + 1)
            {             // Second to last item is being represented sparsely
                tr.Set(GetKeyAt(indices[0] - 1), this.Encoder.EncodeValue(this.DefaultValue));
            }

            tr.Clear(lastTwo[0].Key);

            return(this.Encoder.DecodeValue(lastTwo[0].Value));
        }
		private async Task<KeyValuePair<Slice, Slice>> FindRandomItem(IFdbTransaction tr, FdbSubspace ring)
		{
			var range = ring.ToRange();

			// start from a random position around the ring
			Slice key = ring.Pack(GetRandomId());

			// We want to find the next item in the clockwise direction. If we reach the end of the ring, we "wrap around" by starting again from the start
			// => So we do find_next(key <= x < MAX) and if that does not produce any result, we do a find_next(MIN <= x < key)

			// When the ring only contains a few items (or is empty), there is more than 50% change that we wont find anything in the first read.
			// To reduce the latency for this case, we will issue both range reads at the same time, and discard the second one if the first returned something.
			// This should reduce the latency in half when the ring is empty, or when it contains only items before the random key.

			var candidate = await tr.GetRange(key, range.End).FirstOrDefaultAsync();

			if (!candidate.Key.IsPresent)
			{
				candidate = await tr.GetRange(range.Begin, key).FirstOrDefaultAsync();
			}

			return candidate;
		}
 public virtual FdbRangeQuery <KeyValuePair <Slice, Slice> > GetRange(KeySelector beginInclusive, KeySelector endExclusive, FdbRangeOptions options = null)
 {
     ThrowIfDisposed();
     return(m_transaction.GetRange(beginInclusive, endExclusive, options));
 }
		internal async Task<FdbDirectorySubspace> CreateOrOpenInternalAsync(IFdbReadOnlyTransaction readTrans, IFdbTransaction trans, [NotNull] IFdbTuple path, Slice layer, Slice prefix, bool allowCreate, bool allowOpen, bool throwOnError)
		{
			Contract.Requires(readTrans != null || trans != null, "Need at least one transaction");
			Contract.Requires(path != null, "Path must be specified");
			Contract.Requires(readTrans == null || trans == null || object.ReferenceEquals(readTrans, trans), "The write transaction should be the same as the read transaction");

			if (path.Count == 0)
			{ // Root directory contains node metadata and so may not be opened.
				throw new InvalidOperationException("The root directory may not be opened.");
			}

			// to open an existing directory, we only need the read transaction
			// if none was specified, we can use the writeable transaction
			if (readTrans == null) readTrans = trans;

			await CheckReadVersionAsync(readTrans).ConfigureAwait(false);

			if (prefix.HasValue && this.Path.Count > 0)
				throw new InvalidOperationException("Cannot specify a prefix in a partition.");

			var existingNode = await FindAsync(readTrans, path).ConfigureAwait(false);

			if (existingNode.Exists)
			{
				if (existingNode.IsInPartition(false))
				{
					var subpath = existingNode.PartitionSubPath;
					var dl = GetPartitionForNode(existingNode).DirectoryLayer;
					return await dl.CreateOrOpenInternalAsync(readTrans, trans, subpath, layer, prefix, allowCreate, allowOpen, throwOnError).ConfigureAwait(false);
				}

				if (!allowOpen)
				{
					if (throwOnError) throw new InvalidOperationException(string.Format("The directory {0} already exists.", path));
					return null;
				}

				if (layer.IsPresent && layer != existingNode.Layer)
				{
					throw new InvalidOperationException(String.Format("The directory {0} was created with incompatible layer {1} instead of expected {2}.", path, layer.ToAsciiOrHexaString(), existingNode.Layer.ToAsciiOrHexaString()));
				}
				return ContentsOfNode(existingNode.Subspace, path, existingNode.Layer);
			}

			if (!allowCreate)
			{
				if (throwOnError) throw new InvalidOperationException(string.Format("The directory {0} does not exist.", path));
				return null;
			}

			// from there, we actually do need a wrtieable transaction
			if (trans == null) throw new InvalidOperationException("A writeable transaction is needed to create a new directory");

			await CheckWriteVersionAsync(trans).ConfigureAwait(false);

			if (prefix == null)
			{ // automatically allocate a new prefix inside the ContentSubspace
				long id = await this.Allocator.AllocateAsync(trans).ConfigureAwait(false);
				prefix = this.ContentSubspace.Pack(id);

				// ensure that there is no data already present under this prefix
				if (FdbDirectoryLayer.AnnotateTransactions) trans.Annotate("Ensure that there is no data already present under prefix {0}", prefix);
				if (await trans.GetRange(FdbKeyRange.StartsWith(prefix)).AnyAsync().ConfigureAwait(false))
				{
					throw new InvalidOperationException(String.Format("The database has keys stored at the prefix chosen by the automatic prefix allocator: {0}", prefix.ToAsciiOrHexaString()));
				}

				// ensure that the prefix has not already been allocated
				if (FdbDirectoryLayer.AnnotateTransactions) trans.Annotate("Ensure that the prefix {0} has not already been allocated", prefix);
				if (!(await IsPrefixFree(trans.Snapshot, prefix).ConfigureAwait(false)))
				{
					throw new InvalidOperationException("The directory layer has manually allocated prefixes that conflict with the automatic prefix allocator.");
				}
			}
			else
			{
				if (FdbDirectoryLayer.AnnotateTransactions) trans.Annotate("Ensure that the prefix {0} hasn't already been allocated", prefix);
				// ensure that the prefix has not already been allocated
				if (!(await IsPrefixFree(trans, prefix).ConfigureAwait(false)))
				{
					throw new InvalidOperationException("The given prefix is already in use.");
				}
			}

			// we need to recursively create any missing parents
			FdbSubspace parentNode;
			if (path.Count > 1)
			{
				var parentSubspace = await CreateOrOpenInternalAsync(readTrans, trans, path.Substring(0, path.Count - 1), Slice.Nil, Slice.Nil, true, true, true).ConfigureAwait(false);
				parentNode = NodeWithPrefix(parentSubspace.Key);
			}
			else
			{
				parentNode = this.RootNode;
			}
			if (parentNode == null) throw new InvalidOperationException(string.Format("The parent directory of {0} doesn't exist.", path));

			// initialize the metadata for this new directory
			var node = NodeWithPrefix(prefix);
			if (FdbDirectoryLayer.AnnotateTransactions) trans.Annotate("Registering the new prefix {0} into the folder sub-tree", prefix);
			trans.Set(GetSubDirKey(parentNode, path.Get<string>(-1)), prefix);
			SetLayer(trans, node, layer);

			return ContentsOfNode(node, path, layer);
		}
		/// <summary>
		/// Signup a student to a class
		/// </summary>
		public async Task Signup(IFdbTransaction tr, string s, string c)
		{
			var rec = AttendsKey(s, c);

			if ((await tr.GetAsync(rec)).IsPresent)
			{ // already signed up
				return;
			}
			int seatsLeft = Int32.Parse((await tr.GetAsync(ClassKey(c))).ToAscii());
			if (seatsLeft <= 0)
			{
				throw new InvalidOperationException("No remaining seats");
			}

			var classes = await tr.GetRange(AttendsKeys(s)).ToListAsync();
			if (classes.Count >= 5) throw new InvalidOperationException("Too many classes");

			tr.Set(ClassKey(c), Slice.FromAscii((seatsLeft - 1).ToString()));
			tr.Set(rec, Slice.Empty);
		}