Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Ydb.Sdk/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
- Added XML documentation for all public APIs in `Ydb.Sdk`.
- Feat ADO.NET: Added dispose timeout (10 seconds) to `PoolingSessionSource`.
- Feat ADO.NET: Added `EnableImplicitSession` to support implicit sessions.

Expand Down
2 changes: 1 addition & 1 deletion src/Ydb.Sdk/src/Ado/BulkUpsert/BulkUpsertImporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

namespace Ydb.Sdk.Ado.BulkUpsert;

public sealed class BulkUpsertImporter : IBulkUpsertImporter
internal class BulkUpsertImporter : IBulkUpsertImporter
{
private readonly IDriver _driver;
private readonly string _tablePath;
Expand Down
21 changes: 21 additions & 0 deletions src/Ydb.Sdk/src/Ado/RetryPolicy/IRetryPolicy.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,27 @@
namespace Ydb.Sdk.Ado.RetryPolicy;

/// <summary>
/// Defines the contract for retry policies used by YDB operations.
/// </summary>
/// <remarks>
/// IRetryPolicy provides a way to implement custom retry logic for YDB operations.
/// The recommended implementation is <see cref="YdbRetryPolicy"/>, but custom implementations
/// can be created for specific use cases. When implementing a custom retry policy, ensure
/// you understand the implications of retrying operations and handle idempotency correctly.
/// </remarks>
public interface IRetryPolicy
{
/// <summary>
/// Calculates the delay before the next retry attempt.
/// </summary>
/// <param name="ydbException">The <see cref="YdbException"/> that was thrown during the last execution attempt.</param>
/// <param name="attempt">The current attempt number (0-based).</param>
/// <returns>
/// The delay before the next retry attempt, or null if no more retries should be attempted.
/// </returns>
/// <remarks>
/// This method is called for each retry attempt. Return null to stop retrying.
/// Consider the <see cref="YdbException"/>, attempt number, and operation idempotency when making retry decisions.
/// </remarks>
public TimeSpan? GetNextDelay(YdbException ydbException, int attempt);
}
43 changes: 42 additions & 1 deletion src/Ydb.Sdk/src/Ado/RetryPolicy/YdbRetryPolicy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,23 @@
namespace Ydb.Sdk.Ado.RetryPolicy;

/// <summary>
/// See <a href="https://aws.amazon.com/ru/blogs/architecture/exponential-backoff-and-jitter/">AWS paper</a>
/// Default retry policy implementation for YDB operations using exponential backoff with jitter.
/// </summary>
/// <remarks>
/// YdbRetryPolicy implements the recommended retry strategy for YDB operations based on
/// <a href="https://aws.amazon.com/ru/blogs/architecture/exponential-backoff-and-jitter/">AWS best practices</a>.
/// It uses different backoff strategies for different types of errors and includes jitter
/// to prevent thundering herd problems. This is the recommended implementation of <see cref="IRetryPolicy"/>.
/// </remarks>
public class YdbRetryPolicy : IRetryPolicy
{
/// <summary>
/// Gets the default retry policy instance with default configuration.
/// </summary>
/// <remarks>
/// This instance uses the default configuration from <see cref="YdbRetryPolicyConfig.Default"/>.
/// It's suitable for most use cases and provides a good balance between retry frequency and performance.
/// </remarks>
public static readonly YdbRetryPolicy Default = new(YdbRetryPolicyConfig.Default);

private readonly int _maxAttempt;
Expand All @@ -19,6 +32,14 @@ public class YdbRetryPolicy : IRetryPolicy
private readonly bool _enableRetryIdempotence;
private readonly IRandom _random;

/// <summary>
/// Initializes a new instance of the <see cref="YdbRetryPolicy"/> class with the specified configuration.
/// </summary>
/// <param name="config">The <see cref="YdbRetryPolicyConfig"/> retry policy configuration.</param>
/// <remarks>
/// This constructor creates a retry policy with the specified configuration.
/// The policy will use different backoff strategies based on the error type and attempt number.
/// </remarks>
public YdbRetryPolicy(YdbRetryPolicyConfig config)
{
_maxAttempt = config.MaxAttempts;
Expand All @@ -32,11 +53,31 @@ public YdbRetryPolicy(YdbRetryPolicyConfig config)
_random = ThreadLocalRandom.Instance;
}

/// <summary>
/// Initializes a new instance of the <see cref="YdbRetryPolicy"/> class with the specified configuration and random number generator.
/// </summary>
/// <param name="config">The <see cref="YdbRetryPolicyConfig"/> retry policy configuration.</param>
/// <param name="random">The random number generator for jitter calculations.</param>
/// <remarks>
/// This constructor is primarily used for testing purposes to provide deterministic behavior.
/// In production code, use the constructor that takes only the configuration parameter.
/// </remarks>
internal YdbRetryPolicy(YdbRetryPolicyConfig config, IRandom random) : this(config)
{
_random = random;
}

/// <inheritdoc/>
/// <remarks>
/// <para>This method implements different retry strategies based on the YDB status code:</para>
/// <para>- BadSession/SessionBusy: Immediate retry (TimeSpan.Zero)</para>
/// <para>- Aborted/Undetermined: Fast backoff with full jitter</para>
/// <para>- Unavailable/Transport errors: Fast backoff with equal jitter</para>
/// <para>- Overloaded/Resource exhausted: Slow backoff with equal jitter</para>
/// <para>- Other errors: No retry (null)</para>
///
/// <para>The policy respects the maximum attempt limit and idempotence settings.</para>
/// </remarks>
public TimeSpan? GetNextDelay(YdbException ydbException, int attempt)
{
if (attempt >= _maxAttempt - 1 || (!_enableRetryIdempotence && !ydbException.IsTransient))
Expand Down
76 changes: 76 additions & 0 deletions src/Ydb.Sdk/src/Ado/RetryPolicy/YdbRetryPolicyConfig.cs
Original file line number Diff line number Diff line change
@@ -1,21 +1,97 @@
namespace Ydb.Sdk.Ado.RetryPolicy;

/// <summary>
/// Configuration settings for the <see cref="YdbRetryPolicy"/>.
/// </summary>
/// <remarks>
/// YdbRetryPolicyConfig provides configuration options for customizing the retry behavior
/// of YDB operations. The default values are suitable for most use cases, but can be
/// adjusted based on specific requirements and performance characteristics.
/// </remarks>
public class YdbRetryPolicyConfig
{
/// <summary>
/// Gets the default retry policy configuration.
/// </summary>
/// <remarks>
/// This configuration provides a good balance between retry frequency and performance
/// for most YDB operations. It can be used as a starting point for custom configurations.
/// </remarks>
public static readonly YdbRetryPolicyConfig Default = new();

/// <summary>
/// Gets or sets the maximum number of retry attempts.
/// </summary>
/// <remarks>
/// The total number of attempts will be MaxAttempts (including the initial attempt).
/// Setting this to 1 disables retries entirely.
/// <para>Default value: 10.</para>
/// </remarks>
public int MaxAttempts { get; init; } = 10;

/// <summary>
/// Gets or sets the base delay in milliseconds for fast backoff strategies.
/// </summary>
/// <remarks>
/// This is used for errors that typically resolve quickly, such as temporary
/// unavailability or TLI (Transaction Lock Invalidated).
/// The actual delay will be calculated using exponential backoff with jitter.
/// <para>Default value: 5 ms.</para>
/// </remarks>
public int FastBackoffBaseMs { get; init; } = 5;

/// <summary>
/// Gets or sets the base delay in milliseconds for slow backoff strategies.
/// </summary>
/// <remarks>
/// This is used for errors that may take longer to resolve, such as overload
/// or resource exhaustion. The actual delay will be calculated using
/// exponential backoff with jitter.
/// <para>Default value: 50 ms.</para>
/// </remarks>
public int SlowBackoffBaseMs { get; init; } = 50;

/// <summary>
/// Gets or sets the maximum delay in milliseconds for fast backoff strategies.
/// </summary>
/// <remarks>
/// This caps the maximum delay for fast backoff to prevent excessively long waits.
/// The exponential backoff will not exceed this value.
/// <para>Default value: 500 ms.</para>
/// </remarks>
public int FastCapBackoffMs { get; init; } = 500;

/// <summary>
/// Gets or sets the maximum delay in milliseconds for slow backoff strategies.
/// </summary>
/// <remarks>
/// This caps the maximum delay for slow backoff to prevent excessively long waits.
/// The exponential backoff will not exceed this value.
/// <para>Default value: 5000 ms.</para>
/// </remarks>
public int SlowCapBackoffMs { get; init; } = 5_000;

/// <summary>
/// Gets or sets a value indicating whether to enable retry for idempotent statuses.
/// </summary>
/// <remarks>
/// When false, only transient errors are retried. When true, all retryable statuses
/// are retried, which means the operation may be executed twice. This happens because
/// some statuses (like unavailable) don't indicate whether the server processed the
/// operation - the connection might have been lost during the response. Enable this
/// only if you are certain that the operations being retried are idempotent.
/// <para>Default value: false.</para>
/// </remarks>
public bool EnableRetryIdempotence { get; init; } = false;

/// <summary>
/// Returns a string representation of the retry policy configuration.
/// </summary>
/// <returns>A string containing all configuration values in a readable format.</returns>
/// <remarks>
/// This method is useful for logging and debugging purposes to see the current
/// retry policy configuration values.
/// </remarks>
public override string ToString() => $"MaxAttempt={MaxAttempts};" +
$"FastBackoffBaseMs={FastBackoffBaseMs};" +
$"SlowBackoffBaseMs={SlowBackoffBaseMs};" +
Expand Down
14 changes: 7 additions & 7 deletions src/Ydb.Sdk/src/Ado/RetryPolicy/YdbRetryPolicyExecutor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,20 @@ public YdbRetryPolicyExecutor(IRetryPolicy retryPolicy)
}

/// <summary>
/// Executes the specified asynchronous operation and returns the result.
/// Executes the specified asynchronous operation and returns the result.
/// </summary>
/// <param name="operation">
/// A function that returns a started task of type <typeparamref name="TResult" />.
/// A function that returns a started task of type <typeparamref name="TResult" />.
/// </param>
/// <param name="cancellationToken">
/// A cancellation token used to cancel the retry operation, but not operations that are already in flight
/// or that already completed successfully.
/// A cancellation token used to cancel the retry operation, but not operations that are already in flight
/// or that already completed successfully.
/// </param>
/// <typeparam name="TResult"> The result type of the <see cref="Task{TResult}" /> returned by <paramref name="operation" />. </typeparam>
/// <returns>
/// A task that will run to completion if the original task completes successfully (either the
/// first time or after retrying transient failures). If the task fails with a non-transient error or
/// the retry limit is reached, the returned task will become faulted and the exception must be observed.
/// A task that will run to completion if the original task completes successfully (either the
/// first time or after retrying transient failures). If the task fails with a non-transient error or
/// the retry limit is reached, the returned task will become faulted and the exception must be observed.
/// </returns>
public Task<TResult> ExecuteAsync<TResult>(
Func<CancellationToken, Task<TResult>> operation,
Expand Down
2 changes: 1 addition & 1 deletion src/Ydb.Sdk/src/Ado/Schema/YdbTableStats.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
namespace Ydb.Sdk.Ado.Schema;

public class YdbTableStats
internal class YdbTableStats
{
public YdbTableStats(Table.TableStats tableStats)
{
Expand Down
62 changes: 62 additions & 0 deletions src/Ydb.Sdk/src/Ado/Transaction/TransactionMode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,74 @@

namespace Ydb.Sdk.Ado;

/// <summary>
/// Specifies the transaction isolation mode for YDB operations.
/// </summary>
/// <remarks>
/// TransactionMode defines the isolation level and consistency guarantees
/// for database operations within a transaction.
///
/// <para>
/// For more information about YDB transaction modes, see:
/// <see href="https://ydb.tech/docs/en/concepts/transactions">YDB Transactions Documentation</see>.
/// </para>
/// </remarks>
public enum TransactionMode
{
/// <summary>
/// Serializable read-write transaction mode.
/// </summary>
/// <remarks>
/// Provides the strictest isolation level for custom transactions.
/// Guarantees that the result of successful parallel transactions is equivalent
/// to their serial execution, with no read anomalies for successful transactions.
/// This is the default mode for read-write operations.
/// </remarks>
SerializableRw,

/// <summary>
/// Snapshot read-only transaction mode.
/// </summary>
/// <remarks>
/// All read operations within the transaction access the database snapshot.
/// All data reads are consistent. The snapshot is taken when the transaction begins,
/// meaning the transaction sees all changes committed before it began.
/// Only read operations are allowed.
/// </remarks>
SnapshotRo,

/// <summary>
/// Stale read-only transaction mode.
/// </summary>
/// <remarks>
/// Read operations within the transaction may return results that are slightly
/// out-of-date (lagging by fractions of a second). Each individual read returns
/// consistent data, but no consistency between different reads is guaranteed.
/// Only read operations are allowed.
/// </remarks>
StaleRo,

/// <summary>
/// Online read-only transaction mode.
/// </summary>
/// <remarks>
/// Each read operation in the transaction reads the data that is most recent
/// at execution time. Each individual read operation returns consistent data,
/// but no consistency is guaranteed between reads. Reading the same table range
/// twice may return different results.
/// Only read operations are allowed.
/// </remarks>
OnlineRo,

/// <summary>
/// Online inconsistent read-only transaction mode.
/// </summary>
/// <remarks>
/// Each read operation in the transaction reads the data that is most recent
/// at execution time. Even the data fetched by a particular read operation may
/// contain inconsistent results. This mode provides the highest performance
/// but the lowest consistency guarantees.
/// Only read operations are allowed.
/// </remarks>
OnlineInconsistentRo
}
26 changes: 26 additions & 0 deletions src/Ydb.Sdk/src/Ado/YdbCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,13 @@

namespace Ydb.Sdk.Ado;

/// <summary>
/// Represents a SQL command to execute against a YDB database. This class cannot be inherited.
/// </summary>
/// <remarks>
/// YdbCommand provides a standard ADO.NET command interface for executing SQL statements
/// against YDB databases. It supports both synchronous and asynchronous execution methods.
/// </remarks>
public sealed class YdbCommand : DbCommand
{
private YdbConnection? _ydbConnection;
Expand All @@ -14,15 +21,34 @@ public sealed class YdbCommand : DbCommand
private YdbConnection YdbConnection =>
_ydbConnection ?? throw new InvalidOperationException("Connection property has not been initialized");

/// <summary>
/// Initializes a new instance of the <see cref="YdbCommand"/> class.
/// </summary>
public YdbCommand()
{
}

/// <summary>
/// Initializes a new instance of the <see cref="YdbCommand"/> class with the specified connection.
/// </summary>
/// <param name="ydbConnection">A <see cref="YdbConnection"/> that represents the connection to a YDB server.</param>
public YdbCommand(YdbConnection ydbConnection)
{
_ydbConnection = ydbConnection;
}

/// <summary>
/// Initializes a new instance of the <see cref="YdbCommand"/> class with the text of the query, a
/// <see cref="YdbConnection"/>, and the <see cref="YdbTransaction"/>.
/// </summary>
/// <param name="commandText">The text of the query.</param>
/// <param name="ydbConnection">A <see cref="YdbConnection"/> that represents the connection to a YDB server.</param>
public YdbCommand(string commandText, YdbConnection? ydbConnection = null)
{
_commandText = commandText;
_ydbConnection = ydbConnection;
}

public override void Cancel()
{
}
Expand Down
Loading
Loading