Exemplo n.º 1
0
        /// <summary>Removes the directory, its contents, and all subdirectories.
        /// Warning: Clients that have already opened the directory might still insert data into its contents after it is removed.
        /// </summary>
        public static Task RemoveAsync([NotNull] this IFdbDirectory directory, [NotNull] IFdbRetryable db, CancellationToken ct)
        {
            Contract.NotNull(directory, nameof(directory));
            Contract.NotNull(db, nameof(db));

            return(db.ReadWriteAsync((tr) => directory.RemoveAsync(tr), ct));
        }
        /// <summary>Clear the entire content of a subspace</summary>
        public static Task ClearRangeAsync(this IFdbRetryable db, IKeySubspace subspace, CancellationToken ct)
        {
            Contract.NotNull(db);
            Contract.NotNull(subspace);

            return(db.WriteAsync((tr) => ClearRange(tr, subspace), ct));
        }
Exemplo n.º 3
0
        /// <summary>Clear the entire content of a subspace</summary>
        public static Task ClearRangeAsync(this IFdbRetryable db, [NotNull] IFdbSubspace subspace, CancellationToken cancellationToken)
        {
            Contract.NotNull(db, nameof(db));
            Contract.NotNull(subspace, nameof(subspace));

            return(db.WriteAsync((tr) => ClearRange(tr, subspace), cancellationToken));
        }
 /// <summary>Atomically update a value if it is smaller than the value in the database, using a dedicated transaction.</summary>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task AtomicMin(this IFdbRetryable db, Slice key, Slice value, CancellationToken cancellationToken)
 {
     if (db == null)
     {
         throw new ArgumentNullException("db");
     }
     return(db.WriteAsync((tr) => tr.Atomic(key, value, FdbMutationType.Min), cancellationToken));
 }
 /// <summary>Clear a single range in the database, using a dedicated transaction.</summary>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task ClearRangeAsync(this IFdbRetryable db, FdbKeyRange range, CancellationToken cancellationToken)
 {
     if (db == null)
     {
         throw new ArgumentNullException("db");
     }
     return(db.WriteAsync((tr) => tr.ClearRange(range), cancellationToken));
 }
 /// <summary>Clear a single range in the database, using a dedicated transaction.</summary>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task ClearRangeAsync(this IFdbRetryable db, Slice beginKeyInclusive, Slice endKeyExclusive, CancellationToken cancellationToken)
 {
     if (db == null)
     {
         throw new ArgumentNullException("db");
     }
     return(db.WriteAsync((tr) => tr.ClearRange(beginKeyInclusive, endKeyExclusive), cancellationToken));
 }
 /// <summary>Clear a single key in the database, using a dedicated transaction.</summary>
 /// <param name="db">Database instance</param>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task ClearAsync(this IFdbRetryable db, Slice key, CancellationToken cancellationToken)
 {
     if (db == null)
     {
         throw new ArgumentNullException("db");
     }
     return(db.WriteAsync((tr) => tr.Clear(key), cancellationToken));
 }
 public static Task <FdbWatch> SetAndWatch <TKey>(this IFdbRetryable db, TKey key, Slice value, CancellationToken cancellationToken)
     where TKey : IFdbKey
 {
     if (key == null)
     {
         throw new ArgumentNullException("key");
     }
     return(SetAndWatch(db, key.ToFoundationDbKey(), value, cancellationToken));
 }
 /// <summary>Set the values of a sequence of keys in the database, using a dedicated transaction.</summary>
 /// <param name="db">Database instance</param>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task SetValuesAsync([NotNull] this IFdbRetryable db, IEnumerable <KeyValuePair <Slice, Slice> > keyValuePairs, CancellationToken cancellationToken)
 {
     Contract.NotNull(db, nameof(db));
     return(db.WriteAsync((tr) =>
     {
         foreach (var kv in keyValuePairs)
         {
             tr.Set(kv.Key, kv.Value);
         }
     }, cancellationToken));
 }
Exemplo n.º 10
0
 public static Task SetValuesAsync(this IFdbRetryable db, IEnumerable <KeyValuePair <Slice, Slice> > items, CancellationToken ct)
 {
     Contract.NotNull(db);
     return(db.WriteAsync((tr) =>
     {
         foreach (var kv in items)
         {
             tr.Set(kv.Key, kv.Value);
         }
     }, ct));
 }
        /// <summary>Reads the value associated with <paramref name="key"/>, and returns a Watch that will complete after a subsequent change to key in the database.</summary>
        /// <param name="db">Database instance.</param>
        /// <param name="key">Key to be looked up in the database</param>
        /// <param name="cancellationToken">Token that can be used to cancel the Watch from the outside.</param>
        /// <returns>A new Watch that will track any changes to <paramref name="key"/> in the database, and whose <see cref="FdbWatch.Value">Value</see> property contains the current value of the key.</returns>
        public static Task <FdbWatch> GetAndWatch([NotNull] this IFdbRetryable db, Slice key, CancellationToken cancellationToken)
        {
            Contract.NotNull(db, nameof(db));

            return(db.ReadWriteAsync(async(tr) =>
            {
                var result = await tr.GetAsync(key).ConfigureAwait(false);
                var watch = tr.Watch(key, cancellationToken);
                watch.Value = result.Memoize();
                return watch;
            }, cancellationToken));
        }
        /// <summary>Add and Schedule a new Task in the worker pool</summary>
        /// <param name="db"></param>
        /// <param name="taskId"></param>
        /// <param name="taskBody"></param>
        /// <param name="ct"></param>
        /// <returns></returns>
        public async Task ScheduleTaskAsync(IFdbRetryable db, Slice taskId, Slice taskBody, CancellationToken ct = default(CancellationToken))
        {
            if (db == null)
            {
                throw new ArgumentNullException(nameof(db));
            }
            var now = DateTime.UtcNow;

            await db.ReadWriteAsync(async (tr) =>
            {
                Interlocked.Increment(ref m_schedulingAttempts);
#if DEBUG
                if (tr.Context.Retries > 0)
                {
                    Console.WriteLine($"# retry n°{tr.Context.Retries} for task {taskId:P}");
                }
#endif
                tr.Annotate("I want to schedule {0:P}", taskId);

                // find a random worker from the idle ring
                var randomWorkerKey = await FindRandomItem(tr, this.IdleRing).ConfigureAwait(false);

                if (randomWorkerKey.Key != null)
                {
                    Slice workerId = this.IdleRing.Keys.Decode <Slice>(randomWorkerKey.Key);

                    tr.Annotate("Assigning {0:P} to {1:P}", taskId, workerId);

                    // remove worker from the idle ring
                    tr.Clear(this.IdleRing.Keys.Encode(workerId));
                    this.Counters.Decrement(tr, COUNTER_IDLE);

                    // assign task to the worker
                    tr.Set(this.BusyRing.Keys.Encode(workerId), taskId);
                    this.Counters.Increment(tr, COUNTER_BUSY);
                }
                else
                {
                    tr.Annotate("Queueing {0:P}", taskId);

                    await PushQueueAsync(tr, this.UnassignedTaskRing, taskId).ConfigureAwait(false);
                }

                // store the task in the db
                StoreTask(tr, taskId, now, taskBody);
            },
                                    success : (tr) =>
            {
                Interlocked.Increment(ref m_schedulingMessages);
            },
                                    ct : ct).ConfigureAwait(false);
        }
        /// <summary>Removes the directory, its contents, and all subdirectories.
        /// Warning: Clients that have already opened the directory might still insert data into its contents after it is removed.
        /// </summary>
        public static Task RemoveAsync([NotNull] this IFdbDirectory directory, [NotNull] IFdbRetryable db, IEnumerable <string> path, CancellationToken cancellationToken)
        {
            if (directory == null)
            {
                throw new ArgumentNullException("directory");
            }
            if (db == null)
            {
                throw new ArgumentNullException("db");
            }

            return(db.ReadWriteAsync((tr) => directory.RemoveAsync(tr, path), cancellationToken));
        }
        /// <summary>Clear the entire content of a subspace</summary>
        public static Task ClearRangeAsync(this IFdbRetryable db, [NotNull] FdbSubspace subspace, CancellationToken cancellationToken)
        {
            if (db == null)
            {
                throw new ArgumentNullException("db");
            }
            if (subspace == null)
            {
                throw new ArgumentNullException("subspace");
            }

            return(db.WriteAsync((tr) => ClearRange(tr, subspace), cancellationToken));
        }
        /// <summary>Removes the directory, its contents, and all subdirectories.
        /// Warning: Clients that have already opened the directory might still insert data into its contents after it is removed.
        /// </summary>
        public static Task RemoveAsync([NotNull] this IFdbDirectory directory, [NotNull] IFdbRetryable db, CancellationToken ct)
        {
            if (directory == null)
            {
                throw new ArgumentNullException(nameof(directory));
            }
            if (db == null)
            {
                throw new ArgumentNullException(nameof(db));
            }

            return(db.ReadWriteAsync((tr) => directory.RemoveAsync(tr), ct));
        }
 /// <summary>Set the values of a sequence of keys in the database, using a dedicated transaction.</summary>
 /// <param name="db">Database instance</param>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task SetValuesAsync(this IFdbRetryable db, IEnumerable <KeyValuePair <Slice, Slice> > keyValuePairs, CancellationToken cancellationToken)
 {
     if (db == null)
     {
         throw new ArgumentNullException("db");
     }
     return(db.WriteAsync((tr) =>
     {
         foreach (var kv in keyValuePairs)
         {
             tr.Set(kv.Key, kv.Value);
         }
     }, cancellationToken));
 }
        /// <summary>Sets <paramref name="key"/> to <paramref name="value"/> and returns a Watch that will complete after a subsequent change to the key in the database.</summary>
        /// <param name="db">Database instance.</param>
        /// <param name="key">Name of the key to be inserted into the database.</param>
        /// <param name="value">Value to be inserted into the database.</param>
        /// <param name="cancellationToken">Token that can be used to cancel the Watch from the outside.</param>
        /// <returns>A new Watch that will track any changes to <paramref name="key"/> in the database, and whose <see cref="FdbWatch.Value">Value</see> property will be a copy of <paramref name="value"/> argument</returns>
        public static async Task <FdbWatch> SetAndWatch([NotNull] this IFdbRetryable db, Slice key, Slice value, CancellationToken cancellationToken)
        {
            Contract.NotNull(db, nameof(db));

            var watch = default(FdbWatch);

            await db.WriteAsync((tr) =>
            {
                tr.Set(key, value);
                watch = tr.Watch(key, cancellationToken);
            }, cancellationToken).ConfigureAwait(false);

            watch.Value = value.Memoize();
            return(watch);
        }
        /// <summary>Reads the value associated with <paramref name="key"/>, and returns a Watch that will complete after a subsequent change to key in the database.</summary>
        /// <param name="db">Database instance.</param>
        /// <param name="key">Key to be looked up in the database</param>
        /// <param name="cancellationToken">Token that can be used to cancel the Watch from the outside.</param>
        /// <returns>A new Watch that will track any changes to <paramref name="key"/> in the database, and whose <see cref="FdbWatch.Value">Value</see> property contains the current value of the key.</returns>
        public static Task <FdbWatch> GetAndWatch(this IFdbRetryable db, Slice key, CancellationToken cancellationToken)
        {
            if (db == null)
            {
                throw new ArgumentNullException("db");
            }

            return(db.ReadWriteAsync(async(tr) =>
            {
                var result = await tr.GetAsync(key).ConfigureAwait(false);
                var watch = tr.Watch(key, cancellationToken);
                watch.Value = result.Memoize();
                return watch;
            }, cancellationToken));
        }
 /// <summary>Run an idempotent transaction block inside a writable transaction, which can be executed more than once if any retryable error occurs.</summary>
 /// <param name="layer">Layer that will be resolved using the transaction, and will be passed as the second argument to <paramref name="handler"/>.</param>
 /// <param name="db">Database instance that will be used to start the transaction</param>
 /// <param name="handler">Idempotent handler that will attempt to mutate the database, and may be retried until the transaction commits, or a non-recoverable error occurs.</param>
 /// <param name="ct">Token used to cancel the operation</param>
 /// <remarks>
 /// You do not need to commit the transaction inside the handler, it will be done automatically!
 /// Given that the <paramref name="handler"/> can run more than once, and that there is no guarantee that the transaction commits once it returns, you MUST NOT mutate any global state (counters, cache, global dictionary) inside this lambda!
 /// You must wait for the Task to complete successfully before updating the global state of the application.
 /// </remarks>
 public static Task WriteAsync <TLayer>(
     this IFdbLayer <TLayer> layer,
     IFdbRetryable db,
     Func <IFdbTransaction, TLayer, Task> handler,
     CancellationToken ct)
 {
     return(db.WriteAsync(
                (layer, handler),
                async(tr, s) =>
     {
         var state = await(s.layer).Resolve(tr);
         await s.handler(tr, state);
     },
                ct));
 }
 /// <summary>Removes the directory, its contents, and all subdirectories.
 /// Warning: Clients that have already opened the directory might still insert data into its contents after it is removed.
 /// </summary>
 public static Task RemoveAsync([NotNull] this IFdbDirectory directory, [NotNull] IFdbRetryable db, [NotNull] string name, CancellationToken cancellationToken)
 {
     if (directory == null)
     {
         throw new ArgumentNullException("directory");
     }
     if (db == null)
     {
         throw new ArgumentNullException("db");
     }
     if (name == null)
     {
         throw new ArgumentNullException("name");
     }
     return(db.ReadWriteAsync((tr) => directory.RemoveAsync(tr, new [] { name }), cancellationToken));
 }
        /// <summary>Sets <paramref name="key"/> to <paramref name="value"/> and returns a Watch that will complete after a subsequent change to the key in the database.</summary>
        /// <param name="db">Database instance.</param>
        /// <param name="key">Name of the key to be inserted into the database.</param>
        /// <param name="value">Value to be inserted into the database.</param>
        /// <param name="cancellationToken">Token that can be used to cancel the Watch from the outside.</param>
        /// <returns>A new Watch that will track any changes to <paramref name="key"/> in the database, and whose <see cref="FdbWatch.Value">Value</see> property will be a copy of <paramref name="value"/> argument</returns>
        public static async Task <FdbWatch> SetAndWatch(this IFdbRetryable db, Slice key, Slice value, CancellationToken cancellationToken)
        {
            if (db == null)
            {
                throw new ArgumentNullException("db");
            }

            FdbWatch watch = default(FdbWatch);

            await db.WriteAsync((tr) =>
            {
                tr.Set(key, value);
                watch = tr.Watch(key, cancellationToken);
            }, cancellationToken).ConfigureAwait(false);

            watch.Value = value.Memoize();
            return(watch);
        }
Exemplo n.º 22
0
 public static Task SetAsync(this IFdbRetryable db, Slice key, Slice value, CancellationToken ct)
 {
     Contract.NotNull(db);
     return(db.WriteAsync((tr) => tr.Set(key, value), ct));
 }
 /// <summary>Atomically update a value if it is smaller than the value in the database, using a dedicated transaction.</summary>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task AtomicMin([NotNull] this IFdbRetryable db, Slice key, Slice value, CancellationToken cancellationToken)
 {
     Contract.NotNull(db, nameof(db));
     return(db.WriteAsync((tr) => tr.Atomic(key, value, FdbMutationType.Min), cancellationToken));
 }
 /// <summary>Clear a single range in the database, using a dedicated transaction.</summary>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task ClearRangeAsync([NotNull] this IFdbRetryable db, KeyRange range, CancellationToken cancellationToken)
 {
     Contract.NotNull(db, nameof(db));
     return(db.WriteAsync((tr) => tr.ClearRange(range), cancellationToken));
 }
 /// <summary>Clear a single range in the database, using a dedicated transaction.</summary>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task ClearRangeAsync([NotNull] this IFdbRetryable db, Slice beginKeyInclusive, Slice endKeyExclusive, CancellationToken cancellationToken)
 {
     Contract.NotNull(db, nameof(db));
     return(db.WriteAsync((tr) => tr.ClearRange(beginKeyInclusive, endKeyExclusive), cancellationToken));
 }
		/// <summary>Add and Schedule a new Task in the worker pool</summary>
		/// <param name="db"></param>
		/// <param name="taskId"></param>
		/// <param name="taskBody"></param>
		/// <param name="ct"></param>
		/// <returns></returns>
		public async Task ScheduleTaskAsync(IFdbRetryable db, Slice taskId, Slice taskBody, CancellationToken ct = default(CancellationToken))
		{
			if (db == null) throw new ArgumentNullException("db");
			var now = DateTime.UtcNow;

			await db.ReadWriteAsync(async (tr) =>
			{
				Interlocked.Increment(ref m_schedulingAttempts);
#if DEBUG
				if (tr.Context.Retries > 0) Console.WriteLine("# retry n°" + tr.Context.Retries + " for task " + taskId.ToAsciiOrHexaString());
#endif
				tr.Annotate("I want to schedule {0}", taskId.ToAsciiOrHexaString());

				// find a random worker from the idle ring
				var randomWorkerKey = await FindRandomItem(tr, this.IdleRing).ConfigureAwait(false);

				if (randomWorkerKey.Key != null)
				{
					Slice workerId = this.IdleRing.UnpackSingle<Slice>(randomWorkerKey.Key);

					tr.Annotate("Assigning {0} to {1}", taskId.ToAsciiOrHexaString(), workerId.ToAsciiOrHexaString());

					// remove worker from the idle ring
					tr.Clear(this.IdleRing.Pack(workerId));
					this.Counters.Decrement(tr, COUNTER_IDLE);

					// assign task to the worker
					tr.Set(this.BusyRing.Pack(workerId), taskId);
					this.Counters.Increment(tr, COUNTER_BUSY);
				}
				else
				{
					tr.Annotate("Queueing {0}", taskId.ToAsciiOrHexaString());

					await PushQueueAsync(tr, this.UnassignedTaskRing, taskId).ConfigureAwait(false);
				}

				// store the task in the db
				StoreTask(tr, taskId, now, taskBody);
			}, 
			onDone: (tr) =>
			{
				Interlocked.Increment(ref m_schedulingMessages);
			},
			cancellationToken: ct).ConfigureAwait(false);
		}
        /// <summary>Opens the directory with the given <paramref name="name"/>.
        /// If the directory does not exist, it is created (creating parent directories if necessary).
        /// If layer is specified, it is checked against the layer of an existing directory or set as the layer of a new directory.
        /// </summary>
        public static Task <FdbDirectorySubspace> CreateOrOpenAsync([NotNull] this IFdbDirectory directory, [NotNull] IFdbRetryable db, [NotNull] string name, CancellationToken ct)
        {
            if (directory == null)
            {
                throw new ArgumentNullException(nameof(directory));
            }
            if (db == null)
            {
                throw new ArgumentNullException(nameof(db));
            }
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            return(db.ReadWriteAsync((tr) => directory.CreateOrOpenAsync(tr, new [] { name }, Slice.Nil), ct));
        }
        /// <summary>Removes the directory, its contents, and all subdirectories.
        /// Warning: Clients that have already opened the directory might still insert data into its contents after it is removed.
        /// </summary>
        public static Task <bool> TryRemoveAsync([NotNull] this IFdbDirectory directory, [NotNull] IFdbRetryable db, [NotNull] string name, CancellationToken ct)
        {
            if (directory == null)
            {
                throw new ArgumentNullException(nameof(directory));
            }
            if (db == null)
            {
                throw new ArgumentNullException(nameof(db));
            }
            if (name == null)
            {
                throw new ArgumentNullException(nameof(name));
            }

            return(db.ReadWriteAsync((tr) => directory.TryRemoveAsync(tr, new [] { name }), ct));
        }
        /// <summary>Attempts to move the current directory to <paramref name="newPath"/>.
        /// There is no effect on the physical prefix of the given directory, or on clients that already have the directory open.
        /// </summary>
        public static Task <FdbDirectorySubspace> TryMoveToAsync([NotNull] this FdbDirectorySubspace subspace, [NotNull] IFdbRetryable db, [NotNull] IEnumerable <string> newPath, CancellationToken ct)
        {
            if (subspace == null)
            {
                throw new ArgumentNullException(nameof(subspace));
            }
            if (db == null)
            {
                throw new ArgumentNullException(nameof(db));
            }
            if (newPath == null)
            {
                throw new ArgumentNullException(nameof(newPath));
            }

            return(db.ReadWriteAsync((tr) => subspace.TryMoveToAsync(tr, newPath), ct));
        }
Exemplo n.º 30
0
 public static Task SetValuesAsync(this IFdbRetryable db, IEnumerable <(Slice Key, Slice Value)> items, CancellationToken ct)
 /// <summary>Clear a single key in the database, using a dedicated transaction.</summary>
 /// <param name="db">Database instance</param>
 /// <remarks>
 /// Use this method only if you intend to perform a single operation inside your execution context (ex: HTTP request).
 /// If you need to combine multiple read or write operations, consider using on of the multiple <see cref="IFdbRetryable.WriteAsync"/> or <see cref="IFdbRetryable.ReadWriteAsync"/> overrides.
 /// </remarks>
 public static Task ClearAsync([NotNull] this IFdbRetryable db, Slice key, CancellationToken cancellationToken)
 {
     Contract.NotNull(db, nameof(db));
     return(db.WriteAsync((tr) => tr.Clear(key), cancellationToken));
 }