コード例 #1
0
        public void Test_ScanWait()
        {
            var doc = new Document <DocumentContent>
            {
                Id      = "Test_ReadYourOwnWrite_WaitScan",
                Content = new DocumentContent
                {
                    Value = new Random().Next(0, 100000)
                }
            };

            var result = _bucket.Upsert(doc);

            Assert.True(result.Success);

            var state = MutationState.From(result.Document);

            var request = new QueryRequest("SELECT d.* FROM default as d WHERE `value` = $1 LIMIT 1")
                          .AddPositionalParameter(doc.Content.Value)
                          .ConsistentWith(state)
                          .ScanWait(TimeSpan.FromSeconds(10));

            var queryResult = _bucket.Query <DocumentContent>(request);

            Assert.True(queryResult.Success, queryResult.ToString());
            Assert.IsNotEmpty(queryResult.Rows);
            Assert.AreEqual(doc.Content.Value, queryResult.Rows.First().Value);
        }
コード例 #2
0
        public void Test_ReadYourOwnWrite()
        {
            Assert.IsTrue(_bucket.SupportsEnhancedDurability);

            var doc = new Document<DocumentContent>
            {
                Id = "Test_ReadYourOwnWrite",
                Content = new DocumentContent()
                {
                    Value = new Random().Next(0, 100000)
                }
            };

            var result = _bucket.Upsert(doc);
            Assert.True(result.Success);

            var state = MutationState.From(result.Document);

            var request = new QueryRequest("SELECT d.* FROM default as d WHERE `value` = $1 LIMIT 1")
                .AddPositionalParameter(doc.Content.Value)
                .ConsistentWith(state);

            var queryResult = _bucket.Query<DocumentContent>(request);

            Assert.True(queryResult.Success);
            Assert.IsNotEmpty(queryResult.Rows);
            Assert.AreEqual(doc.Content.Value, queryResult.Rows.First().Value);
        }
コード例 #3
0
        private static async Task ScanConsistencyAtPlusExample(ICluster cluster, ICouchbaseCollection collection)
        {
            // tag::atplus[]
            // create / update document (mutation)
            var upsertResult = await collection.UpsertAsync("doc1", new { name = "Mike AtPlus", type = "user" });

            // create mutation state from mutation results
            var state = MutationState.From(upsertResult);

            // use mutation state with query option
            var result = await cluster.QueryAsync <dynamic>(
                "SELECT t.* FROM `travel-sample` t WHERE t.type=$1",
                options => options.ConsistentWith(state)
                .Parameter("user")
                );

            // end::atplus[]

            // check query was successful
            if (result.MetaData.Status != QueryStatus.Success)
            {
                // error
            }

            // iterate over rows
            // NOTE: because the query is using AtPlus, the new user will be indexed, but notice
            // the extra step of creating the 'state' object and passing it in as a 'ConsistentWith' option
            await foreach (var row in result)
            {
                // each row is an instance of the Query<T> call (e.g. dynamic or custom type)
                var name = row.name;        // "Mike AtPlus"
                Console.WriteLine($"{name}");
            }
        }
コード例 #4
0
        // end::RequestPlusExample[]

        // tag::AtPlusExample[]
        private static void AtPlusExample()
        {
            Console.WriteLine("========= AtPlus");

            // get the current count
            var result1 = _bucket.Query <dynamic>("SELECT COUNT(1) as airportCount FROM `travel-sample` WHERE type='airport'")
                          .Rows.First();

            Console.WriteLine($"Initial count: {result1.airportCount}");

            // insert a new airport
            var doc = new Document <dynamic>
            {
                Id      = "ScanConsistency::airport::" + _random.Next(10000),
                Content = new
                {
                    type = "airport"
                }
            };
            var insertResult = _bucket.Insert(doc);

            // get the count again
            var state   = MutationState.From(insertResult.Document);
            var request = new QueryRequest("SELECT COUNT(1) as airportCount FROM `travel-sample` WHERE type='airport'");
            var t       = request.ConsistentWith(state);
            var result2 = _bucket.Query <dynamic>(t).Rows.First();

            Console.WriteLine($"Count after insert with AtPlus: {result2.airportCount}");
        }
コード例 #5
0
        public void GetFormValues_MultipleTokensSameVBucketId_HighestSequenceNumberIsUsed2()
        {
            var document1 = new Mock <IDocument <dynamic> >();

            document1.Setup(x => x.Token).Returns(new MutationToken("bucket1_name", 102, 22, 9999));

            var document2 = new Mock <IDocument <dynamic> >();

            document2.Setup(x => x.Token).Returns(new MutationToken("bucket1_name", 102, 11, 8332));

            var document3 = new Mock <IDocument <dynamic> >();

            document3.Setup(x => x.Token).Returns(new MutationToken("bucket2_name", 133, 23, 333));

            var queryRequest = new QueryRequest("SELECT * FROM `bucket1_name`;").
                               ConsistentWith(MutationState.From(document1.Object, document2.Object, document3.Object)).
#pragma warning disable 618
                               ScanConsistency(ScanConsistency.AtPlus);

#pragma warning restore 618

            var actual   = queryRequest.GetFormValues()["scan_vectors"];
            var expected = "{\"bucket1_name\":{\"102\":[9999,\"22\"]},\"bucket2_name\":{\"133\":[333,\"23\"]}}";

            Assert.AreEqual(expected, JsonConvert.SerializeObject(actual));
        }
コード例 #6
0
        public void GetFormValues_WhenScanConsistenyIsAtPlus_ScanVectorsIsAddedToFormValues()
        {
            var document1 = new Mock <IDocument <dynamic> >();

            document1.Setup(x => x.Token).Returns(new MutationToken("bucket1_name", 102, 22, 8282));

            var document2 = new Mock <IDocument <dynamic> >();

            document2.Setup(x => x.Token).Returns(new MutationToken("bucket1_name", 123, 11, 8332));

            var document3 = new Mock <IDocument <dynamic> >();

            document3.Setup(x => x.Token).Returns(new MutationToken("bucket2_name", 133, 23, 333));

            var queryRequest = new QueryRequest("SELECT * FROM `bucket1_name`;").
                               ConsistentWith(MutationState.From(document1.Object, document2.Object, document3.Object)).
#pragma warning disable 618
                               ScanConsistency(ScanConsistency.AtPlus);

#pragma warning restore 618

            var actual   = queryRequest.GetFormValues()["scan_vectors"];
            var expected = "{\"bucket1_name\":{\"102\":[8282,\"22\"],\"123\":[8332,\"11\"]},\"bucket2_name\":{\"133\":[333,\"23\"]}}";

            Assert.AreEqual(expected, JsonConvert.SerializeObject(actual));
        }
コード例 #7
0
        public void GetFormValues_ScanVector_CorrectValues()
        {
            // Arrange

            var token1 = new MutationToken("defaultIndex", 1, 9, 12);
            var token2 = new MutationToken("defaultIndex", 2, 1, 22);

            var state = new MutationState()
                        .Add(
                // ReSharper disable PossibleUnintendedReferenceComparison
                Mock.Of <IMutationResult>(m => m.MutationToken == token1),
                Mock.Of <IMutationResult>(m => m.MutationToken == token2));
            // ReSharper restore PossibleUnintendedReferenceComparison

            var options = new SearchOptions()
                          .ConsistentWith(state);

            // Assert

            var json         = options.ToJson("defaultIndex");
            var vectors      = json.SelectToken("ctl.consistency.vectors");
            var indexVectors = vectors["defaultIndex"];

            Assert.Equal(12, indexVectors["1/9"]);
            Assert.Equal(22, indexVectors["2/1"]);
        }
コード例 #8
0
        public void Test_CloneIdUsedAlready()
        {
            var cts           = new CancellationTokenSource();
            var mutationState = new MutationState();

            mutationState.Add(new MutationResult(0, TimeSpan.FromSeconds(10), new MutationToken("default", 1, 1, 1)));
            var options = new QueryOptions().
                          AdHoc(true).AutoExecute(true).
                          CancellationToken(cts.Token).
                          ClientContextId("clientid").
                          ConsistentWith(mutationState).
                          FlexIndex(true).
                          MaxServerParallelism(1).
                          Metrics(true).
                          Parameter(1).
                          Parameter("name", "value").
                          PipelineBatch(1).
                          PipelineCap(1).
                          PreserveExpiry(true).
                          Profile(QueryProfile.Off).
                          Raw("foo", "bar").
                          Readonly(true).
                          ScanCap(1).
                          ScanWait(TimeSpan.FromSeconds(10)).
                          Timeout(TimeSpan.FromMilliseconds(1)).
                          Statement("SELECT 1;").
                          ScanCap(1);

            var newOptions = options.CloneIfUsedAlready();
            var newValues  = newOptions.GetFormValues();
            var oldValues  = options.GetFormValues();

            Assert.Equal(newValues.Count, oldValues.Count);
            Assert.Equal(newValues["max_parallelism"], oldValues["max_parallelism"]);
            Assert.Equal(newValues["statement"], oldValues["statement"]);
            Assert.Equal(newValues["timeout"], oldValues["timeout"]);
            Assert.Equal(newValues["readonly"], oldValues["readonly"]);
            Assert.Equal(newValues["metrics"], oldValues["metrics"]);
            Assert.Equal(newValues["$name"], oldValues["$name"]);
            Assert.Equal(newValues["args"], oldValues["args"]);
            Assert.Equal(newValues["scan_consistency"], oldValues["scan_consistency"]);
            Assert.Equal(newValues["scan_vectors"], oldValues["scan_vectors"]);
            Assert.Equal(newValues["scan_wait"], oldValues["scan_wait"]);
            Assert.Equal(newValues["scan_cap"], oldValues["scan_cap"]);
            Assert.Equal(newValues["pipeline_batch"], oldValues["pipeline_batch"]);
            Assert.Equal(newValues["pipeline_cap"], oldValues["pipeline_cap"]);
            Assert.Equal(newValues["preserve_expiry"], oldValues["preserve_expiry"]);
            Assert.Equal(newValues["foo"], oldValues["foo"]);
            Assert.Equal(newValues["auto_execute"], oldValues["auto_execute"]);
            Assert.Equal(newValues["client_context_id"], oldValues["client_context_id"]);
            Assert.Equal(newValues["use_fts"], oldValues["use_fts"]);
        }
コード例 #9
0
        /// <summary>
        /// Requires that the indexes but up to date with a <see cref="MutationState"/> before the query is executed.
        /// </summary>
        /// <param name="source">Sets consistency requirement for this query.  Must be a Couchbase LINQ query.</param>
        /// <param name="state"><see cref="MutationState"/> used for conistency controls.</param>
        /// <remarks>If called multiple times, the states from the calls are combined.</remarks>
        public static IQueryable <T> ConsistentWith <T>(this IQueryable <T> source, MutationState state)
        {
            if (source == null)
            {
                throw new ArgumentNullException(nameof(source));
            }

            return(source.Provider.CreateQuery <T>(
                       Expression.Call(
                           QueryExtensionMethods.ConsistentWith.MakeGenericMethod(typeof(T)),
                           source.Expression,
                           Expression.Constant(state))));
        }
コード例 #10
0
        /// <summary>
        /// Requires that the indexes but up to date with a <see cref="N1QL.MutationState"/> before the query is executed.
        /// </summary>
        /// <param name="state"><see cref="N1QL.MutationState"/> used for conistency controls.</param>
        /// <remarks>If called multiple times, the states from the calls are combined.</remarks>
        public void ConsistentWith(MutationState state)
        {
            if (state == null)
            {
                return;
            }

            if (MutationState == null)
            {
                MutationState = new MutationState();
            }

            MutationState.Add(state);
        }
コード例 #11
0
        public SearchOptions ConsistentWith(MutationState mutationState)
        {
#pragma warning disable 618
            ScanConsistency(SearchScanConsistency.AtPlus);
#pragma warning restore 618
            _scanVectors = new Dictionary <string, Dictionary <string, List <object> > >();
            foreach (var token in mutationState)
            {
                if (_scanVectors.TryGetValue(token.BucketRef, out var vector))
                {
                    var bucketId = token.VBucketId.ToString();
                    if (vector.TryGetValue(bucketId, out var bucketRef))
                    {
                        if ((long)bucketRef.First() < token.SequenceNumber)
                        {
                            vector[bucketId] = new List <object>
                            {
                                token.SequenceNumber,
                                token.VBucketUuid.ToString()
                            };
                        }
                    }
                    else
                    {
                        vector.Add(token.VBucketId.ToString(),
                                   new List <object>
                        {
                            token.SequenceNumber,
                            token.VBucketUuid.ToString()
                        });
                    }
                }
                else
                {
                    _scanVectors.Add(token.BucketRef, new Dictionary <string, List <object> >
                    {
                        {
                            token.VBucketId.ToString(),
                            new List <object>
                            {
                                token.SequenceNumber,
                                token.VBucketUuid.ToString()
                            }
                        }
                    });
                }
            }

            return(this);
        }
コード例 #12
0
        /// <summary>
        /// Requires that the indexes but up to date with a <see cref="MutationState"/> before the query is executed.
        /// </summary>
        /// <param name="source">Sets consistency requirement for this query.  Must be a Couchbase LINQ query.</param>
        /// <param name="state"><see cref="MutationState"/> used for conistency controls.</param>
        /// <remarks>If called multiple times, the states from the calls are combined.</remarks>
        public static IQueryable <T> ConsistentWith <T>(this IQueryable <T> source, MutationState state)
        {
            if (source == null)
            {
                throw new ArgumentNullException("source");
            }
            if (!(source is IBucketQueryExecutorProvider))
            {
                // do nothing if this isn't a Couchbase LINQ query
                return(source);
            }

            ((IBucketQueryExecutorProvider)source).BucketQueryExecutor.ConsistentWith(state);

            return(source);
        }
コード例 #13
0
        internal virtual void AddToMutationState(MutationToken token)
        {
            if (token == null || !IsTokenSet(token))
            {
                // No token was returned, so don't add to the mutation state
                return;
            }

            if (MutationState == null)
            {
                MutationState = new MutationState();
            }

            MutationState.Add(new TempDocument()
            {
                Token = token
            });
        }
コード例 #14
0
        public void MutationState_WhenScanConsistencyIsNotAtPlus_ThrowsArgumentException()
        {
            var document1 = new Mock <IDocument <dynamic> >();

            document1.Setup(x => x.Token).Returns(new MutationToken("bucket1_name", 102, 22, 8282));

            var document2 = new Mock <IDocument <dynamic> >();

            document2.Setup(x => x.Token).Returns(new MutationToken("bucket1_name", 123, 11, 8332));

            var document3 = new Mock <IDocument <dynamic> >();

            document3.Setup(x => x.Token).Returns(new MutationToken("bucket2_name", 133, 23, 333));

            var queryRequest = new QueryRequest("SELECT * FROM `bucket1_name`;").
                               ConsistentWith(MutationState.From(document1.Object, document2.Object, document3.Object)).
                               ScanConsistency(ScanConsistency.NotBounded);

            Assert.Throws <ArgumentException>(() => queryRequest.GetFormValues());
        }
コード例 #15
0
        public async Task ConsistentWith_ScanWait()
        {
            var context = new BucketContext(TestSetup.Bucket);

            var upsertResult = await TestSetup.Bucket.DefaultCollection().UpsertAsync("test-mutation", new { a = "a" });

            try
            {
                var mutationState = MutationState.From(upsertResult);

                var beers = from b in context.Query <Beer>().ConsistentWith(mutationState, TimeSpan.FromSeconds(10))
                            select b;

                var beer = await beers.FirstAsync();

                Console.WriteLine(beer.Name);
            }
            finally
            {
                await TestSetup.Bucket.DefaultCollection().RemoveAsync("test-mutation");
            }
        }
コード例 #16
0
        public async Task GetRequestBody_ScanVector_CorrectFormatting()
        {
            // Arrange

            var token1 = new MutationToken("WHAT", 105, 105, 945678);
            var token2 = new MutationToken("WHAT", 105, 105, 955555);
            var token3 = new MutationToken("WHAT", 210, 210, 12345);

            var state = new MutationState()
                        .Add(
                // ReSharper disable PossibleUnintendedReferenceComparison
                Mock.Of <IMutationResult>(m => m.MutationToken == token1),
                Mock.Of <IMutationResult>(m => m.MutationToken == token2),
                Mock.Of <IMutationResult>(m => m.MutationToken == token3));
            // ReSharper restore PossibleUnintendedReferenceComparison

            var options = new QueryOptions("SELECT * FROM WHAT").ConsistentWith(state);

            // Act

            using var content = options.GetRequestBody(GetSerializer());

            // Assert

            var values = await ExtractValuesAsync(content);

            var vectors       = (JObject)values["scan_vectors"];
            var bucketVectors = (JObject)vectors["WHAT"];

            var vBucketComponent1 = (JArray)bucketVectors["105"];

            Assert.Equal(955555L, vBucketComponent1[0]);
            Assert.Equal("105", vBucketComponent1[1]);

            var vBucketComponent2 = (JArray)bucketVectors["210"];

            Assert.Equal(12345L, vBucketComponent2[0]);
            Assert.Equal("210", vBucketComponent2[1]);
        }
コード例 #17
0
        public void GetFormValues_ScanVector_CorrectValues()
        {
            // Arrange

            var token1 = new MutationToken("WHAT", 105, 105, 945678);
            var token2 = new MutationToken("WHAT", 105, 105, 955555);
            var token3 = new MutationToken("WHAT", 210, 210, 12345);

            var state = new MutationState()
                        .Add(
                // ReSharper disable PossibleUnintendedReferenceComparison
                Mock.Of <IMutationResult>(m => m.MutationToken == token1),
                Mock.Of <IMutationResult>(m => m.MutationToken == token2),
                Mock.Of <IMutationResult>(m => m.MutationToken == token3));
            // ReSharper restore PossibleUnintendedReferenceComparison

            var options = new QueryOptions("SELECT * FROM WHAT")
                          .ConsistentWith(state);

            // Assert

            var values = options.GetFormValues();

            var vectors       = (Dictionary <string, Dictionary <string, ScanVectorComponent> >)values["scan_vectors"] !;
            var bucketVectors = vectors["WHAT"];

            var vBucketComponent1 = bucketVectors["105"];

            Assert.Equal(955555L, vBucketComponent1.SequenceNumber);
            Assert.Equal(105, vBucketComponent1.VBucketUuid);

            var vBucketComponent2 = bucketVectors["210"];

            Assert.Equal(12345L, vBucketComponent2.SequenceNumber);
            Assert.Equal(210, vBucketComponent2.VBucketUuid);
        }
コード例 #18
0
 public void ConsistentWith(MutationState state)
 {
 }
コード例 #19
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);
    }
コード例 #20
0
 /// <summary>
 /// Initializes a new instance of the <see cref="ConsistentWithClause" /> class.
 /// </summary>
 /// <param name="mutationState">Mutation state for the query.</param>
 /// <param name="scanWait">Time to wait for index scan.</param>
 public ConsistentWithClause(MutationState mutationState, TimeSpan?scanWait)
 {
     MutationState = mutationState;
     ScanWait      = scanWait;
 }
コード例 #21
0
        /// <summary>
        /// Provides a means of ensuring "read your own writes" or RYOW consistency on the current query.
        /// </summary>
#pragma warning disable 618
        /// <remarks>Note: <see cref="ScanConsistency"/> will be overwritten to <see cref="N1QL.ScanConsistency.AtPlus"/>.</remarks>
#pragma warning restore 618
        /// <param name="mutationState">State of the mutation.</param>
        /// <returns>A reference to the current <see cref="IQueryRequest"/> for method chaining.</returns>
        public IQueryRequest ConsistentWith(MutationState mutationState)
        {
#pragma warning disable 618
            ScanConsistency(N1QL.ScanConsistency.AtPlus);
#pragma warning restore 618
            _scanVectors = new Dictionary<string, Dictionary<string, List<object>>>();
            foreach (var token in mutationState)
            {
                Dictionary<string, List<object>> vector;
                if (_scanVectors.TryGetValue(token.BucketRef, out vector))
                {
                    var bucketId = token.VBucketId.ToString();
                    List<object> bucketRef;
                    if (vector.TryGetValue(bucketId, out bucketRef))
                    {
                        if ((long)bucketRef.First() < token.SequenceNumber)
                        {
                            vector[bucketId] = new List<object>
                            {
                                token.SequenceNumber,
                                token.VBucketUUID.ToString()
                            };
                        }
                    }
                    else
                    {
                        vector.Add(token.VBucketId.ToString(),
                            new List<object>
                            {
                                token.SequenceNumber,
                                token.VBucketUUID.ToString()
                            });
                    }
                }
                else
                {
                    _scanVectors.Add(token.BucketRef, new Dictionary<string, List<object>>
                    {
                        {
                            token.VBucketId.ToString(),
                            new List<object>
                            {
                                token.SequenceNumber,
                                token.VBucketUUID.ToString()
                            }
                        }
                    });
                }
            }
            return this;
        }
コード例 #22
0
 public void ResetMutationState()
 {
     _mutationState = new MutationState();;
 }
コード例 #23
0
 /// <summary>
 /// Resets the <see cref="MutationState"/> to start a new set of mutations.
 /// </summary>
 /// <remarks>
 /// If you are using an <see cref="BucketContext"/> over and extended period of time,
 /// performing a reset regularly is recommend.  This will help keep the size of the
 /// <see cref="MutationState"/> to a minimum.
 /// </remarks>
 public void ResetMutationState()
 {
     MutationState = null;
 }