diff --git a/src/Knet.Kudu.Client/ExternalConsistencyMode.cs b/src/Knet.Kudu.Client/ExternalConsistencyMode.cs index 580aa349..d8d5838d 100644 --- a/src/Knet.Kudu.Client/ExternalConsistencyMode.cs +++ b/src/Knet.Kudu.Client/ExternalConsistencyMode.cs @@ -3,62 +3,69 @@ namespace Knet.Kudu.Client { /// + /// /// The external consistency mode for client requests. /// This defines how transactions and/or sequences of operations that touch /// several TabletServers, in different machines, can be observed by external /// clients. - /// + /// + /// + /// /// Note that ExternalConsistencyMode makes no guarantee on atomicity, i.e. /// no sequence of operations is made atomic (or transactional) just because /// an external consistency mode is set. /// Note also that ExternalConsistencyMode has no implication on the /// consistency between replicas of the same tablet. + /// /// public enum ExternalConsistencyMode { /// - /// The response to any write will contain a timestamp. - /// Any further calls from the same client to other servers will update - /// those servers with that timestamp. The user will make sure that the - /// timestamp is propagated through back-channels to other - /// KuduClient's. - /// - /// WARNING: Failure to propagate timestamp information through - /// back-channels will negate any external consistency guarantee under this - /// mode. - /// - /// Example: - /// 1 - Client A executes operation X in Tablet A - /// 2 - Afterwards, Client A executes operation Y in Tablet B - /// - /// - /// Client B may observe the following operation sequences: - /// {}, {X}, {X Y} - /// - /// This is the default mode. + /// + /// The response to any write will contain a timestamp. Any further calls + /// from the same client to other servers will update those servers + /// with that timestamp. Following write operations from the same client + /// will be assigned timestamps that are strictly higher, enforcing external + /// consistency without having to wait or incur any latency penalties. + /// + /// + /// + /// In order to maintain external consistency for writes between + /// two different clients in this mode, the user must forward the timestamp + /// from the first client to the second by using + /// . + /// + /// + /// + /// This is the default external consistency mode. + /// + /// + /// + /// Failure to propagate timestamp information through back-channels + /// between two different clients will negate any external consistency + /// guarantee under this mode. + /// /// ClientPropagated = ExternalConsistencyModePB.ClientPropagated, /// - /// The server will guarantee that each transaction is externally - /// consistent by making sure that none of its results are visible - /// until every Kudu server agrees that the transaction is in the past. - /// The client is not obligated to forward timestamp information - /// through back-channels. - /// - /// WARNING: Depending on the clock synchronization state of TabletServers - /// this may imply considerable latency. Moreover operations with - /// COMMIT_WAIT requested external consistency will outright fail if - /// TabletServer clocks are either unsynchronized or synchronized but - /// with a maximum error which surpasses a pre-configured one. - /// - /// Example: - /// - Client A executes operation X in Tablet A - /// - Afterwards, Client A executes operation Y in Tablet B - /// - /// - /// Client B may observe the following operation sequences: - /// {}, {X}, {X Y} + /// + /// The server will guarantee that write operations from the same or from + /// other client are externally consistent, without the need to propagate + /// timestamps across clients. This is done by making write operations + /// wait until there is certainty that all follow up write operations + /// (operations that start after the previous one finishes) + /// will be assigned a timestamp that is strictly higher, enforcing external + /// consistency. + /// + /// + /// + /// Depending on the clock synchronization state of TabletServers this may + /// imply considerable latency. Moreover operations in COMMIT_WAIT + /// external consistency mode will outright fail if TabletServer clocks + /// are either unsynchronized or synchronized but with a maximum error + /// which surpasses a pre-configured threshold. + /// /// CommitWait = ExternalConsistencyModePB.CommitWait } diff --git a/src/Knet.Kudu.Client/Internal/ISystemClock.cs b/src/Knet.Kudu.Client/Internal/ISystemClock.cs index 919df555..c8d0f7b0 100644 --- a/src/Knet.Kudu.Client/Internal/ISystemClock.cs +++ b/src/Knet.Kudu.Client/Internal/ISystemClock.cs @@ -2,6 +2,11 @@ { public interface ISystemClock { + /// + /// Retrieve the current milliseconds. This value should only + /// be used to measure how much time has passed relative to + /// another call to this property. + /// long CurrentMilliseconds { get; } } } diff --git a/src/Knet.Kudu.Client/Internal/SystemClock.cs b/src/Knet.Kudu.Client/Internal/SystemClock.cs index 59272757..e48e7fda 100644 --- a/src/Knet.Kudu.Client/Internal/SystemClock.cs +++ b/src/Knet.Kudu.Client/Internal/SystemClock.cs @@ -6,10 +6,12 @@ namespace Knet.Kudu.Client.Internal public sealed class SystemClock : ISystemClock { #if NETCOREAPP3_0 + /// public long CurrentMilliseconds => Environment.TickCount64; #else private readonly Stopwatch _stopwatch = Stopwatch.StartNew(); + /// public long CurrentMilliseconds => _stopwatch.ElapsedMilliseconds; #endif } diff --git a/src/Knet.Kudu.Client/KuduClient.cs b/src/Knet.Kudu.Client/KuduClient.cs index 8b8a8822..d34962ea 100644 --- a/src/Knet.Kudu.Client/KuduClient.cs +++ b/src/Knet.Kudu.Client/KuduClient.cs @@ -168,17 +168,23 @@ public void ImportAuthenticationCredentials(ReadOnlyMemory token) _securityContext.ImportAuthenticationCredentials(token); } + /// + /// Create a table on the cluster with the specified name, schema, and + /// table configurations. + /// + /// The create table options. + /// The cancellation token. public async Task CreateTableAsync( - TableBuilder tableBuilder, CancellationToken cancellationToken = default) + TableBuilder builder, CancellationToken cancellationToken = default) { - var rpc = new CreateTableRequest(tableBuilder.Build()); + var rpc = new CreateTableRequest(builder.Build()); var response = await SendRpcAsync(rpc, cancellationToken) .ConfigureAwait(false); var tableId = new TableIdentifierPB { TableId = response.TableId }; - if (tableBuilder.Wait) + if (builder.Wait) { await WaitForCreateTableDoneAsync( tableId, cancellationToken).ConfigureAwait(false); @@ -190,11 +196,16 @@ await WaitForCreateTableDoneAsync( return null; } + /// + /// Alter a table on the cluster as specified by the builder. + /// + /// The alter table options. + /// The cancellation token. public async Task AlterTableAsync( - AlterTableBuilder alterTable, + AlterTableBuilder builder, CancellationToken cancellationToken = default) { - var rpc = new AlterTableRequest(alterTable); + var rpc = new AlterTableRequest(builder); AlterTableResponse response; try @@ -204,19 +215,19 @@ public async Task AlterTableAsync( } finally { - if (alterTable.HasAddDropRangePartitions) + if (builder.HasAddDropRangePartitions) { // Clear the table locations cache so the new partition is // immediately visible. We clear the cache even on failure, // just in case the alter table operation actually succeeded. - _tableLocations.TryRemove(alterTable.TableId, out _); + _tableLocations.TryRemove(builder.TableId, out _); } } - if (alterTable.Wait) + if (builder.Wait) { var isDoneResponse = await WaitForAlterTableDoneAsync( - alterTable.TableIdPb, cancellationToken).ConfigureAwait(false); + builder.TableIdPb, cancellationToken).ConfigureAwait(false); response = new AlterTableResponse( response.TableId, @@ -286,6 +297,13 @@ public async Task DeleteTableAsync( await SendRpcAsync(rpc, cancellationToken).ConfigureAwait(false); } + /// + /// Get a list of table names. Passing a null filter returns all the tables. + /// When a filter is specified, it only returns tables that satisfy a substring + /// match. + /// + /// An optional table name filter. + /// The cancellation token. public async Task> GetTablesAsync( string nameFilter = null, CancellationToken cancellationToken = default) { @@ -381,6 +399,11 @@ internal async Task> GetTableLocationsAsync( return tableLocations; } + /// + /// Open the table with the given name. + /// + /// The table to open. + /// The cancellation token. public async Task OpenTableAsync( string tableName, CancellationToken cancellationToken = default) { @@ -532,6 +555,23 @@ public IKuduSession NewSession(KuduSessionOptions options) return new KuduSession(this, options, _loggerFactory); } + /// + /// + /// Create a that allows clients to determine + /// the target partition of a row without actually performing a write. The + /// set of partitions is eagerly fetched when the KuduPartitioner is constructed + /// so that the actual partitioning step can be performed synchronously + /// without any network trips. + /// + /// + /// + /// NOTE: Because this operates on a metadata snapshot retrieved at + /// construction time, it will not reflect any metadata changes to the + /// table that have occurred since its creation. + /// + /// + /// The table to operate on. + /// The cancellation token. public async ValueTask CreatePartitionerAsync( KuduTable table, CancellationToken cancellationToken = default) { @@ -736,7 +776,7 @@ private TableLocationsCache GetTableLocationsCache(string tableId) #endif } - public async ValueTask> LoopLocateTableAsync( + private async ValueTask> LoopLocateTableAsync( string tableId, byte[] startPartitionKey, byte[] endPartitionKey, diff --git a/src/Knet.Kudu.Client/KuduScanEnumerator.cs b/src/Knet.Kudu.Client/KuduScanEnumerator.cs index 78722738..2a472f8e 100644 --- a/src/Knet.Kudu.Client/KuduScanEnumerator.cs +++ b/src/Knet.Kudu.Client/KuduScanEnumerator.cs @@ -131,7 +131,6 @@ public KuduScanEnumerator( _lastPrimaryKey = Array.Empty(); _cancellationToken = cancellationToken; ResourceMetrics = new ResourceMetrics(); - // TODO: Register cancellation callback and cancel the scan. // Map the column names to actual columns in the table schema. // If the user set this to 'null', we scan all columns. @@ -436,7 +435,6 @@ private async ValueTask ScanNextRowsAsync() private ScanRequest GetOpenRequest() { - //checkScanningNotStarted(); var request = new ScanRequestPB(); var newRequest = request.NewScanRequest = new NewScanRequestPB @@ -499,7 +497,6 @@ private ScanRequest GetOpenRequest() private ScanRequest GetNextRowsRequest() { - //checkScanningNotStarted(); var request = new ScanRequestPB { ScannerId = _scannerId,