YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/docdb/docrowwiseiterator-test.cc
Line
Count
Source (jump to first uncovered line)
1
// Copyright (c) YugaByte, Inc.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4
// in compliance with the License.  You may obtain a copy of the License at
5
//
6
// http://www.apache.org/licenses/LICENSE-2.0
7
//
8
// Unless required by applicable law or agreed to in writing, software distributed under the License
9
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
10
// or implied.  See the License for the specific language governing permissions and limitations
11
// under the License.
12
//
13
14
#include <memory>
15
#include <string>
16
17
#include "yb/common/common.pb.h"
18
#include "yb/common/ql_expr.h"
19
#include "yb/common/ql_value.h"
20
#include "yb/common/read_hybrid_time.h"
21
#include "yb/common/transaction-test-util.h"
22
23
#include "yb/docdb/doc_key.h"
24
#include "yb/docdb/doc_rowwise_iterator.h"
25
#include "yb/docdb/docdb.h"
26
#include "yb/docdb/docdb_rocksdb_util.h"
27
#include "yb/docdb/docdb_test_base.h"
28
#include "yb/docdb/docdb_test_util.h"
29
30
#include "yb/server/hybrid_clock.h"
31
32
#include "yb/util/size_literals.h"
33
#include "yb/util/test_macros.h"
34
#include "yb/util/test_util.h"
35
36
DECLARE_bool(TEST_docdb_sort_weak_intents);
37
38
namespace yb {
39
namespace docdb {
40
41
class DocRowwiseIteratorTest : public DocDBTestBase {
42
 protected:
43
0
  DocRowwiseIteratorTest() {
44
0
    SeedRandom();
45
0
  }
46
0
  ~DocRowwiseIteratorTest() override {}
47
48
  // TODO Could define them out of class, so one line would be enough for them.
49
  static const KeyBytes kEncodedDocKey1;
50
  static const KeyBytes kEncodedDocKey2;
51
  static const Schema kSchemaForIteratorTests;
52
  static Schema kProjectionForIteratorTests;
53
54
0
  void SetUp() override {
55
0
    FLAGS_TEST_docdb_sort_weak_intents = true;
56
0
    DocDBTestBase::SetUp();
57
0
  }
58
59
0
  static void SetUpTestCase() {
60
0
    ASSERT_OK(kSchemaForIteratorTests.CreateProjectionByNames({"c", "d", "e"},
61
0
        &kProjectionForIteratorTests));
62
0
  }
63
};
64
65
const KeyBytes DocRowwiseIteratorTest::kEncodedDocKey1(
66
    DocKey(PrimitiveValues("row1", 11111)).Encode());
67
68
const KeyBytes DocRowwiseIteratorTest::kEncodedDocKey2(
69
    DocKey(PrimitiveValues("row2", 22222)).Encode());
70
71
const Schema DocRowwiseIteratorTest::kSchemaForIteratorTests({
72
        ColumnSchema("a", DataType::STRING, /* is_nullable = */ false),
73
        ColumnSchema("b", DataType::INT64, false),
74
        // Non-key columns
75
        ColumnSchema("c", DataType::STRING, true),
76
        ColumnSchema("d", DataType::INT64, true),
77
        ColumnSchema("e", DataType::STRING, true)
78
    }, {
79
        10_ColId,
80
        20_ColId,
81
        30_ColId,
82
        40_ColId,
83
        50_ColId
84
    }, 2);
85
86
Schema DocRowwiseIteratorTest::kProjectionForIteratorTests;
87
88
0
TEST_F(DocRowwiseIteratorTest, DocRowwiseIteratorTest) {
89
  // Row 1
90
  // We don't need any seeks for writes, where column values are primitives.
91
0
  ASSERT_OK(SetPrimitive(
92
0
      DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
93
0
      PrimitiveValue("row1_c"), HybridTime::FromMicros(1000)));
94
0
  ASSERT_OK(SetPrimitive(
95
0
      DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
96
0
      PrimitiveValue(10000), HybridTime::FromMicros(1000)));
97
0
  ASSERT_OK(SetPrimitive(
98
0
      DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
99
0
      PrimitiveValue("row1_e"), HybridTime::FromMicros(1000)));
100
101
  // Row 2: one null column, one column that gets deleted and overwritten, another that just gets
102
  // overwritten. No seeks needed for writes.
103
0
  ASSERT_OK(SetPrimitive(
104
0
      DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
105
0
      PrimitiveValue(20000), HybridTime::FromMicros(2000)));
106
107
  // Deletions normally perform a lookup of the key to see whether it's already there. We will use
108
  // that to provide the expected result (the number of rows deleted in SQL or whether a key was
109
  // deleted in Redis). However, because we've just set a value at this path, we don't expect to
110
  // perform any reads for this deletion.
111
0
  ASSERT_OK(DeleteSubDoc(
112
0
      DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
113
0
      HybridTime::FromMicros(2500)));
114
115
  // The entire subdocument under DocPath(encoded_doc_key2, 40) just got deleted, and that fact
116
  // should still be in the write batch's cache, so we should not perform a seek to overwrite it.
117
0
  ASSERT_OK(SetPrimitive(
118
0
      DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
119
0
      PrimitiveValue(30000), HybridTime::FromMicros(3000)));
120
0
  ASSERT_OK(SetPrimitive(
121
0
      DocPath(kEncodedDocKey2, PrimitiveValue(50_ColId)),
122
0
      PrimitiveValue("row2_e"), HybridTime::FromMicros(2000)));
123
124
0
  ASSERT_OK(SetPrimitive(
125
0
      DocPath(kEncodedDocKey2, PrimitiveValue(50_ColId)),
126
0
      PrimitiveValue("row2_e_prime"), HybridTime::FromMicros(4000)));
127
128
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
129
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30); HT{ physical: 1000 }]) -> "row1_c"
130
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 }]) -> 10000
131
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 1000 }]) -> "row1_e"
132
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 3000 }]) -> 30000
133
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 2500 }]) -> DEL
134
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 2000 }]) -> 20000
135
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50); HT{ physical: 4000 }]) -> "row2_e_prime"
136
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50); HT{ physical: 2000 }]) -> "row2_e"
137
0
      )#");
138
139
0
  const Schema &schema = kSchemaForIteratorTests;
140
0
  const Schema &projection = kProjectionForIteratorTests;
141
0
  QLTableRow row;
142
0
  QLValue value;
143
144
0
  {
145
0
    DocRowwiseIterator iter(
146
0
        projection, schema, kNonTransactionalOperationContext, doc_db(),
147
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(2000));
148
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
149
150
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
151
0
    ASSERT_OK(iter.NextRow(&row));
152
153
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
154
0
    ASSERT_FALSE(value.IsNull());
155
0
    ASSERT_EQ("row1_c", value.string_value());
156
157
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
158
0
    ASSERT_FALSE(value.IsNull());
159
0
    ASSERT_EQ(10000, value.int64_value());
160
161
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
162
0
    ASSERT_FALSE(value.IsNull());
163
0
    ASSERT_EQ("row1_e", value.string_value());
164
165
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
166
0
    ASSERT_OK(iter.NextRow(&row));
167
168
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
169
0
    ASSERT_TRUE(value.IsNull());
170
171
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
172
0
    ASSERT_FALSE(value.IsNull());
173
0
    ASSERT_EQ(20000, value.int64_value());
174
175
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
176
0
    ASSERT_FALSE(value.IsNull());
177
0
    ASSERT_EQ("row2_e", value.string_value());
178
179
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
180
0
  }
181
182
  // Scan at a later hybrid_time.
183
184
0
  {
185
0
    DocRowwiseIterator iter(
186
0
        projection, schema, kNonTransactionalOperationContext, doc_db(),
187
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(5000));
188
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
189
190
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
191
0
    ASSERT_OK(iter.NextRow(&row));
192
193
    // This row is exactly the same as in the previous case. TODO: deduplicate.
194
195
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
196
0
    ASSERT_FALSE(value.IsNull());
197
0
    ASSERT_EQ("row1_c", value.string_value());
198
199
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
200
0
    ASSERT_FALSE(value.IsNull());
201
0
    ASSERT_EQ(10000, value.int64_value());
202
203
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
204
0
    ASSERT_FALSE(value.IsNull());
205
0
    ASSERT_EQ("row1_e", value.string_value());
206
207
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
208
0
    ASSERT_OK(iter.NextRow(&row));
209
210
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
211
0
    ASSERT_TRUE(value.IsNull());
212
213
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
214
0
    ASSERT_FALSE(value.IsNull());
215
216
    // These two rows have different values compared to the previous case.
217
0
    ASSERT_EQ(30000, value.int64_value());
218
219
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
220
0
    ASSERT_FALSE(value.IsNull());
221
0
    ASSERT_EQ("row2_e_prime", value.string_value());
222
223
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
224
0
  }
225
0
}
226
227
0
TEST_F(DocRowwiseIteratorTest, DocRowwiseIteratorDeletedDocumentTest) {
228
0
  ASSERT_OK(SetPrimitive(
229
0
      DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
230
0
      PrimitiveValue("row1_c"), HybridTime::FromMicros(1000)));
231
0
  ASSERT_OK(SetPrimitive(
232
0
      DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
233
0
      PrimitiveValue(10000), HybridTime::FromMicros(1000)));
234
0
  ASSERT_OK(SetPrimitive(
235
0
      DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
236
0
      PrimitiveValue("row1_e"), HybridTime::FromMicros(1000)));
237
0
  ASSERT_OK(SetPrimitive(
238
0
      DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
239
0
      PrimitiveValue(20000), HybridTime::FromMicros(2000)));
240
241
  // Delete entire row1 document to test that iterator can successfully jump to next document
242
  // when it finds deleted document.
243
0
  ASSERT_OK(DeleteSubDoc(
244
0
      DocPath(kEncodedDocKey1), HybridTime::FromMicros(2500)));
245
246
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
247
0
      SubDocKey(DocKey([], ["row1", 11111]), [HT{ physical: 2500 }]) -> DEL
248
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30); HT{ physical: 1000 }]) -> "row1_c"
249
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 }]) -> 10000
250
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 1000 }]) -> "row1_e"
251
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 2000 }]) -> 20000
252
0
      )#");
253
254
0
  const Schema &schema = kSchemaForIteratorTests;
255
0
  const Schema &projection = kProjectionForIteratorTests;
256
257
0
  {
258
0
    DocRowwiseIterator iter(
259
0
        projection, schema, kNonTransactionalOperationContext, doc_db(),
260
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(2500));
261
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
262
263
0
    QLTableRow row;
264
0
    QLValue value;
265
266
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
267
0
    ASSERT_OK(iter.NextRow(&row));
268
269
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
270
0
    ASSERT_TRUE(value.IsNull());
271
272
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
273
0
    ASSERT_FALSE(value.IsNull());
274
0
    ASSERT_EQ(20000, value.int64_value());
275
276
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
277
0
    ASSERT_TRUE(value.IsNull());
278
279
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
280
0
  }
281
0
}
282
283
0
TEST_F(DocRowwiseIteratorTest, DocRowwiseIteratorTestRowDeletes) {
284
0
  auto dwb = MakeDocWriteBatch();
285
286
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
287
0
      PrimitiveValue("row1_c")));
288
289
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
290
0
      PrimitiveValue(10000)));
291
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(1000)));
292
293
0
  ASSERT_OK(dwb.DeleteSubDoc(DocPath(kEncodedDocKey1)));
294
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(2500)));
295
296
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
297
0
      PrimitiveValue("row1_e")));
298
299
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
300
0
      PrimitiveValue(20000)));
301
0
  ASSERT_OK(WriteToRocksDB(dwb, HybridTime::FromMicros(2800)));
302
303
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
304
0
SubDocKey(DocKey([], ["row1", 11111]), [HT{ physical: 2500 }]) -> DEL
305
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30); HT{ physical: 1000 }]) -> "row1_c"
306
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 w: 1 }]) -> 10000
307
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 2800 }]) -> "row1_e"
308
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 2800 w: 1 }]) -> 20000
309
0
      )#");
310
311
0
  const Schema &schema = kSchemaForIteratorTests;
312
0
  const Schema &projection = kProjectionForIteratorTests;
313
314
0
  {
315
0
    DocRowwiseIterator iter(
316
0
        projection, schema, kNonTransactionalOperationContext, doc_db(),
317
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(2800));
318
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
319
320
0
    QLTableRow row;
321
0
    QLValue value;
322
323
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
324
0
    ASSERT_OK(iter.NextRow(&row));
325
326
    // ColumnId 30, 40 should be hidden whereas ColumnId 50 should be visible.
327
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
328
0
    ASSERT_TRUE(value.IsNull());
329
330
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
331
0
    ASSERT_TRUE(value.IsNull());
332
333
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
334
0
    ASSERT_FALSE(value.IsNull());
335
0
    ASSERT_EQ("row1_e", value.string_value());
336
337
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
338
0
    ASSERT_OK(iter.NextRow(&row));
339
340
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
341
0
    ASSERT_TRUE(value.IsNull());
342
343
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
344
0
    ASSERT_FALSE(value.IsNull());
345
0
    ASSERT_EQ(20000, value.int64_value());
346
347
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
348
0
    ASSERT_TRUE(value.IsNull());
349
0
  }
350
0
}
351
352
void VerifyOldestRecordTime(IntentAwareIterator *iter, const DocKey &doc_key,
353
                            const SubDocKey &subkey, HybridTime min_hybrid_time,
354
0
                            HybridTime expected_oldest_record_time) {
355
0
  iter->Seek(doc_key);
356
0
  const KeyBytes subkey_bytes = subkey.EncodeWithoutHt();
357
0
  const Slice subkey_slice = subkey_bytes.AsSlice();
358
0
  Slice read_value;
359
0
  HybridTime oldest_past_min_ht =
360
0
      ASSERT_RESULT(iter->FindOldestRecord(subkey_slice, min_hybrid_time));
361
0
  LOG(INFO) << "iter->FindOldestRecord returned " << oldest_past_min_ht
362
0
            << " for " << SubDocKey::DebugSliceToString(subkey_slice);
363
0
  ASSERT_EQ(oldest_past_min_ht, expected_oldest_record_time);
364
0
}
365
366
void VerifyOldestRecordTime(IntentAwareIterator *iter, const DocKey &doc_key,
367
                            const SubDocKey &subkey, uint64_t min_hybrid_time,
368
0
                            uint64_t expected_oldest_record_time) {
369
0
  VerifyOldestRecordTime(iter, doc_key, subkey,
370
0
                         HybridTime::FromMicros(min_hybrid_time),
371
0
                         HybridTime::FromMicros(expected_oldest_record_time));
372
0
}
373
374
void VerifyOldestRecordTimeIsInvalid(IntentAwareIterator *iter,
375
                                     const DocKey &doc_key,
376
                                     const SubDocKey &subkey,
377
0
                                     uint64_t min_hybrid_time) {
378
0
  VerifyOldestRecordTime(iter, doc_key, subkey,
379
0
                         HybridTime::FromMicros(min_hybrid_time),
380
0
                         HybridTime::kInvalid);
381
0
}
382
383
0
TEST_F(DocRowwiseIteratorTest, BackfillInsert) {
384
0
  ASSERT_OK(DeleteSubDoc(DocPath(kEncodedDocKey1), 5000_usec_ht));
385
0
  ASSERT_OK(SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
386
0
                         PrimitiveValue(10000), 1000_usec_ht));
387
388
0
  ASSERT_OK(SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
389
0
                         PrimitiveValue("row1_e"), 1000_usec_ht));
390
391
0
  ASSERT_OK(SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
392
0
                         PrimitiveValue(10000), 900_usec_ht));
393
394
0
  ASSERT_OK(SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
395
0
                         PrimitiveValue("row1_e"), 900_usec_ht));
396
397
0
  ASSERT_OK(DeleteSubDoc(DocPath(kEncodedDocKey1), 500_usec_ht));
398
0
  ASSERT_OK(SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
399
0
                         PrimitiveValue(10000), 300_usec_ht));
400
401
0
  ASSERT_OK(SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
402
0
                         PrimitiveValue("row1_e"), 300_usec_ht));
403
404
0
  ASSERT_OK(DeleteSubDoc(DocPath(kEncodedDocKey2), 900_usec_ht));
405
0
  ASSERT_OK(DeleteSubDoc(DocPath(kEncodedDocKey2), 700_usec_ht));
406
407
0
  SetTransactionIsolationLevel(IsolationLevel::SNAPSHOT_ISOLATION);
408
0
  Result<TransactionId> txn1 = FullyDecodeTransactionId("0000000000000001");
409
0
  ASSERT_OK(txn1);
410
0
  SetCurrentTransactionId(*txn1);
411
0
  ASSERT_OK(DeleteSubDoc(DocPath(kEncodedDocKey2), 800_usec_ht));
412
413
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
414
0
SubDocKey(DocKey([], ["row1", 11111]), [HT{ physical: 5000 }]) -> DEL
415
0
SubDocKey(DocKey([], ["row1", 11111]), [HT{ physical: 500 }]) -> DEL
416
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 }]) -> 10000
417
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 900 }]) -> 10000
418
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 300 }]) -> 10000
419
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 1000 }]) -> "row1_e"
420
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 900 }]) -> "row1_e"
421
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 300 }]) -> "row1_e"
422
0
SubDocKey(DocKey([], ["row2", 22222]), [HT{ physical: 900 }]) -> DEL
423
0
SubDocKey(DocKey([], ["row2", 22222]), [HT{ physical: 700 }]) -> DEL
424
0
SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 800 w: 1 } -> \
425
0
  TransactionId(30303030-3030-3030-3030-303030303031) none
426
0
SubDocKey(DocKey([], ["row2"]), []) [kWeakRead, kWeakWrite] HT{ physical: 800 w: 2 } -> \
427
0
  TransactionId(30303030-3030-3030-3030-303030303031) none
428
0
SubDocKey(DocKey([], ["row2", 22222]), []) [kStrongRead, kStrongWrite] HT{ physical: 800 } -> \
429
0
  TransactionId(30303030-3030-3030-3030-303030303031) WriteId(0) DEL
430
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 800 } -> \
431
0
  SubDocKey(DocKey([], ["row2", 22222]), []) [kStrongRead, kStrongWrite] HT{ physical: 800 }
432
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 800 w: 1 } -> \
433
0
  SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 800 w: 1 }
434
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 800 w: 2 } -> \
435
0
  SubDocKey(DocKey([], ["row2"]), []) [kWeakRead, kWeakWrite] HT{ physical: 800 w: 2 }
436
0
      )#");
437
438
0
  TransactionStatusManagerMock myTransactionalOperationContext;
439
0
  const TransactionOperationContext kMockTransactionalOperationContext = {
440
0
      TransactionId::GenerateRandom(), &myTransactionalOperationContext};
441
0
  myTransactionalOperationContext.Commit(*txn1, 800_usec_ht);
442
443
0
  const HybridTime kSafeTime = 50000_usec_ht;
444
0
  {
445
0
    DocKey doc_key(PrimitiveValues("row1", 11111));
446
0
    const KeyBytes doc_key_bytes = doc_key.Encode();
447
0
    boost::optional<const yb::Slice> doc_key_optional(doc_key_bytes.AsSlice());
448
0
    auto iter = CreateIntentAwareIterator(
449
0
        doc_db(), BloomFilterMode::USE_BLOOM_FILTER, doc_key_optional,
450
0
        rocksdb::kDefaultQueryId, kMockTransactionalOperationContext,
451
0
        CoarseTimePoint::max(), ReadHybridTime::SingleTime(kSafeTime));
452
453
0
    {
454
0
      SubDocKey subkey(doc_key);
455
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 499, 500);
456
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 500, 5000);
457
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 501, 5000);
458
459
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 4999, 5000);
460
0
      VerifyOldestRecordTimeIsInvalid(iter.get(), doc_key, subkey, 5000);
461
0
      VerifyOldestRecordTimeIsInvalid(iter.get(), doc_key, subkey, 5001);
462
0
    }
463
464
0
    {
465
0
      SubDocKey subkey(doc_key, PrimitiveValue(40_ColId));
466
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 299, 300);
467
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 300, 900);
468
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 301, 900);
469
470
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 500, 900);
471
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 600, 900);
472
473
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 899, 900);
474
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 900, 1000);
475
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 901, 1000);
476
477
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 999, 1000);
478
0
      VerifyOldestRecordTimeIsInvalid(iter.get(), doc_key, subkey, 1000);
479
0
      VerifyOldestRecordTimeIsInvalid(iter.get(), doc_key, subkey, 1001);
480
0
      VerifyOldestRecordTimeIsInvalid(iter.get(), doc_key, subkey, 40000);
481
0
    }
482
0
  }
483
484
0
  {
485
0
    DocKey doc_key(PrimitiveValues("row2", 22222));
486
0
    const KeyBytes doc_key_bytes = doc_key.Encode();
487
0
    boost::optional<const yb::Slice> doc_key_optional(doc_key_bytes.AsSlice());
488
0
    auto iter = CreateIntentAwareIterator(
489
0
        doc_db(), BloomFilterMode::USE_BLOOM_FILTER, doc_key_optional,
490
0
        rocksdb::kDefaultQueryId, kMockTransactionalOperationContext,
491
0
        CoarseTimePoint::max(), ReadHybridTime::SingleTime(kSafeTime));
492
493
0
    {
494
0
      SubDocKey subkey(doc_key);
495
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 400, 700);
496
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 699, 700);
497
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 700, 800);
498
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 701, 800);
499
500
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 750, 800);
501
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 800, 900);
502
0
      VerifyOldestRecordTime(iter.get(), doc_key, subkey, 801, 900);
503
0
      VerifyOldestRecordTimeIsInvalid(iter.get(), doc_key, subkey, 900);
504
0
      VerifyOldestRecordTimeIsInvalid(iter.get(), doc_key, subkey, 1000);
505
0
    }
506
0
  }
507
0
}
508
509
0
TEST_F(DocRowwiseIteratorTest, DocRowwiseIteratorHasNextIdempotence) {
510
0
  ASSERT_OK(SetPrimitive(
511
0
      DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
512
0
      PrimitiveValue(10000), HybridTime::FromMicros(1000)));
513
514
0
  ASSERT_OK(SetPrimitive(
515
0
      DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
516
0
      PrimitiveValue("row1_e"), HybridTime::FromMicros(2800)));
517
518
0
  ASSERT_OK(DeleteSubDoc(DocPath(kEncodedDocKey1), HybridTime::FromMicros(2500)));
519
520
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
521
0
SubDocKey(DocKey([], ["row1", 11111]), [HT{ physical: 2500 }]) -> DEL
522
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 }]) -> 10000
523
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 2800 }]) -> "row1_e"
524
0
      )#");
525
526
0
  const Schema &schema = kSchemaForIteratorTests;
527
0
  const Schema &projection = kProjectionForIteratorTests;
528
529
0
  {
530
0
    DocRowwiseIterator iter(
531
0
        projection, schema, kNonTransactionalOperationContext, doc_db(),
532
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(2800));
533
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
534
535
0
    QLTableRow row;
536
0
    QLValue value;
537
538
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
539
    // Ensure calling HasNext() again doesn't mess up anything.
540
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
541
0
    ASSERT_OK(iter.NextRow(&row));
542
543
    // ColumnId 40 should be deleted whereas ColumnId 50 should be visible.
544
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
545
0
    ASSERT_TRUE(value.IsNull());
546
547
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
548
0
    ASSERT_TRUE(value.IsNull());
549
550
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
551
0
    ASSERT_FALSE(value.IsNull());
552
0
    ASSERT_EQ("row1_e", value.string_value());
553
0
  }
554
0
}
555
556
0
TEST_F(DocRowwiseIteratorTest, DocRowwiseIteratorIncompleteProjection) {
557
0
  auto dwb = MakeDocWriteBatch();
558
559
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
560
0
      PrimitiveValue(10000)));
561
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
562
0
      PrimitiveValue("row1_e")));
563
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
564
0
      PrimitiveValue(20000)));
565
566
0
  ASSERT_OK(WriteToRocksDB(dwb, HybridTime::FromMicros(1000)));
567
568
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
569
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 }]) -> 10000
570
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 1000 w: 1 }]) -> "row1_e"
571
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 1000 w: 2 }]) -> 20000
572
0
      )#");
573
574
0
  const Schema &schema = kSchemaForIteratorTests;
575
0
  Schema projection;
576
0
  ASSERT_OK(kSchemaForIteratorTests.CreateProjectionByNames({"c", "d"},
577
0
      &projection));
578
579
0
  {
580
0
    DocRowwiseIterator iter(
581
0
        projection, schema, kNonTransactionalOperationContext, doc_db(),
582
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(2800));
583
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
584
585
0
    QLTableRow row;
586
0
    QLValue value;
587
588
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
589
0
    ASSERT_OK(iter.NextRow(&row));
590
591
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
592
0
    ASSERT_TRUE(value.IsNull());
593
594
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
595
0
    ASSERT_FALSE(value.IsNull());
596
0
    ASSERT_EQ(10000, value.int64_value());
597
598
    // Now find next row.
599
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
600
0
    ASSERT_OK(iter.NextRow(&row));
601
602
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
603
0
    ASSERT_TRUE(value.IsNull());
604
605
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
606
0
    ASSERT_FALSE(value.IsNull());
607
0
    ASSERT_EQ(20000, value.int64_value());
608
609
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
610
0
  }
611
0
}
612
613
0
TEST_F(DocRowwiseIteratorTest, ColocatedTableTombstoneTest) {
614
0
  constexpr PgTableOid pgtable_id(0x4001);
615
0
  auto dwb = MakeDocWriteBatch();
616
617
0
  DocKey encoded_1_with_tableid;
618
619
0
  ASSERT_OK(encoded_1_with_tableid.FullyDecodeFrom(kEncodedDocKey1));
620
0
  encoded_1_with_tableid.set_pgtable_id(pgtable_id);
621
622
0
  ASSERT_OK(dwb.SetPrimitive(
623
0
      DocPath(encoded_1_with_tableid.Encode(), PrimitiveValue::kLivenessColumn),
624
0
      PrimitiveValue(ValueType::kNullLow)));
625
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(1000)));
626
627
0
  DocKey table_id(pgtable_id);
628
0
  ASSERT_OK(dwb.DeleteSubDoc(DocPath(table_id.Encode())));
629
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(2000)));
630
631
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
632
0
SubDocKey(DocKey(PgTableId=16385, [], []), [HT{ physical: 2000 }]) -> DEL
633
0
SubDocKey(DocKey(PgTableId=16385, [], ["row1", 11111]), [SystemColumnId(0); HT{ physical: 1000 }]) \
634
0
    -> null
635
0
      )#");
636
0
  Schema schema_copy = kSchemaForIteratorTests;
637
0
  schema_copy.set_pgtable_id(pgtable_id);
638
0
  Schema projection;
639
  // Read should have results before delete...
640
0
  {
641
0
    DocRowwiseIterator iter(
642
0
        projection, schema_copy, kNonTransactionalOperationContext, doc_db(),
643
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(1500));
644
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
645
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
646
0
  }
647
  // ...but there should be no results after delete.
648
0
  {
649
0
    DocRowwiseIterator iter(
650
0
        projection, schema_copy, kNonTransactionalOperationContext, doc_db(),
651
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::Max());
652
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
653
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
654
0
  }
655
0
}
656
657
0
TEST_F(DocRowwiseIteratorTest, DocRowwiseIteratorMultipleDeletes) {
658
0
  auto dwb = MakeDocWriteBatch();
659
660
0
  MonoDelta ttl = MonoDelta::FromMilliseconds(1);
661
0
  MonoDelta ttl_expiry = MonoDelta::FromMilliseconds(2);
662
0
  auto read_time = ReadHybridTime::SingleTime(server::HybridClock::AddPhysicalTimeToHybridTime(
663
0
      HybridTime::FromMicros(2800), ttl_expiry));
664
665
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
666
0
      PrimitiveValue("row1_c")));
667
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
668
0
      PrimitiveValue(10000)));
669
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(1000)));
670
671
  // Deletes.
672
0
  ASSERT_OK(dwb.DeleteSubDoc(DocPath(kEncodedDocKey1)));
673
0
  ASSERT_OK(dwb.DeleteSubDoc(DocPath(kEncodedDocKey2)));
674
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(2500)));
675
0
  dwb.Clear();
676
677
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
678
0
      Value(PrimitiveValue("row1_e"), ttl)));
679
680
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey2, PrimitiveValue(30_ColId)),
681
0
      PrimitiveValue::kTombstone));
682
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
683
0
      PrimitiveValue(20000)));
684
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey2, PrimitiveValue(50_ColId)),
685
0
      Value(PrimitiveValue("row2_e"), MonoDelta::FromMilliseconds(3))));
686
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(2800)));
687
688
0
  ASSERT_OK(WriteToRocksDB(dwb, HybridTime::FromMicros(1000)));
689
690
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
691
0
SubDocKey(DocKey([], ["row1", 11111]), [HT{ physical: 2500 }]) -> DEL
692
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30); HT{ physical: 1000 }]) -> "row1_c"
693
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 w: 1 }]) -> 10000
694
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 2800 }]) -> \
695
0
    "row1_e"; ttl: 0.001s
696
0
SubDocKey(DocKey([], ["row2", 22222]), [HT{ physical: 2500 w: 1 }]) -> DEL
697
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(30); HT{ physical: 2800 w: 1 }]) -> DEL
698
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 2800 w: 2 }]) -> 20000
699
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50); HT{ physical: 2800 w: 3 }]) -> \
700
0
    "row2_e"; ttl: 0.003s
701
0
      )#");
702
703
0
  const Schema &schema = kSchemaForIteratorTests;
704
0
  Schema projection;
705
0
  ASSERT_OK(kSchemaForIteratorTests.CreateProjectionByNames({"c", "e"}, &projection));
706
707
0
  {
708
0
    DocRowwiseIterator iter(
709
0
        projection, schema, kNonTransactionalOperationContext, doc_db(),
710
0
        CoarseTimePoint::max() /* deadline */, read_time);
711
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
712
713
0
    QLTableRow row;
714
0
    QLValue value;
715
716
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
717
    // Ensure Idempotency.
718
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
719
0
    ASSERT_OK(iter.NextRow(&row));
720
721
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
722
0
    ASSERT_TRUE(value.IsNull());
723
724
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
725
0
    ASSERT_FALSE(value.IsNull());
726
0
    ASSERT_EQ("row2_e", value.string_value());
727
728
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
729
0
  }
730
0
}
731
732
0
TEST_F(DocRowwiseIteratorTest, DocRowwiseIteratorValidColumnNotInProjection) {
733
0
  auto dwb = MakeDocWriteBatch();
734
735
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
736
0
      PrimitiveValue(10000)));
737
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
738
0
      PrimitiveValue(20000)));
739
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(1000)));
740
741
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey2, PrimitiveValue(50_ColId)),
742
0
      PrimitiveValue("row2_e")));
743
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey2, PrimitiveValue(30_ColId)),
744
0
      PrimitiveValue("row2_c")));
745
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(2000)));
746
747
0
  ASSERT_OK(dwb.DeleteSubDoc(DocPath(kEncodedDocKey1)));
748
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(2500)));
749
750
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
751
0
      PrimitiveValue("row1_e")));
752
0
  ASSERT_OK(WriteToRocksDBAndClear(&dwb, HybridTime::FromMicros(2800)));
753
754
755
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
756
0
      SubDocKey(DocKey([], ["row1", 11111]), [HT{ physical: 2500 }]) -> DEL
757
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 }]) -> 10000
758
0
      SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 2800 }]) -> "row1_e"
759
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(30); HT{ physical: 2000 w: 1 }]) -> "row2_c"
760
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 1000 w: 1 }]) -> 20000
761
0
      SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50); HT{ physical: 2000 }]) -> "row2_e"
762
0
      )#");
763
764
0
  const Schema &schema = kSchemaForIteratorTests;
765
0
  Schema projection;
766
0
  ASSERT_OK(kSchemaForIteratorTests.CreateProjectionByNames({"c", "d"}, &projection));
767
768
0
  {
769
0
    DocRowwiseIterator iter(
770
0
        projection, schema, kNonTransactionalOperationContext, doc_db(),
771
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(2800));
772
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
773
774
0
    QLTableRow row;
775
0
    QLValue value;
776
777
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
778
0
    ASSERT_OK(iter.NextRow(&row));
779
780
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
781
0
    ASSERT_TRUE(value.IsNull());
782
783
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
784
0
    ASSERT_TRUE(value.IsNull());
785
786
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
787
0
    ASSERT_OK(iter.NextRow(&row));
788
789
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
790
0
    ASSERT_FALSE(value.IsNull());
791
0
    ASSERT_EQ("row2_c", value.string_value());
792
793
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
794
0
    ASSERT_FALSE(value.IsNull());
795
0
    ASSERT_EQ(20000, value.int64_value());
796
797
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
798
0
  }
799
0
}
800
801
0
TEST_F(DocRowwiseIteratorTest, DocRowwiseIteratorKeyProjection) {
802
0
  auto dwb = MakeDocWriteBatch();
803
804
  // Row 1
805
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
806
0
      PrimitiveValue(10000)));
807
0
  ASSERT_OK(dwb.SetPrimitive(DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
808
0
      PrimitiveValue("row1_e")));
809
810
0
  ASSERT_OK(WriteToRocksDB(dwb, HybridTime::FromMicros(1000)));
811
812
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
813
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 }]) -> 10000
814
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 1000 w: 1 }]) -> "row1_e"
815
0
      )#");
816
817
0
  const Schema &schema = kSchemaForIteratorTests;
818
0
  Schema projection;
819
0
  ASSERT_OK(kSchemaForIteratorTests.CreateProjectionByNames({"a", "b"},
820
0
      &projection, 2));
821
822
0
  {
823
0
    DocRowwiseIterator iter(
824
0
        projection, schema, kNonTransactionalOperationContext, doc_db(),
825
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(2800));
826
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
827
828
0
    QLTableRow row;
829
0
    QLValue value;
830
831
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
832
0
    ASSERT_OK(iter.NextRow(&row));
833
834
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
835
0
    ASSERT_EQ("row1", value.string_value());
836
837
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
838
0
    ASSERT_EQ(11111, value.int64_value());
839
840
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
841
0
  }
842
0
}
843
844
0
TEST_F(DocRowwiseIteratorTest, DocRowwiseIteratorResolveWriteIntents) {
845
0
  SetTransactionIsolationLevel(IsolationLevel::SNAPSHOT_ISOLATION);
846
847
0
  TransactionStatusManagerMock txn_status_manager;
848
849
0
  auto txn1 = ASSERT_RESULT(FullyDecodeTransactionId("0000000000000001"));
850
0
  auto txn2 = ASSERT_RESULT(FullyDecodeTransactionId("0000000000000002"));
851
852
0
  SetCurrentTransactionId(txn1);
853
0
  ASSERT_OK(SetPrimitive(
854
0
      DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
855
0
      PrimitiveValue("row1_c_t1"), HybridTime::FromMicros(500)));
856
0
  ASSERT_OK(SetPrimitive(
857
0
      DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
858
0
      PrimitiveValue(40000), HybridTime::FromMicros(500)));
859
0
  ASSERT_OK(SetPrimitive(
860
0
      DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
861
0
      PrimitiveValue("row1_e_t1"), HybridTime::FromMicros(500)));
862
0
  ASSERT_OK(SetPrimitive(
863
0
      DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
864
0
      PrimitiveValue(42000), HybridTime::FromMicros(500)));
865
0
  ASSERT_OK(SetPrimitive(
866
0
      DocPath(kEncodedDocKey2, PrimitiveValue(50_ColId)),
867
0
      PrimitiveValue("row2_e_t1"), HybridTime::FromMicros(500)));
868
0
  ResetCurrentTransactionId();
869
870
0
  ASSERT_OK(SetPrimitive(
871
0
      DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
872
0
      PrimitiveValue("row1_c"), HybridTime::FromMicros(1000)));
873
0
  ASSERT_OK(SetPrimitive(
874
0
      DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
875
0
      PrimitiveValue(10000), HybridTime::FromMicros(1000)));
876
0
  ASSERT_OK(SetPrimitive(
877
0
      DocPath(kEncodedDocKey1, PrimitiveValue(50_ColId)),
878
0
      PrimitiveValue("row1_e"), HybridTime::FromMicros(1000)));
879
880
0
  ASSERT_OK(SetPrimitive(
881
0
      DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
882
0
      PrimitiveValue(20000), HybridTime::FromMicros(2000)));
883
884
0
  ASSERT_OK(DeleteSubDoc(
885
0
      DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
886
0
      HybridTime::FromMicros(2500)));
887
0
  ASSERT_OK(SetPrimitive(
888
0
      DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
889
0
      PrimitiveValue(30000), HybridTime::FromMicros(3000)));
890
0
  ASSERT_OK(SetPrimitive(
891
0
      DocPath(kEncodedDocKey2, PrimitiveValue(50_ColId)),
892
0
      PrimitiveValue("row2_e"), HybridTime::FromMicros(2000)));
893
0
  ASSERT_OK(SetPrimitive(
894
0
      DocPath(kEncodedDocKey2, PrimitiveValue(50_ColId)),
895
0
      PrimitiveValue("row2_e_prime"), HybridTime::FromMicros(4000)));
896
897
0
  txn_status_manager.Commit(txn1, HybridTime::FromMicros(3500));
898
899
0
  SetCurrentTransactionId(txn2);
900
0
  ASSERT_OK(DeleteSubDoc(
901
0
      DocPath(kEncodedDocKey1),
902
0
      HybridTime::FromMicros(4000)));
903
0
  ASSERT_OK(SetPrimitive(
904
0
      DocPath(kEncodedDocKey2, PrimitiveValue(50_ColId)),
905
0
      PrimitiveValue("row2_e_t2"), HybridTime::FromMicros(4000)));
906
0
  ResetCurrentTransactionId();
907
0
  txn_status_manager.Commit(txn2, HybridTime::FromMicros(6000));
908
909
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
910
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30); HT{ physical: 1000 }]) -> "row1_c"
911
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 }]) -> 10000
912
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50); HT{ physical: 1000 }]) -> "row1_e"
913
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 3000 }]) -> 30000
914
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 2500 }]) -> DEL
915
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 2000 }]) -> 20000
916
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50); HT{ physical: 4000 }]) -> "row2_e_prime"
917
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50); HT{ physical: 2000 }]) -> "row2_e"
918
0
SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 4000 w: 1 } -> \
919
0
    TransactionId(30303030-3030-3030-3030-303030303032) none
920
0
SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 1 } -> \
921
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
922
0
SubDocKey(DocKey([], ["row1"]), []) [kWeakRead, kWeakWrite] HT{ physical: 4000 w: 2 } -> \
923
0
    TransactionId(30303030-3030-3030-3030-303030303032) none
924
0
SubDocKey(DocKey([], ["row1"]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 2 } -> \
925
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
926
0
SubDocKey(DocKey([], ["row1", 11111]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 3 } -> \
927
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
928
0
SubDocKey(DocKey([], ["row1", 11111]), []) [kStrongRead, kStrongWrite] HT{ physical: 4000 } -> \
929
0
    TransactionId(30303030-3030-3030-3030-303030303032) WriteId(5) DEL
930
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30)]) [kStrongRead, kStrongWrite] \
931
0
    HT{ physical: 500 } -> \
932
0
    TransactionId(30303030-3030-3030-3030-303030303031) WriteId(0) "row1_c_t1"
933
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40)]) [kStrongRead, kStrongWrite] \
934
0
    HT{ physical: 500 } -> \
935
0
    TransactionId(30303030-3030-3030-3030-303030303031) WriteId(1) 40000
936
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(50)]) [kStrongRead, kStrongWrite] \
937
0
    HT{ physical: 500 } -> \
938
0
    TransactionId(30303030-3030-3030-3030-303030303031) WriteId(2) "row1_e_t1"
939
0
SubDocKey(DocKey([], ["row2"]), []) [kWeakRead, kWeakWrite] HT{ physical: 4000 w: 2 } -> \
940
0
    TransactionId(30303030-3030-3030-3030-303030303032) none
941
0
SubDocKey(DocKey([], ["row2"]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 2 } -> \
942
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
943
0
SubDocKey(DocKey([], ["row2", 22222]), []) [kWeakRead, kWeakWrite] HT{ physical: 4000 w: 3 } -> \
944
0
    TransactionId(30303030-3030-3030-3030-303030303032) none
945
0
SubDocKey(DocKey([], ["row2", 22222]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 3 } -> \
946
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
947
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40)]) [kStrongRead, kStrongWrite] \
948
0
    HT{ physical: 500 } -> \
949
0
    TransactionId(30303030-3030-3030-3030-303030303031) WriteId(3) 42000
950
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50)]) [kStrongRead, kStrongWrite] \
951
0
    HT{ physical: 4000 } \
952
0
    -> TransactionId(30303030-3030-3030-3030-303030303032) WriteId(6) "row2_e_t2"
953
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50)]) [kStrongRead, kStrongWrite] \
954
0
    HT{ physical: 500 } -> \
955
0
    TransactionId(30303030-3030-3030-3030-303030303031) WriteId(4) "row2_e_t1"
956
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 } -> \
957
0
    SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50)]) [kStrongRead, kStrongWrite] \
958
0
    HT{ physical: 500 }
959
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 w: 1 } -> \
960
0
    SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 1 }
961
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 w: 2 } -> \
962
0
    SubDocKey(DocKey([], ["row2"]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 2 }
963
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 w: 3 } -> \
964
0
    SubDocKey(DocKey([], ["row2", 22222]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 3 }
965
0
TXN REV 30303030-3030-3030-3030-303030303032 HT{ physical: 4000 } -> \
966
0
    SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(50)]) [kStrongRead, kStrongWrite] \
967
0
    HT{ physical: 4000 }
968
0
TXN REV 30303030-3030-3030-3030-303030303032 HT{ physical: 4000 w: 1 } -> \
969
0
    SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 4000 w: 1 }
970
0
TXN REV 30303030-3030-3030-3030-303030303032 HT{ physical: 4000 w: 2 } -> \
971
0
    SubDocKey(DocKey([], ["row2"]), []) [kWeakRead, kWeakWrite] HT{ physical: 4000 w: 2 }
972
0
TXN REV 30303030-3030-3030-3030-303030303032 HT{ physical: 4000 w: 3 } -> \
973
0
    SubDocKey(DocKey([], ["row2", 22222]), []) [kWeakRead, kWeakWrite] HT{ physical: 4000 w: 3 }
974
0
      )#");
975
976
0
  const Schema &schema = kSchemaForIteratorTests;
977
0
  const Schema &projection = kProjectionForIteratorTests;
978
0
  const auto txn_context = TransactionOperationContext(
979
0
      TransactionId::GenerateRandom(), &txn_status_manager);
980
981
0
  {
982
0
    DocRowwiseIterator iter(
983
0
        projection, schema, txn_context, doc_db(),
984
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(2000));
985
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
986
987
0
    QLTableRow row;
988
0
    QLValue value;
989
990
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
991
0
    ASSERT_OK(iter.NextRow(&row));
992
993
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
994
0
    ASSERT_FALSE(value.IsNull());
995
0
    ASSERT_EQ("row1_c", value.string_value());
996
997
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
998
0
    ASSERT_FALSE(value.IsNull());
999
0
    ASSERT_EQ(10000, value.int64_value());
1000
1001
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
1002
0
    ASSERT_FALSE(value.IsNull());
1003
0
    ASSERT_EQ("row1_e", value.string_value());
1004
1005
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
1006
0
    ASSERT_OK(iter.NextRow(&row));
1007
1008
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
1009
0
    ASSERT_TRUE(value.IsNull());
1010
1011
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
1012
0
    ASSERT_FALSE(value.IsNull());
1013
0
    ASSERT_EQ(20000, value.int64_value());
1014
1015
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
1016
0
    ASSERT_FALSE(value.IsNull());
1017
0
    ASSERT_EQ("row2_e", value.string_value());
1018
1019
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
1020
0
  }
1021
1022
  // Scan at a later hybrid_time.
1023
1024
0
  LOG(INFO) << "===============================================";
1025
0
  {
1026
0
    DocRowwiseIterator iter(
1027
0
        projection, schema, txn_context, doc_db(),
1028
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(5000));
1029
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
1030
0
    QLTableRow row;
1031
0
    QLValue value;
1032
1033
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
1034
0
    ASSERT_OK(iter.NextRow(&row));
1035
1036
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
1037
0
    ASSERT_FALSE(value.IsNull());
1038
0
    ASSERT_EQ("row1_c_t1", value.string_value());
1039
1040
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
1041
0
    ASSERT_FALSE(value.IsNull());
1042
0
    ASSERT_EQ(40000, value.int64_value());
1043
1044
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
1045
0
    ASSERT_FALSE(value.IsNull());
1046
0
    ASSERT_EQ("row1_e_t1", value.string_value());
1047
1048
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
1049
0
    ASSERT_OK(iter.NextRow(&row));
1050
1051
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
1052
0
    ASSERT_TRUE(value.IsNull());
1053
1054
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
1055
0
    ASSERT_FALSE(value.IsNull());
1056
0
    ASSERT_EQ(42000, value.int64_value());
1057
1058
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
1059
0
    ASSERT_FALSE(value.IsNull());
1060
0
    ASSERT_EQ("row2_e_prime", value.string_value());
1061
1062
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
1063
0
  }
1064
1065
  // Scan at a later hybrid_time.
1066
1067
0
  {
1068
0
    DocRowwiseIterator iter(
1069
0
        projection, schema, txn_context, doc_db(),
1070
0
        CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(6000));
1071
0
    ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
1072
1073
0
    QLTableRow row;
1074
0
    QLValue value;
1075
1076
0
    ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
1077
0
    ASSERT_OK(iter.NextRow(&row));
1078
1079
0
    ASSERT_OK(row.GetValue(projection.column_id(0), &value));
1080
0
    ASSERT_TRUE(value.IsNull());
1081
1082
0
    ASSERT_OK(row.GetValue(projection.column_id(1), &value));
1083
0
    ASSERT_FALSE(value.IsNull());
1084
0
    ASSERT_EQ(42000, value.int64_value());
1085
1086
0
    ASSERT_OK(row.GetValue(projection.column_id(2), &value));
1087
0
    ASSERT_FALSE(value.IsNull());
1088
0
    ASSERT_EQ("row2_e_t2", value.string_value());
1089
1090
0
    ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
1091
0
  }
1092
0
}
1093
1094
0
TEST_F(DocRowwiseIteratorTest, IntentAwareIteratorSeek) {
1095
0
  SetTransactionIsolationLevel(IsolationLevel::SNAPSHOT_ISOLATION);
1096
1097
0
  TransactionStatusManagerMock txn_status_manager;
1098
1099
0
  Result<TransactionId> txn = FullyDecodeTransactionId("0000000000000001");
1100
0
  ASSERT_OK(txn);
1101
1102
  // Have a mix of transactional / non-transaction writes.
1103
0
  SetCurrentTransactionId(*txn);
1104
0
  ASSERT_OK(SetPrimitive(
1105
0
      DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
1106
0
      PrimitiveValue("row1_c_txn"), HybridTime::FromMicros(500)));
1107
1108
0
  txn_status_manager.Commit(*txn, HybridTime::FromMicros(600));
1109
1110
0
  ResetCurrentTransactionId();
1111
1112
0
  ASSERT_OK(SetPrimitive(
1113
0
      DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
1114
0
      PrimitiveValue("row1_c"), HybridTime::FromMicros(1000)));
1115
0
  ASSERT_OK(SetPrimitive(
1116
0
      DocPath(kEncodedDocKey1, PrimitiveValue(40_ColId)),
1117
0
      PrimitiveValue(10000), HybridTime::FromMicros(1000)));
1118
0
  ASSERT_OK(SetPrimitive(
1119
0
      DocPath(kEncodedDocKey2, PrimitiveValue(30_ColId)),
1120
0
      PrimitiveValue("row2_c"), HybridTime::FromMicros(1000)));
1121
0
  ASSERT_OK(SetPrimitive(
1122
0
      DocPath(kEncodedDocKey2, PrimitiveValue(40_ColId)),
1123
0
      PrimitiveValue(20000), HybridTime::FromMicros(1000)));
1124
1125
  // Verify the content of RocksDB.
1126
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
1127
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30); HT{ physical: 1000 }]) -> "row1_c"
1128
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(40); HT{ physical: 1000 }]) -> 10000
1129
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(30); HT{ physical: 1000 }]) -> "row2_c"
1130
0
SubDocKey(DocKey([], ["row2", 22222]), [ColumnId(40); HT{ physical: 1000 }]) -> 20000
1131
0
SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 1 } -> \
1132
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
1133
0
SubDocKey(DocKey([], ["row1"]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 2 } -> \
1134
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
1135
0
SubDocKey(DocKey([], ["row1", 11111]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 3 } -> \
1136
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
1137
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30)]) [kStrongRead, kStrongWrite] \
1138
0
    HT{ physical: 500 } -> \
1139
0
    TransactionId(30303030-3030-3030-3030-303030303031) WriteId(0) "row1_c_txn"
1140
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 } -> \
1141
0
    SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30)]) [kStrongRead, kStrongWrite] \
1142
0
    HT{ physical: 500 }
1143
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 w: 1 } -> \
1144
0
    SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 1 }
1145
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 w: 2 } -> \
1146
0
    SubDocKey(DocKey([], ["row1"]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 2 }
1147
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 w: 3 } -> \
1148
0
    SubDocKey(DocKey([], ["row1", 11111]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 3 }
1149
0
    )#");
1150
1151
  // Create a new IntentAwareIterator and seek to an empty DocKey. Verify that it returns the
1152
  // first non-intent key.
1153
0
  IntentAwareIterator iter(
1154
0
      doc_db(), rocksdb::ReadOptions(), CoarseTimePoint::max() /* deadline */,
1155
0
      ReadHybridTime::FromMicros(1000), TransactionOperationContext());
1156
0
  iter.Seek(DocKey());
1157
0
  ASSERT_TRUE(iter.valid());
1158
0
  auto key_data = ASSERT_RESULT(iter.FetchKey());
1159
0
  SubDocKey subdoc_key;
1160
0
  ASSERT_OK(subdoc_key.FullyDecodeFrom(key_data.key, HybridTimeRequired::kFalse));
1161
0
  ASSERT_EQ(subdoc_key.ToString(), R"#(SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30)]))#");
1162
0
  ASSERT_EQ(key_data.write_time.ToString(), "HT{ physical: 1000 }");
1163
0
}
1164
1165
0
TEST_F(DocRowwiseIteratorTest, SeekTwiceWithinTheSameTxn) {
1166
0
  SetTransactionIsolationLevel(IsolationLevel::SNAPSHOT_ISOLATION);
1167
1168
0
  TransactionStatusManagerMock txn_status_manager;
1169
1170
0
  Result<TransactionId> txn = FullyDecodeTransactionId("0000000000000001");
1171
0
  ASSERT_OK(txn);
1172
1173
0
  SetCurrentTransactionId(*txn);
1174
0
  ASSERT_OK(SetPrimitive(
1175
0
      DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
1176
0
      PrimitiveValue("row1_c_t1"), HybridTime::FromMicros(500)));
1177
1178
  // Verify the content of RocksDB.
1179
0
  ASSERT_DOCDB_DEBUG_DUMP_STR_EQ(R"#(
1180
0
SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 1 } -> \
1181
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
1182
0
SubDocKey(DocKey([], ["row1"]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 2 } -> \
1183
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
1184
0
SubDocKey(DocKey([], ["row1", 11111]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 3 } -> \
1185
0
    TransactionId(30303030-3030-3030-3030-303030303031) none
1186
0
SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30)]) [kStrongRead, kStrongWrite] \
1187
0
    HT{ physical: 500 } -> \
1188
0
    TransactionId(30303030-3030-3030-3030-303030303031) WriteId(0) "row1_c_t1"
1189
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 } -> \
1190
0
    SubDocKey(DocKey([], ["row1", 11111]), [ColumnId(30)]) [kStrongRead, kStrongWrite] \
1191
0
    HT{ physical: 500 }
1192
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 w: 1 } -> \
1193
0
    SubDocKey(DocKey([], []), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 1 }
1194
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 w: 2 } -> \
1195
0
    SubDocKey(DocKey([], ["row1"]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 2 }
1196
0
TXN REV 30303030-3030-3030-3030-303030303031 HT{ physical: 500 w: 3 } -> \
1197
0
    SubDocKey(DocKey([], ["row1", 11111]), []) [kWeakRead, kWeakWrite] HT{ physical: 500 w: 3 }
1198
0
      )#");
1199
1200
0
  IntentAwareIterator iter(
1201
0
      doc_db(), rocksdb::ReadOptions(), CoarseTimePoint::max() /* deadline */,
1202
0
      ReadHybridTime::FromMicros(1000), TransactionOperationContext(*txn, &txn_status_manager));
1203
0
  for (int i = 1; i <= 2; ++i) {
1204
0
    iter.Seek(DocKey());
1205
0
    ASSERT_TRUE(iter.valid()) << "Seek #" << i << " failed";
1206
0
  }
1207
0
}
1208
1209
0
TEST_F(DocRowwiseIteratorTest, ScanWithinTheSameTxn) {
1210
0
  SetTransactionIsolationLevel(IsolationLevel::SNAPSHOT_ISOLATION);
1211
1212
0
  TransactionStatusManagerMock txn_status_manager;
1213
1214
0
  Result<TransactionId> txn = FullyDecodeTransactionId("0000000000000001");
1215
0
  ASSERT_OK(txn);
1216
1217
0
  SetCurrentTransactionId(*txn);
1218
0
  ASSERT_OK(SetPrimitive(
1219
0
      DocPath(kEncodedDocKey2, PrimitiveValue(30_ColId)),
1220
0
      PrimitiveValue("row2_c_t1"), HybridTime::FromMicros(500)));
1221
0
  ASSERT_OK(SetPrimitive(
1222
0
      DocPath(kEncodedDocKey1, PrimitiveValue(30_ColId)),
1223
0
      PrimitiveValue("row1_c_t1"), HybridTime::FromMicros(600)));
1224
1225
0
  LOG(INFO) << "Dump:\n" << DocDBDebugDumpToStr();
1226
1227
0
  const auto txn_context = TransactionOperationContext(*txn, &txn_status_manager);
1228
0
  const Schema &projection = kProjectionForIteratorTests;
1229
1230
0
  DocRowwiseIterator iter(
1231
0
      projection, kSchemaForIteratorTests, txn_context, doc_db(),
1232
0
      CoarseTimePoint::max() /* deadline */, ReadHybridTime::FromMicros(1000));
1233
0
  ASSERT_OK(iter.Init(YQL_TABLE_TYPE));
1234
1235
0
  QLTableRow row;
1236
0
  QLValue value;
1237
1238
0
  ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
1239
0
  ASSERT_OK(iter.NextRow(&row));
1240
1241
0
  ASSERT_OK(row.GetValue(projection.column_id(0), &value));
1242
0
  ASSERT_FALSE(value.IsNull());
1243
0
  ASSERT_EQ("row1_c_t1", value.string_value());
1244
1245
0
  ASSERT_OK(row.GetValue(projection.column_id(1), &value));
1246
0
  ASSERT_TRUE(value.IsNull());
1247
1248
0
  ASSERT_OK(row.GetValue(projection.column_id(2), &value));
1249
0
  ASSERT_TRUE(value.IsNull());
1250
1251
0
  ASSERT_TRUE(ASSERT_RESULT(iter.HasNext()));
1252
0
  ASSERT_OK(iter.NextRow(&row));
1253
1254
0
  ASSERT_OK(row.GetValue(projection.column_id(0), &value));
1255
0
  ASSERT_FALSE(value.IsNull());
1256
0
  ASSERT_EQ("row2_c_t1", value.string_value());
1257
1258
0
  ASSERT_OK(row.GetValue(projection.column_id(1), &value));
1259
0
  ASSERT_TRUE(value.IsNull());
1260
1261
0
  ASSERT_OK(row.GetValue(projection.column_id(2), &value));
1262
0
  ASSERT_TRUE(value.IsNull());
1263
1264
0
  ASSERT_FALSE(ASSERT_RESULT(iter.HasNext()));
1265
1266
  // Empirically we require 3 seeks to perform this test.
1267
  // If this number increased, then something got broken and should be fixed.
1268
  // IF this number decreased because of optimization, then we should adjust this check.
1269
0
  ASSERT_EQ(intents_db_options_.statistics->getTickerCount(rocksdb::Tickers::NUMBER_DB_SEEK), 3);
1270
0
}
1271
1272
}  // namespace docdb
1273
}  // namespace yb