public ValueTask <ulong> SaveAllAsync(NpgsqlConnection connection, IEnumerable <TEntity> entities, CancellationToken cancellationToken = default)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                return(new ValueTask <ulong>(Task.FromCanceled <ulong>(cancellationToken)));
            }

            using (NoSynchronizationContextScope.Enter())
            {
                return(DoSaveAllAsync(connection, entities));
            }
        }
Exemple #2
0
        public override async Task <int> ReadAsync([NotNull] byte[] buffer, int offset, int count, CancellationToken token)
        {
            using (NoSynchronizationContextScope.Enter())
            {
                CheckDisposed();
                count = Math.Min(count, _row.ColumnLen - _row.PosInColumn);
                var read = await _row.Buffer.ReadAllBytes(buffer, offset, count, true, true);

                _row.PosInColumn += read;
                return(read);
            }
        }
Exemple #3
0
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, AppDbContext context, IOptionsMonitor <DbOptions> options, IUserService userService)
        {
            if (options.CurrentValue.Delete)
            {
                context.Database.EnsureDeleted();
            }

            if (options.CurrentValue.Create)
            {
                context.Database.EnsureCreated();
            }

            if (options.CurrentValue.Migrate)
            {
                context.Database.Migrate();
            }

            // Without the using statement, Azure Pipelines might get a deadlock
            using (NoSynchronizationContextScope.Enter())
            {
                // TODO: This system can be used to set an admin password in production too (as long as that is managed securely)
                userService.SetPasswordAsync(FakeDataSeeder.FakeAdminName, "Abcd123#").Wait();
            }

            CurrentEnvironment = env;

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");

                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            //app.UseHttpsRedirection();

            app.UseCors("AllowMyApp");
            app.UseStatusCodePagesWithReExecute("/error/{0}");

            app.UseRouting();
            app.UseAuthentication();
            app.UseAuthorization();
            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
Exemple #4
0
        public override ValueTask <int> ReadAsync(Memory <byte> buffer, CancellationToken cancellationToken = default)
#endif
        {
            CheckDisposed();

            var count = Math.Min(buffer.Length, _len - _read);

            if (count == 0)
            {
                return(new ValueTask <int>(0));
            }

            using (NoSynchronizationContextScope.Enter())
                return(ReadLong(this, buffer.Slice(0, count), cancellationToken));
Exemple #5
0
    /// <summary>
    /// This API is for internal use and for implementing logical replication plugins.
    /// It is not meant to be consumed in common Npgsql usage scenarios.
    /// </summary>
    /// <remarks>
    /// Creates a new replication slot and returns information about the newly-created slot.
    /// </remarks>
    /// <param name="connection">The <see cref="LogicalReplicationConnection"/> to use for creating the
    /// replication slot</param>
    /// <param name="slotName">The name of the slot to create. Must be a valid replication slot name (see
    /// <a href="https://www.postgresql.org/docs/current/warm-standby.html#STREAMING-REPLICATION-SLOTS-MANIPULATION">
    /// https://www.postgresql.org/docs/current/warm-standby.html#STREAMING-REPLICATION-SLOTS-MANIPULATION</a>).
    /// </param>
    /// <param name="outputPlugin">The name of the output plugin used for logical decoding (see
    /// <a href="https://www.postgresql.org/docs/current/logicaldecoding-output-plugin.html">
    /// https://www.postgresql.org/docs/current/logicaldecoding-output-plugin.html</a>).
    /// </param>
    /// <param name="isTemporary"><see langword="true"/> if this replication slot shall be temporary one; otherwise
    /// <see langword="false"/>. Temporary slots are not saved to disk and are automatically dropped on error or
    /// when the session has finished.</param>
    /// <param name="slotSnapshotInitMode">A <see cref="LogicalSlotSnapshotInitMode"/> to specify what to do with the
    /// snapshot created during logical slot initialization. <see cref="LogicalSlotSnapshotInitMode.Export"/>, which is
    /// also the default, will export the snapshot for use in other sessions. This option can't be used inside a
    /// transaction. <see cref="LogicalSlotSnapshotInitMode.Use"/> will use the snapshot for the current transaction
    /// executing the command. This option must be used in a transaction, and <see cref="LogicalSlotSnapshotInitMode.Use"/>
    /// must be the first command run in that transaction. Finally, <see cref="LogicalSlotSnapshotInitMode.NoExport"/> will
    /// just use the snapshot for logical decoding as normal but won't do anything else with it.</param>
    /// <param name="twoPhase">
    /// If <see langword="true"/>, this logical replication slot supports decoding of two-phase transactions. With this option,
    /// two-phase commands like PREPARE TRANSACTION, COMMIT PREPARED and ROLLBACK PREPARED are decoded and transmitted.
    /// The transaction will be decoded and transmitted at PREPARE TRANSACTION time. The default is <see langword="false"/>.
    /// </param>
    /// <param name="cancellationToken">
    /// An optional token to cancel the asynchronous operation. The default value is <see cref="CancellationToken.None"/>.
    /// </param>
    /// <returns>A <see cref="Task{T}"/> representing a <see cref="ReplicationSlotOptions"/> class that
    /// can be used to initialize instances of <see cref="ReplicationSlot"/> subclasses.</returns>
    public static Task <ReplicationSlotOptions> CreateLogicalReplicationSlot(
        this LogicalReplicationConnection connection,
        string slotName,
        string outputPlugin,
        bool isTemporary = false,
        LogicalSlotSnapshotInitMode?slotSnapshotInitMode = null,
        bool twoPhase = false,
        CancellationToken cancellationToken = default)
    {
        connection.CheckDisposed();

        using var _ = NoSynchronizationContextScope.Enter();
        return(CreateLogicalReplicationSlotCore());

        Task <ReplicationSlotOptions> CreateLogicalReplicationSlotCore()
        {
            if (slotName is null)
            {
                throw new ArgumentNullException(nameof(slotName));
            }
            if (outputPlugin is null)
            {
                throw new ArgumentNullException(nameof(outputPlugin));
            }

            cancellationToken.ThrowIfCancellationRequested();

            var builder = new StringBuilder("CREATE_REPLICATION_SLOT ").Append(slotName);

            if (isTemporary)
            {
                builder.Append(" TEMPORARY");
            }
            builder.Append(" LOGICAL ").Append(outputPlugin);
            builder.Append(slotSnapshotInitMode switch
            {
                // EXPORT_SNAPSHOT is the default since it has been introduced.
                // We don't set it unless it is explicitly requested so that older backends can digest the query too.
                null => string.Empty,
                LogicalSlotSnapshotInitMode.Export => " EXPORT_SNAPSHOT",
                LogicalSlotSnapshotInitMode.Use => " USE_SNAPSHOT",
                LogicalSlotSnapshotInitMode.NoExport => " NOEXPORT_SNAPSHOT",
                _ => throw new ArgumentOutOfRangeException(nameof(slotSnapshotInitMode),
                                                           slotSnapshotInitMode,
                                                           $"Unexpected value {slotSnapshotInitMode} for argument {nameof(slotSnapshotInitMode)}.")
            });
Exemple #6
0
        /// <summary>
        /// Instructs the server to start streaming the WAL for physical replication, starting at WAL location
        /// <paramref name="walLocation"/>. The server can reply with an error, for example if the requested
        /// section of the WAL has already been recycled.
        /// </summary>
        /// <remarks>
        /// If the client requests a timeline that's not the latest but is part of the history of the server, the server
        /// will stream all the WAL on that timeline starting from the requested start point up to the point where the
        /// server switched to another timeline.
        /// </remarks>
        /// <param name="slot">
        /// The replication slot that will be updated as replication progresses so that the server
        /// knows which WAL segments are still needed by the standby.
        /// </param>
        /// <param name="walLocation">The WAL location to begin streaming at.</param>
        /// <param name="cancellationToken">The token to be used for stopping the replication.</param>
        /// <param name="timeline">Streaming starts on timeline tli.</param>
        /// <returns>A <see cref="Task{T}"/> representing an <see cref="IAsyncEnumerable{NpgsqlXLogDataMessage}"/> that
        /// can be used to stream WAL entries in form of <see cref="XLogDataMessage"/> instances.</returns>
        public IAsyncEnumerable <XLogDataMessage> StartReplication(PhysicalReplicationSlot?slot,
                                                                   NpgsqlLogSequenceNumber walLocation,
                                                                   CancellationToken cancellationToken,
                                                                   uint timeline = default)
        {
            using var _ = NoSynchronizationContextScope.Enter();

            var builder = new StringBuilder("START_REPLICATION");

            if (slot != null)
            {
                builder.Append(" SLOT ").Append(slot.Name);
            }
            builder.Append(" PHYSICAL ").Append(walLocation);
            if (timeline != default)
            {
                builder.Append(" TIMELINE ").Append(timeline.ToString(CultureInfo.InvariantCulture));
            }

            return(StartReplicationInternal(builder.ToString(), bypassingStream: false, cancellationToken));
        }
Exemple #7
0
        private void applyProjections(IDocumentSession session, ICollection <EventProjection> projections, IEnumerable <TView> views)
        {
            var idAssigner = session.Tenant.IdAssignmentFor <TView>();
            var resolver   = session.Tenant.StorageFor <TView>();
            var viewMap    = views.ToDictionary(view => (TId)resolver.IdentityFor(view), view => view);

            foreach (var eventProjection in projections)
            {
                var viewId          = eventProjection.ViewId;
                var hasExistingView = viewMap.TryGetValue(viewId, out var view);
                if (!hasExistingView)
                {
                    if (eventProjection.Type == ProjectionEventType.CreateAndUpdate)
                    {
                        view = newView(session.Tenant, idAssigner, viewId);
                        viewMap.Add(viewId, view);
                        hasExistingView = true;
                    }
                }

                using (NoSynchronizationContextScope.Enter())
                {
                    if (eventProjection.Type == ProjectionEventType.CreateAndUpdate ||
                        (eventProjection.Type == ProjectionEventType.UpdateOnly && hasExistingView))
                    {
                        session.Store(view);
                        eventProjection.ProjectTo(session, view).Wait();
                    }
                    else if (eventProjection.Type == ProjectionEventType.Delete && hasExistingView)
                    {
                        var shouldDeleteTask = eventProjection.ShouldDelete(session, view);
                        shouldDeleteTask.Wait();
                        if (shouldDeleteTask.Result)
                        {
                            session.Delete(view);
                        }
                    }
                }
            }
        }
Exemple #8
0
    /// <summary>
    /// Instructs the server to start streaming the WAL for physical replication, starting at WAL location
    /// <paramref name="walLocation"/>. The server can reply with an error, for example if the requested
    /// section of the WAL has already been recycled.
    /// </summary>
    /// <remarks>
    /// If the client requests a timeline that's not the latest but is part of the history of the server, the server
    /// will stream all the WAL on that timeline starting from the requested start point up to the point where the
    /// server switched to another timeline.
    /// </remarks>
    /// <param name="slot">
    /// The replication slot that will be updated as replication progresses so that the server
    /// knows which WAL segments are still needed by the standby.
    /// </param>
    /// <param name="walLocation">The WAL location to begin streaming at.</param>
    /// <param name="cancellationToken">The token to be used for stopping the replication.</param>
    /// <param name="timeline">Streaming starts on timeline tli.</param>
    /// <returns>A <see cref="Task{T}"/> representing an <see cref="IAsyncEnumerable{NpgsqlXLogDataMessage}"/> that
    /// can be used to stream WAL entries in form of <see cref="XLogDataMessage"/> instances.</returns>
    public IAsyncEnumerable <XLogDataMessage> StartReplication(PhysicalReplicationSlot?slot,
                                                               NpgsqlLogSequenceNumber walLocation,
                                                               CancellationToken cancellationToken,
                                                               ulong timeline = default)
    {
        using (NoSynchronizationContextScope.Enter())
            return(StartPhysicalReplication(slot, walLocation, cancellationToken, timeline));

        async IAsyncEnumerable <XLogDataMessage> StartPhysicalReplication(PhysicalReplicationSlot?slot,
                                                                          NpgsqlLogSequenceNumber walLocation,
                                                                          [EnumeratorCancellation] CancellationToken cancellationToken,
                                                                          ulong timeline)
        {
            var builder = new StringBuilder("START_REPLICATION");

            if (slot != null)
            {
                builder.Append(" SLOT ").Append(slot.Name);
            }
            builder.Append(" PHYSICAL ").Append(walLocation);
            if (timeline != default)
            {
                builder.Append(" TIMELINE ").Append(timeline.ToString(CultureInfo.InvariantCulture));
            }

            var command = builder.ToString();

            LogMessages.StartingPhysicalReplication(Logger, slot?.Name, command, Connector.Id);

            var enumerator = StartReplicationInternalWrapper(command, bypassingStream: false, cancellationToken);

            while (await enumerator.MoveNextAsync())
            {
                yield return(enumerator.Current);
            }
        }
    }
Exemple #9
0
 /// <summary>
 /// Read some information associated to a replication slot.
 /// <remarks>
 /// This command is currently only supported for physical replication slots.
 /// </remarks>
 /// </summary>
 /// <param name="slotName">
 /// The name of the slot to read. Must be a valid replication slot name
 /// </param>
 /// <param name="cancellationToken">
 /// An optional token to cancel the asynchronous operation. The default value is <see cref="CancellationToken.None"/>.
 /// </param>
 /// <returns>A <see cref="Task{T}"/> representing a <see cref="PhysicalReplicationSlot"/> or <see langword="null"/>
 /// if the replication slot does not exist.</returns>
 public Task <PhysicalReplicationSlot?> ReadReplicationSlot(string slotName, CancellationToken cancellationToken = default)
 {
     using (NoSynchronizationContextScope.Enter())
         return(ReadReplicationSlotInternal(slotName, cancellationToken));
 }
 /// <summary>
 /// Starts reading a single row, must be invoked before reading any columns.
 /// </summary>
 /// <returns>
 /// The number of columns in the row. -1 if there are no further rows.
 /// Note: This will currently be the same value for all rows, but this may change in the future.
 /// </returns>
 public ValueTask <int> StartRowAsync(CancellationToken cancellationToken = default)
 {
     using (NoSynchronizationContextScope.Enter())
         return(StartRow(true, cancellationToken));
 }
 /// <summary>
 /// Reads <i>count</i> bytes from the large object. The only case when fewer bytes are read is when end of stream is reached.
 /// </summary>
 /// <param name="buffer">The buffer where read data should be stored.</param>
 /// <param name="offset">The offset in the buffer where the first byte should be read.</param>
 /// <param name="count">The maximum number of bytes that should be read.</param>
 /// <param name="cancellationToken">
 /// An optional token to cancel the asynchronous operation. The default value is <see cref="CancellationToken.None"/>.
 /// </param>
 /// <returns>How many bytes actually read, or 0 if end of file was already reached.</returns>
 public override Task <int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
 {
     using (NoSynchronizationContextScope.Enter())
         return(Read(buffer, offset, count, true, cancellationToken));
 }
 /// <summary>
 /// Cancels and terminates an ongoing import. Any data already written will be discarded.
 /// </summary>
 public Task CancelAsync()
 {
     using (NoSynchronizationContextScope.Enter())
         return(((NpgsqlRawCopyStream)BaseStream).CancelAsync());
 }
 /// <summary>
 /// Reads the current column, returns its value according to <paramref name="type"/> and
 /// moves ahead to the next column.
 /// If the column is null an exception is thrown.
 /// </summary>
 /// <param name="type">
 /// In some cases <typeparamref name="T"/> isn't enough to infer the data type coming in from the
 /// database. This parameter can be used to unambiguously specify the type. An example is the JSONB
 /// type, for which <typeparamref name="T"/> will be a simple string but for which
 /// <paramref name="type"/> must be specified as <see cref="NpgsqlDbType.Jsonb"/>.
 /// </param>
 /// <param name="cancellationToken">
 /// An optional token to cancel the asynchronous operation. The default value is <see cref="CancellationToken.None"/>.
 /// </param>
 /// <typeparam name="T">The .NET type of the column to be read.</typeparam>
 /// <returns>The value of the column</returns>
 public ValueTask <T> ReadAsync <T>(NpgsqlDbType type, CancellationToken cancellationToken = default)
 {
     using (NoSynchronizationContextScope.Enter())
         return(Read <T>(type, true, cancellationToken));
 }
Exemple #14
0
        public override ValueTask DisposeAsync()
#endif
        {
            using (NoSynchronizationContextScope.Enter())
                return(DisposeAsync(disposing: true, async: true));
        }
 /// <summary>
 /// <para>
 /// Async terminates the ongoing binary import and puts the connection back into the idle state, where regular commands can be executed.
 /// </para>
 /// <para>
 /// Note that if <see cref="CompleteAsync" /> hasn't been invoked before calling this, the import will be cancelled and all changes will
 /// be reverted.
 /// </para>
 /// </summary>
 public ValueTask DisposeAsync()
 {
     using (NoSynchronizationContextScope.Enter())
         return(CloseAsync(true));
 }
 /// <summary>
 /// Imports a large object to be stored as a large object in the database from a file stored on the backend. This requires superuser permissions.
 /// </summary>
 /// <param name="path">Path to read the file on the backend</param>
 /// <param name="oid">A preferred oid, or specify 0 if one should be automatically assigned</param>
 /// <param name="cancellationToken">
 /// An optional token to cancel the asynchronous operation. The default value is <see cref="CancellationToken.None"/>.
 /// </param>
 public Task ImportRemoteAsync(string path, uint oid, CancellationToken cancellationToken = default)
 {
     using (NoSynchronizationContextScope.Enter())
         return(ExecuteFunction <object>("lo_import", true, cancellationToken, path, (int)oid));
 }
 /// <summary>
 /// Deletes a large object on the backend.
 /// </summary>
 /// <param name="oid">Oid of the object to delete</param>
 /// <param name="cancellationToken">
 /// An optional token to cancel the asynchronous operation. The default value is <see cref="CancellationToken.None"/>.
 /// </param>
 public Task UnlinkAsync(uint oid, CancellationToken cancellationToken = default)
 {
     using (NoSynchronizationContextScope.Enter())
         return(ExecuteFunction <object>("lo_unlink", true, cancellationToken, (int)oid));
 }
 /// <summary>
 /// Opens a large object on the backend, returning a stream controlling this remote object.
 /// Note that this method, as well as operations on the stream must be wrapped inside a transaction.
 /// </summary>
 /// <param name="oid">Oid of the object</param>
 /// <param name="cancellationToken">
 /// An optional token to cancel the asynchronous operation. The default value is <see cref="CancellationToken.None"/>.
 /// </param>
 /// <returns>An NpgsqlLargeObjectStream</returns>
 public Task <NpgsqlLargeObjectStream> OpenReadWriteAsync(uint oid, CancellationToken cancellationToken = default)
 {
     using (NoSynchronizationContextScope.Enter())
         return(OpenReadWrite(oid, true, cancellationToken));
 }