/// <summary>
    /// Load a table of default schema with the specified number of records, in ascending key order.
    /// </summary>
    public static async Task LoadDefaultTableAsync(KuduClient client, KuduTable table, int numRows)
    {
        var rows = Enumerable.Range(0, numRows)
                   .Select(i => CreateBasicSchemaInsert(table, i));

        await client.WriteAsync(rows);
    }
    public async Task TestAlterModifyColumns()
    {
        KuduTable table = await CreateTableAsync();

        await InsertRowsAsync(table, 0, 100);

        Assert.Equal(100, await ClientTestUtil.CountRowsAsync(_client, table));

        // Check for expected defaults.
        ColumnSchema col = table.Schema.GetColumn(1);

        Assert.Equal(CompressionType.DefaultCompression, col.Compression);
        Assert.Equal(EncodingType.AutoEncoding, col.Encoding);
        Assert.Null(col.DefaultValue);

        // Alter the table.
        await _client.AlterTableAsync(new AlterTableBuilder(table)
                                      .ChangeCompressionAlgorithm(col.Name, CompressionType.Snappy)
                                      .ChangeEncoding(col.Name, EncodingType.Rle)
                                      .ChangeDefault(col.Name, 0));

        // Check for new values.
        table = await _client.OpenTableAsync(_tableName);

        col = table.Schema.GetColumn(1);
        Assert.Equal(CompressionType.Snappy, col.Compression);
        Assert.Equal(EncodingType.Rle, col.Encoding);
        Assert.Equal(0, col.DefaultValue);
    }
    public async Task InitializeAsync()
    {
        _harness = await new MiniKuduClusterBuilder().BuildHarnessAsync();

        var options           = _harness.CreateClientBuilder().BuildOptions();
        var securityContext   = new SecurityContext();
        var systemClock       = new SystemClock();
        var connectionFactory = new KuduConnectionFactory(
            options, securityContext, NullLoggerFactory.Instance);

        _testConnectionFactory = new TestConnectionFactory(connectionFactory);

        _client = new KuduClient(
            options,
            securityContext,
            _testConnectionFactory,
            systemClock,
            NullLoggerFactory.Instance);

        var builder = ClientTestUtil.GetBasicSchema()
                      .SetTableName("chaos_test_table")
                      .SetNumReplicas(3)
                      .CreateBasicRangePartition();

        _table = await _client.CreateTableAsync(builder);
    }
    public static KuduOperation CreateBasicSchemaDeleteIgnore(KuduTable table, int key)
    {
        var row = table.NewDeleteIgnore();

        row.SetInt32(0, key);
        return(row);
    }
    private async Task <long> SetupTableForDiffScansAsync(KuduTable table, int numRows)
    {
        for (int i = 0; i < numRows / 2; i++)
        {
            var row = ClientTestUtil.CreateBasicSchemaInsert(table, i);
            await _session.EnqueueAsync(row);
        }

        await _session.FlushAsync();

        // Grab the timestamp, then add more data so there's a diff.
        long timestamp = _client.LastPropagatedTimestamp;

        for (int i = numRows / 2; i < numRows; i++)
        {
            var row = ClientTestUtil.CreateBasicSchemaInsert(table, i);
            await _session.EnqueueAsync(row);
        }

        await _session.FlushAsync();

        // Delete some data so the is_deleted column can be tested.
        for (int i = 0; i < numRows / 4; i++)
        {
            var row = table.NewDelete();
            row.SetInt32(0, i);
            await _session.EnqueueAsync(row);
        }

        await _session.FlushAsync();

        return(timestamp);
    }
    public static async Task <List <string> > ScanTableToStringsAsync(
        KuduClient client, KuduTable table, params KuduPredicate[] predicates)
    {
        var rowStrings  = new List <string>();
        var scanBuilder = client.NewScanBuilder(table)
                          .SetReadMode(ReadMode.ReadYourWrites)
                          .SetReplicaSelection(ReplicaSelection.LeaderOnly);

        foreach (var predicate in predicates)
        {
            scanBuilder.AddPredicate(predicate);
        }

        var scanner = scanBuilder.Build();

        await foreach (var resultSet in scanner)
        {
            foreach (var row in resultSet)
            {
                rowStrings.Add(row.ToString());
            }
        }

        rowStrings.Sort();

        return(rowStrings);
    }
 public AbstractKuduScannerBuilder(KuduClient client, KuduTable table)
 {
     Client             = client;
     Table              = table;
     Predicates         = new Dictionary <string, KuduPredicate>();
     ScanRequestTimeout = -1; // TODO: Pull this from the client.
 }
Exemple #8
0
    public KuduScanEnumerator(
        ILogger logger,
        KuduClient client,
        KuduTable table,
        List <ColumnSchemaPB> projectedColumnsPb,
        KuduSchema projectionSchema,
        OrderMode orderMode,
        ReadMode readMode,
        ReplicaSelection replicaSelection,
        bool isFaultTolerant,
        Dictionary <string, KuduPredicate> predicates,
        long limit,
        bool cacheBlocks,
        byte[] startPrimaryKey,
        byte[] endPrimaryKey,
        long startTimestamp,
        long htTimestamp,
        int batchSizeBytes,
        PartitionPruner partitionPruner,
        CancellationToken cancellationToken)
    {
        _logger            = logger;
        _client            = client;
        _table             = table;
        _partitionPruner   = partitionPruner;
        _orderMode         = orderMode;
        _readMode          = readMode;
        _columns           = projectedColumnsPb;
        _schema            = projectionSchema;
        _predicates        = predicates;
        _replicaSelection  = replicaSelection;
        _isFaultTolerant   = isFaultTolerant;
        _limit             = limit;
        _cacheBlocks       = cacheBlocks;
        _startPrimaryKey   = startPrimaryKey ?? Array.Empty <byte>();
        _endPrimaryKey     = endPrimaryKey ?? Array.Empty <byte>();
        _startTimestamp    = startTimestamp;
        SnapshotTimestamp  = htTimestamp;
        _batchSizeBytes    = batchSizeBytes;
        _scannerId         = ByteString.Empty;
        _lastPrimaryKey    = ByteString.Empty;
        _cancellationToken = cancellationToken;
        ResourceMetrics    = new ResourceMetrics();

        // If the partition pruner has pruned all partitions, then the scan can be
        // short circuited without contacting any tablet servers.
        if (!_partitionPruner.HasMorePartitionKeyRanges)
        {
            _closed = true;
        }

        // For READ_YOUR_WRITES scan mode, get the latest observed timestamp
        // and store it. Always use this one as the propagated timestamp for
        // the duration of the scan to avoid unnecessary wait.
        if (readMode == ReadMode.ReadYourWrites)
        {
            _lowerBoundPropagationTimestamp = client.LastPropagatedTimestamp;
        }
    }
    /// <summary>
    /// Checks the number of tablets and pruner ranges generated for a scan with
    /// predicates and optional partition key bounds.
    /// </summary>
    /// <param name="expectedTablets">The expected number of tablets to satisfy the scan.</param>
    /// <param name="expectedPrunerRanges">The expected number of generated partition pruner ranges.</param>
    /// <param name="table">The table to scan.</param>
    /// <param name="partitions">The partitions of the table.</param>
    /// <param name="lowerBoundPartitionKey">An optional lower bound partition key.</param>
    /// <param name="upperBoundPartitionKey">An optional upper bound partition key.</param>
    /// <param name="predicates">The predicates to apply to the scan.</param>
    private async Task CheckPartitionsAsync(
        int expectedTablets,
        int expectedPrunerRanges,
        KuduTable table,
        List <Partition> partitions,
        byte[] lowerBoundPartitionKey,
        byte[] upperBoundPartitionKey,
        params KuduPredicate[] predicates)
    {
        // Partition key bounds can't be applied to the ScanTokenBuilder.
        var scanBuilder = _client.NewScanBuilder(table);

        foreach (var predicate in predicates)
        {
            scanBuilder.AddPredicate(predicate);
        }

        if (lowerBoundPartitionKey != null)
        {
            scanBuilder.LowerBoundPartitionKeyRaw(lowerBoundPartitionKey);
        }

        if (upperBoundPartitionKey != null)
        {
            scanBuilder.ExclusiveUpperBoundPartitionKeyRaw(upperBoundPartitionKey);
        }

        var pruner = PartitionPruner.Create(scanBuilder);

        int scannedPartitions = 0;

        foreach (var partition in partitions)
        {
            if (!pruner.ShouldPruneForTests(partition))
            {
                scannedPartitions++;
            }
        }

        Assert.Equal(expectedTablets, scannedPartitions);
        Assert.Equal(expectedPrunerRanges, pruner.NumRangesRemaining);

        // Check that the scan token builder comes up with the same amount.
        // The scan token builder does not allow for upper/lower partition keys.
        if (lowerBoundPartitionKey == null && upperBoundPartitionKey == null)
        {
            var tokenBuilder = _client.NewScanTokenBuilder(table);

            foreach (var predicate in predicates)
            {
                tokenBuilder.AddPredicate(predicate);
            }

            // Check that the number of ScanTokens built for the scan matches.
            var tokens = await tokenBuilder.BuildAsync();

            Assert.Equal(expectedTablets, tokens.Count);
        }
    }
    public static ValueTask <long> CountRowsAsync(KuduClient client, KuduTable table)
    {
        var scanner = client.NewScanBuilder(table)
                      .SetReadMode(ReadMode.ReadYourWrites)
                      .SetReplicaSelection(ReplicaSelection.LeaderOnly)
                      .Build();

        return(scanner.CountAsync());
    }
Exemple #11
0
    public async Task InitializeAsync()
    {
        _harness = await new MiniKuduClusterBuilder().BuildHarnessAsync();
        _client  = _harness.CreateClient();
        await using var session = _client.NewSession();

        // Create a 4-tablets table for scanning.
        var builder = new TableBuilder(_tableName)
                      .AddColumn("key1", KuduType.String, opt => opt.Key(true))
                      .AddColumn("key2", KuduType.String, opt => opt.Key(true))
                      .AddColumn("val", KuduType.String)
                      .SetRangePartitionColumns("key1", "key2");

        for (int i = 1; i < 4; i++)
        {
            builder.AddSplitRow(splitRow =>
            {
                splitRow.SetString("key1", i.ToString());
                splitRow.SetString("key2", "");
            });
        }

        var table = await _client.CreateTableAsync(builder);

        // The data layout ends up like this:
        // tablet '', '1': no rows
        // tablet '1', '2': '111', '122', '133'
        // tablet '2', '3': '211', '222', '233'
        // tablet '3', '': '311', '322', '333'
        var keys = new[] { "1", "2", "3" };

        foreach (var key1 in keys)
        {
            foreach (var key2 in keys)
            {
                var insert = table.NewInsert();
                insert.SetString(0, key1);
                insert.SetString(1, key2);
                insert.SetString(2, key2);
                await session.EnqueueAsync(insert);

                await session.FlushAsync();
            }
        }

        _beforeWriteTimestamp = _client.LastPropagatedTimestamp;

        // Reset the client in order to clear the propagated timestamp.
        _newClient = _harness.CreateClient();

        // Reopen the table using the new client.
        _table = await _newClient.OpenTableAsync(_tableName);

        _schema = _table.Schema;
    }
Exemple #12
0
    private async Task InsertRowsAsync(KuduTable table, IEnumerable <Row> rows)
    {
        var operations = rows.Select(r =>
        {
            var insert = table.NewInsert();
            r.FillPartialRow(insert);
            return(insert);
        });

        await _client.WriteAsync(operations);
    }
    public static KuduOperation CreateBasicSchemaInsert(KuduTable table, int key)
    {
        var row = table.NewInsert();

        row.SetInt32(0, key);
        row.SetInt32(1, 2);
        row.SetInt32(2, 3);
        row.SetString(3, "a string");
        row.SetBool(4, true);
        return(row);
    }
 public AlterTableBuilder(KuduTable table)
 {
     _table   = table;
     _request = new AlterTableRequestPB
     {
         Table = new TableIdentifierPB
         {
             TableId = _table.SchemaPb.TableId
         }
     };
 }
    private static async ValueTask InsertRowsAsync(
        IKuduSession session, KuduTable table, int startRow, int numRows)
    {
        var end = startRow + numRows;

        for (var i = startRow; i < end; i++)
        {
            var insert = ClientTestUtil.CreateBasicSchemaInsert(table, i);
            await session.EnqueueAsync(insert);
        }
    }
    public static KuduOperation CreateAllNullsInsert(KuduTable table, int key)
    {
        var numColumns = table.Schema.Columns.Count;
        var row        = table.NewUpsert();

        row.SetInt32(0, key);
        for (int i = 1; i < numColumns; i++)
        {
            row.SetNull(i);
        }
        return(row);
    }
    public async Task TestRenameKeyColumn()
    {
        KuduTable table = await CreateTableAsync();

        await InsertRowsAsync(table, 0, 100);

        Assert.Equal(100, await ClientTestUtil.CountRowsAsync(_client, table));

        await _client.AlterTableAsync(new AlterTableBuilder(table)
                                      .RenameColumn("c0", "c0Key"));

        var exception = await Assert.ThrowsAsync <NonRecoverableException>(async() =>
        {
            // Scanning with the old schema.
            var scanner = _client.NewScanBuilder(table)
                          .SetProjectedColumns("c0", "c1")
                          .Build();

            await foreach (var resultSet in scanner)
            {
            }
        });

        Assert.True(exception.Status.IsInvalidArgument);
        Assert.Contains(
            "Some columns are not present in the current schema: c0",
            exception.Status.Message);

        // Reopen table for the new schema.
        table = await _client.OpenTableAsync(_tableName);

        Assert.Equal("c0Key", table.Schema.GetColumn(0).Name);
        Assert.Equal(2, table.Schema.Columns.Count);

        // Add a row
        var insert = table.NewInsert();

        insert.SetInt32("c0Key", 101);
        insert.SetInt32("c1", 101);
        await _session.EnqueueAsync(insert);

        await _session.FlushAsync();

        var scanner2 = _client.NewScanBuilder(table)
                       .SetProjectedColumns("c0Key", "c1")
                       .Build();

        var rows = await scanner2.ScanToListAsync <(int c0Key, int c1)>();

        Assert.Equal(101, rows.Count);
        Assert.All(rows, row => Assert.Equal(row.c0Key, row.c1));
    }
Exemple #18
0
    public async Task InitializeAsync()
    {
        _harness = await new MiniKuduClusterBuilder().BuildHarnessAsync();
        _client  = _harness.CreateClient();

        // Use one tablet because multiple tablets don't work: we could jump
        // from one tablet to another which could change the logical clock.
        var builder = new TableBuilder("HybridTimeTest")
                      .AddColumn("key", KuduType.String, opt => opt.Key(true))
                      .SetRangePartitionColumns("key");

        _table = await _client.CreateTableAsync(builder);
    }
    public async Task TestAlterAddColumns()
    {
        KuduTable table = await CreateTableAsync();

        await InsertRowsAsync(table, 0, 100);

        Assert.Equal(100, await ClientTestUtil.CountRowsAsync(_client, table));

        await _client.AlterTableAsync(new AlterTableBuilder(table)
                                      .AddColumn("addNonNull", KuduType.Int32, opt => opt
                                                 .Nullable(false)
                                                 .DefaultValue(100))
                                      .AddColumn("addNullable", KuduType.Int32)
                                      .AddColumn("addNullableDef", KuduType.Int32, opt => opt
                                                 .DefaultValue(200)));

        // Reopen table for the new schema.
        table = await _client.OpenTableAsync(_tableName);

        Assert.Equal(5, table.Schema.Columns.Count);

        // Add a row with addNullableDef=null
        var insert = table.NewInsert();

        insert.SetInt32("c0", 101);
        insert.SetInt32("c1", 101);
        insert.SetInt32("addNonNull", 101);
        insert.SetInt32("addNullable", 101);
        insert.SetNull("addNullableDef");
        await _session.EnqueueAsync(insert);

        await _session.FlushAsync();

        // Check defaults applied, and that row key=101
        var results = await ClientTestUtil.ScanTableToStringsAsync(_client, table);

        var expected = new List <string>(101);

        for (int i = 0; i < 100; i++)
        {
            expected.Add($"INT32 c0={i}, INT32 c1={i}, INT32 addNonNull=100, " +
                         "INT32 addNullable=NULL, INT32 addNullableDef=200");
        }

        expected.Add("INT32 c0=101, INT32 c1=101, INT32 addNonNull=101, " +
                     "INT32 addNullable=101, INT32 addNullableDef=NULL");

        Assert.Equal(
            expected.OrderBy(r => r),
            results.OrderBy(r => r));
    }
Exemple #20
0
    private ValueTask <long> CountRowsAsync(KuduTable table, params KuduPredicate[] predicates)
    {
        var scanBuilder = _client.NewScanBuilder(table)
                          .SetReadMode(ReadMode.ReadYourWrites);

        foreach (var predicate in predicates)
        {
            scanBuilder.AddPredicate(predicate);
        }

        var scanner = scanBuilder.Build();

        return(scanner.CountAsync());
    }
    public async Task TestAlterExtraConfigs()
    {
        KuduTable table = await CreateTableAsync();

        await InsertRowsAsync(table, 0, 100);

        Assert.Equal(100, await ClientTestUtil.CountRowsAsync(_client, table));

        // 1. Check for expected defaults.
        table = await _client.OpenTableAsync(_tableName);

        Assert.DoesNotContain("kudu.table.history_max_age_sec", table.ExtraConfig);

        // 2. Alter history max age second to 3600
        var alterExtraConfigs = new Dictionary <string, string>
        {
            { "kudu.table.history_max_age_sec", "3600" }
        };
        await _client.AlterTableAsync(new AlterTableBuilder(table)
                                      .AlterExtraConfigs(alterExtraConfigs));

        table = await _client.OpenTableAsync(_tableName);

        Assert.Equal("3600", table.ExtraConfig["kudu.table.history_max_age_sec"]);

        // 3. Alter history max age second to 7200
        alterExtraConfigs = new Dictionary <string, string>
        {
            { "kudu.table.history_max_age_sec", "7200" }
        };
        await _client.AlterTableAsync(new AlterTableBuilder(table)
                                      .AlterExtraConfigs(alterExtraConfigs));

        table = await _client.OpenTableAsync(_tableName);

        Assert.Equal("7200", table.ExtraConfig["kudu.table.history_max_age_sec"]);

        // 4. Reset history max age second to default
        alterExtraConfigs = new Dictionary <string, string>
        {
            { "kudu.table.history_max_age_sec", "" }
        };
        await _client.AlterTableAsync(new AlterTableBuilder(table)
                                      .AlterExtraConfigs(alterExtraConfigs));

        table = await _client.OpenTableAsync(_tableName);

        Assert.Empty(table.ExtraConfig);
    }
    /// <summary>
    /// Counts the partitions touched by a scan with optional primary key bounds.
    /// The table is assumed to have three INT8 columns as the primary key.
    /// </summary>
    /// <param name="expectedTablets">The expected number of tablets to satisfy the scan.</param>
    /// <param name="table">The table to scan.</param>
    /// <param name="partitions">The partitions of the table.</param>
    /// <param name="lowerBoundPrimaryKey">The optional lower bound primary key.</param>
    /// <param name="upperBoundPrimaryKey">The optional upper bound primary key.</param>
    private async Task CheckPartitionsPrimaryKeyAsync(
        int expectedTablets,
        KuduTable table,
        List <Partition> partitions,
        sbyte[] lowerBoundPrimaryKey,
        sbyte[] upperBoundPrimaryKey)
    {
        var scanBuilder = _client.NewScanTokenBuilder(table);

        if (lowerBoundPrimaryKey != null)
        {
            var lower = new PartialRow(table.Schema);
            for (int i = 0; i < 3; i++)
            {
                lower.SetSByte(i, lowerBoundPrimaryKey[i]);
            }
            scanBuilder.LowerBound(lower);
        }

        if (upperBoundPrimaryKey != null)
        {
            var upper = new PartialRow(table.Schema);
            for (int i = 0; i < 3; i++)
            {
                upper.SetSByte(i, upperBoundPrimaryKey[i]);
            }
            scanBuilder.ExclusiveUpperBound(upper);
        }

        var pruner = PartitionPruner.Create(scanBuilder);

        int scannedPartitions = 0;

        foreach (var partition in partitions)
        {
            if (!pruner.ShouldPruneForTests(partition))
            {
                scannedPartitions++;
            }
        }

        // Check that the number of ScanTokens built for the scan matches.
        var tokens = await scanBuilder.BuildAsync();

        Assert.Equal(expectedTablets, scannedPartitions);
        Assert.Equal(scannedPartitions, tokens.Count);
        Assert.Equal(expectedTablets == 0 ? 0 : 1, pruner.NumRangesRemaining);
    }
 /// <summary>
 /// Checks the number of tablets and pruner ranges generated for a scan.
 /// </summary>
 /// <param name="expectedTablets">The expected number of tablets to satisfy the scan.</param>
 /// <param name="expectedPrunerRanges">The expected number of generated partition pruner ranges.</param>
 /// <param name="table">The table to scan.</param>
 /// <param name="partitions">The partitions of the table.</param>
 /// <param name="predicates">The predicates to apply to the scan.</param>
 private Task CheckPartitionsAsync(
     int expectedTablets,
     int expectedPrunerRanges,
     KuduTable table,
     List <Partition> partitions,
     params KuduPredicate[] predicates)
 {
     return(CheckPartitionsAsync(
                expectedTablets,
                expectedPrunerRanges,
                table,
                partitions,
                null,
                null,
                predicates));
 }
Exemple #24
0
    private static IEnumerable <KuduOperation> CreateRows(KuduTable table, int numRows)
    {
        var hosts   = new[] { "host1.example.com", "host2.example.com" };
        var metrics = new[] { "cpuload.avg1", "cpuload.avg5", "cpuload.avg15" };
        var now     = DateTime.UtcNow;

        for (int i = 0; i < numRows; i++)
        {
            var row = table.NewInsert();
            row.SetString("host", hosts[i % hosts.Length]);
            row.SetString("metric", metrics[i % metrics.Length]);
            row.SetDateTime("timestamp", now.AddSeconds(i));
            row.SetDouble("value", Random.Shared.NextDouble());

            yield return(row);
        }
    }
    public async Task TestAlterRangePartitioningExclusiveInclusive()
    {
        // Create initial table with single range partition covering (-1, 99].
        var builder = new TableBuilder(_tableName)
                      .SetNumReplicas(1)
                      .AddColumn("c0", KuduType.Int32, opt => opt.Key(true))
                      .AddColumn("c1", KuduType.Int32, opt => opt.Nullable(false))
                      .SetRangePartitionColumns("c0")
                      .AddRangePartition((lower, upper) =>
        {
            lower.SetInt32("c0", -1);
            upper.SetInt32("c0", 99);
        }, RangePartitionBound.Exclusive, RangePartitionBound.Inclusive);

        KuduTable table = await _client.CreateTableAsync(builder);

        await _client.AlterTableAsync(new AlterTableBuilder(table)
                                      .AddRangePartition((lower, upper) =>
        {
            lower.SetInt32("c0", 199);
            upper.SetInt32("c0", 299);
        }, RangePartitionBound.Exclusive, RangePartitionBound.Inclusive));

        // Insert some rows, and then drop the partition and ensure that the table is empty.
        await InsertRowsAsync(table, 0, 100);
        await InsertRowsAsync(table, 200, 300);

        Assert.Equal(200, await ClientTestUtil.CountRowsAsync(_client, table));

        await _client.AlterTableAsync(new AlterTableBuilder(table)
                                      .DropRangePartition((lower, upper) =>
        {
            lower.SetInt32("c0", 0);
            upper.SetInt32("c0", 100);
        }, RangePartitionBound.Inclusive, RangePartitionBound.Exclusive)
                                      .DropRangePartition((lower, upper) =>
        {
            lower.SetInt32("c0", 199);
            upper.SetInt32("c0", 299);
        }, RangePartitionBound.Exclusive, RangePartitionBound.Inclusive));

        Assert.Equal(0, await ClientTestUtil.CountRowsAsync(_client, table));
    }
    public static KuduOperation CreateBasicSchemaUpsert(
        KuduTable table, int key, int secondVal, bool hasNull)
    {
        var row = table.NewUpsert();

        row.SetInt32(0, key);
        row.SetInt32(1, secondVal);
        row.SetInt32(2, 3);
        if (hasNull)
        {
            row.SetNull(3);
        }
        else
        {
            row.SetString(3, "a string");
        }
        row.SetBool(4, true);
        return(row);
    }
Exemple #27
0
    private async Task CheckPredicatesAsync <T>(
        KuduTable table,
        SortedSet <T> values,
        List <T> testValues)
    {
        var col = table.Schema.GetColumn("value");

        Assert.Equal(values.Count + 1, await CountRowsAsync(table));

        foreach (var v in testValues)
        {
            // value = v
            var equal = KuduPredicate.NewComparisonPredicate(col, ComparisonOp.Equal, (dynamic)v);
            Assert.Equal(values.Contains(v) ? 1 : 0, await CountRowsAsync(table, equal));

            // value >= v
            var greaterEqual = KuduPredicate.NewComparisonPredicate(col, ComparisonOp.GreaterEqual, (dynamic)v);
            Assert.Equal(values.TailSet(v).Count, await CountRowsAsync(table, greaterEqual));

            // value <= v
            var lessEqual = KuduPredicate.NewComparisonPredicate(col, ComparisonOp.LessEqual, (dynamic)v);
            Assert.Equal(values.HeadSet(v, true).Count, await CountRowsAsync(table, lessEqual));

            // value > v
            var greater = KuduPredicate.NewComparisonPredicate(col, ComparisonOp.Greater, (dynamic)v);
            Assert.Equal(values.TailSet(v, false).Count, await CountRowsAsync(table, greater));

            // value < v
            var less = KuduPredicate.NewComparisonPredicate(col, ComparisonOp.Less, (dynamic)v);
            Assert.Equal(values.HeadSet(v).Count, await CountRowsAsync(table, less));
        }

        var isNotNull = KuduPredicate.NewIsNotNullPredicate(col);

        Assert.Equal(values.Count, await CountRowsAsync(table, isNotNull));

        var isNull = KuduPredicate.NewIsNullPredicate(col);

        Assert.Equal(1, await CountRowsAsync(table, isNull));
    }
    public static KuduOperation CreateAllTypesInsert(KuduTable table, int key)
    {
        var row = table.NewUpsert();

        row.SetInt32("key", key);
        row.SetByte("int8", 42);
        row.SetInt16("int16", 43);
        row.SetInt32("int32", 44);
        row.SetInt64("int64", 45);
        row.SetBool("bool", true);
        row.SetFloat("float", 52.35f);
        row.SetDouble("double", 53.35);
        row.SetString("string", "fun with ütf\0");
        row.SetString("varchar", "árvíztűrő tükörfúrógép");
        row.SetBinary("binary", new byte[] { 0, 1, 2, 3, 4 });
        row.SetDateTime("timestamp", DateTime.Parse("8/19/2020 7:50 PM"));
        row.SetDateTime("date", DateTime.Parse("8/19/2020"));
        row.SetDecimal("decimal32", 12.345m);
        row.SetDecimal("decimal64", 12.346m);
        row.SetDecimal("decimal128", 12.347m);
        return(row);
    }
    public async Task InitializeAsync()
    {
        _harness = await new MiniKuduClusterBuilder().BuildHarnessAsync();
        _client  = _harness.CreateClient();

        var builder = ClientTestUtil.GetBasicSchema()
                      .SetTableName("ScannerFaultToleranceTests")
                      .AddHashPartitions(_numTablets, "key");

        _table = await _client.CreateTableAsync(builder);

        var random = new Random();

        _keys = new HashSet <int>();
        while (_keys.Count < _numRows)
        {
            _keys.Add(random.Next());
        }

        var rows = _keys
                   .Select((key, i) =>
        {
            var insert = _table.NewInsert();
            insert.SetInt32(0, key);
            insert.SetInt32(1, i);
            insert.SetInt32(2, i++);
            insert.SetString(3, DataGenerator.RandomString(1024, random));
            insert.SetBool(4, true);

            return(insert);
        })
                   .Chunk(1000);

        foreach (var batch in rows)
        {
            await _client.WriteAsync(batch);
        }
    }
Exemple #30
0
    /// <summary>
    /// Generates a list of random mutation operations. Any unique row, identified by
    /// it's key, could have a random number of operations/mutations. However, the
    /// target count of numInserts, numUpdates and numDeletes will always be achieved
    /// if the entire list of operations is processed.
    /// </summary>
    /// <param name="table">The table to generate operations for.</param>
    /// <param name="numInserts">The number of row mutations to end with an insert.</param>
    /// <param name="numUpdates">The number of row mutations to end with an update.</param>
    /// <param name="numDeletes">The number of row mutations to end with an delete.</param>
    private List <KuduOperation> GenerateMutationOperations(
        KuduTable table, int numInserts, int numUpdates, int numDeletes)
    {
        var results           = new List <KuduOperation>();
        var unfinished        = new List <MutationState>();
        int minMutationsBound = 5;

        // Generate Operations to initialize all of the row with inserts.
        var changeCounts = new List <(RowOperation type, int count)>
        {
            (RowOperation.Insert, numInserts),
            (RowOperation.Update, numUpdates),
            (RowOperation.Delete, numDeletes)
        };

        foreach (var(type, count) in changeCounts)
        {
            for (int i = 0; i < count; i++)
            {
                // Generate a random insert.
                var insert = table.NewInsert();
                _generator.RandomizeRow(insert);
                var key = insert.GetInt32(0);
                // Add the insert to the results.
                results.Add(insert);
                // Initialize the unfinished MutationState.
                unfinished.Add(new MutationState(key, type, _random.Next(minMutationsBound)));
            }
        }

        // Randomly pull from the unfinished list, mutate it and add that operation to
        // the results. If it has been mutated at least the minimum number of times,
        // remove it from the unfinished list.
        while (unfinished.Count > 0)
        {
            // Get a random row to mutate.
            int           index = _random.Next(unfinished.Count);
            MutationState state = unfinished[index];

            // If the row is done, remove it from unfinished and continue.
            if (state.NumMutations >= state.MinMutations && state.CurrentType == state.EndType)
            {
                unfinished.RemoveAt(index);
                continue;
            }

            // Otherwise, generate an operation to mutate the row based on its current ChangeType.
            //    insert -> update|delete
            //    update -> update|delete
            //    delete -> insert
            KuduOperation op;
            if (state.CurrentType == RowOperation.Insert || state.CurrentType == RowOperation.Update)
            {
                op = _random.NextBool() ? table.NewUpdate() : table.NewDelete();
            }
            else
            {
                // Must be a delete, so we need an insert next.
                op = table.NewInsert();
            }

            op.SetInt32(0, state.Key);

            if (op.Operation != RowOperation.Delete)
            {
                _generator.RandomizeRow(op, randomizeKeys: false);
            }

            results.Add(op);

            state.CurrentType = op.Operation;
            state.NumMutations++;
        }

        return(results);
    }