Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 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