YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/rocksdb/db/write_batch_test.cc
Line
Count
Source (jump to first uncovered line)
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
//  This source code is licensed under the BSD-style license found in the
3
//  LICENSE file in the root directory of this source tree. An additional grant
4
//  of patent rights can be found in the PATENTS file in the same directory.
5
//
6
// The following only applies to changes made to this file as part of YugaByte development.
7
//
8
// Portions Copyright (c) YugaByte, Inc.
9
//
10
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
11
// in compliance with the License.  You may obtain a copy of the License at
12
//
13
// http://www.apache.org/licenses/LICENSE-2.0
14
//
15
// Unless required by applicable law or agreed to in writing, software distributed under the License
16
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17
// or implied.  See the License for the specific language governing permissions and limitations
18
// under the License.
19
//
20
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
21
// Use of this source code is governed by a BSD-style license that can be
22
// found in the LICENSE file. See the AUTHORS file for names of contributors.
23
24
#include <memory>
25
#include <string>
26
27
#include <gtest/gtest.h>
28
29
#include "yb/rocksdb/db.h"
30
31
#include "yb/rocksdb/db/memtable.h"
32
#include "yb/rocksdb/db/column_family.h"
33
#include "yb/rocksdb/db/write_batch_internal.h"
34
#include "yb/rocksdb/db/writebuffer.h"
35
#include "yb/rocksdb/env.h"
36
#include "yb/rocksdb/memtablerep.h"
37
#include "yb/rocksdb/utilities/write_batch_with_index.h"
38
#include "yb/rocksdb/table/scoped_arena_iterator.h"
39
#include "yb/rocksdb/util/logging.h"
40
#include "yb/util/string_util.h"
41
#include "yb/util/test_macros.h"
42
#include "yb/rocksdb/util/testutil.h"
43
44
namespace rocksdb {
45
46
30
static std::string PrintContents(WriteBatch* b) {
47
30
  InternalKeyComparator cmp(BytewiseComparator());
48
30
  auto factory = std::make_shared<SkipListFactory>();
49
30
  Options options;
50
30
  options.memtable_factory = factory;
51
30
  ImmutableCFOptions ioptions(options);
52
30
  WriteBuffer wb(options.db_write_buffer_size);
53
30
  MemTable* mem =
54
30
      new MemTable(cmp, ioptions, MutableCFOptions(options, ioptions), &wb,
55
30
                   kMaxSequenceNumber);
56
30
  mem->Ref();
57
30
  std::string state;
58
30
  ColumnFamilyMemTablesDefault cf_mems_default(mem);
59
30
  Status s = WriteBatchInternal::InsertInto(b, &cf_mems_default, nullptr);
60
30
  size_t count = 0;
61
30
  int put_count = 0;
62
30
  int delete_count = 0;
63
30
  int single_delete_count = 0;
64
30
  int merge_count = 0;
65
30
  Arena arena;
66
30
  ScopedArenaIterator iter(mem->NewIterator(ReadOptions(), &arena));
67
72
  for (iter->SeekToFirst(); iter->Valid(); iter->Next()) {
68
42
    ParsedInternalKey ikey;
69
42
    memset(static_cast<void*>(&ikey), 0, sizeof(ikey));
70
42
    EXPECT_TRUE(ParseInternalKey(iter->key(), &ikey));
71
42
    switch (ikey.type) {
72
26
      case kTypeValue:
73
26
        state.append("Put(");
74
26
        state.append(ikey.user_key.ToString());
75
26
        state.append(", ");
76
26
        state.append(iter->value().ToString());
77
26
        state.append(")");
78
26
        count++;
79
26
        put_count++;
80
26
        break;
81
11
      case kTypeDeletion:
82
11
        state.append("Delete(");
83
11
        state.append(ikey.user_key.ToString());
84
11
        state.append(")");
85
11
        count++;
86
11
        delete_count++;
87
11
        break;
88
3
      case kTypeSingleDeletion:
89
3
        state.append("SingleDelete(");
90
3
        state.append(ikey.user_key.ToString());
91
3
        state.append(")");
92
3
        count++;
93
3
        single_delete_count++;
94
3
        break;
95
2
      case kTypeMerge:
96
2
        state.append("Merge(");
97
2
        state.append(ikey.user_key.ToString());
98
2
        state.append(", ");
99
2
        state.append(iter->value().ToString());
100
2
        state.append(")");
101
2
        count++;
102
2
        merge_count++;
103
2
        break;
104
0
      default:
105
0
        assert(false);
106
0
        break;
107
42
    }
108
42
    state.append("@");
109
42
    state.append(NumberToString(ikey.sequence));
110
42
  }
111
30
  EXPECT_EQ(b->HasPut(), put_count > 0);
112
30
  EXPECT_EQ(b->HasDelete(), delete_count > 0);
113
30
  EXPECT_EQ(b->HasSingleDelete(), single_delete_count > 0);
114
30
  EXPECT_EQ(b->HasMerge(), merge_count > 0);
115
30
  if (!s.ok()) {
116
1
    state.append(s.ToString(false));
117
29
  } else if (count != WriteBatchInternal::Count(b)) {
118
0
    state.append("CountMismatch()");
119
0
  }
120
30
  delete mem->Unref();
121
30
  return state;
122
30
}
123
124
class WriteBatchTest : public RocksDBTest {};
125
126
1
TEST_F(WriteBatchTest, Empty) {
127
1
  WriteBatch batch;
128
1
  ASSERT_EQ("", PrintContents(&batch));
129
1
  ASSERT_EQ(0, WriteBatchInternal::Count(&batch));
130
1
  ASSERT_EQ(0, batch.Count());
131
1
}
132
133
1
TEST_F(WriteBatchTest, Multiple) {
134
1
  WriteBatch batch;
135
1
  batch.Put(Slice("foo"), Slice("bar"));
136
1
  batch.Delete(Slice("box"));
137
1
  batch.Put(Slice("baz"), Slice("boo"));
138
1
  WriteBatchInternal::SetSequence(&batch, 100);
139
1
  ASSERT_EQ(100U, WriteBatchInternal::Sequence(&batch));
140
1
  ASSERT_EQ(3, WriteBatchInternal::Count(&batch));
141
1
  ASSERT_EQ("Put(baz, boo)@102"
142
1
            "Delete(box)@101"
143
1
            "Put(foo, bar)@100",
144
1
            PrintContents(&batch));
145
1
  ASSERT_EQ(3, batch.Count());
146
1
}
147
148
1
TEST_F(WriteBatchTest, Corruption) {
149
1
  WriteBatch batch;
150
1
  batch.Put(Slice("foo"), Slice("bar"));
151
1
  batch.Delete(Slice("box"));
152
1
  WriteBatchInternal::SetSequence(&batch, 200);
153
1
  Slice contents = WriteBatchInternal::Contents(&batch);
154
1
  WriteBatchInternal::SetContents(&batch,
155
1
                                  Slice(contents.data(), contents.size() - 1));
156
1
  ASSERT_EQ("Put(foo, bar)@200"
157
1
            "Corruption: bad WriteBatch Delete",
158
1
            PrintContents(&batch));
159
1
}
160
161
1
TEST_F(WriteBatchTest, Append) {
162
1
  WriteBatch b1, b2;
163
1
  WriteBatchInternal::SetSequence(&b1, 200);
164
1
  WriteBatchInternal::SetSequence(&b2, 300);
165
1
  WriteBatchInternal::Append(&b1, &b2);
166
1
  ASSERT_EQ("",
167
1
            PrintContents(&b1));
168
1
  ASSERT_EQ(0, b1.Count());
169
1
  b2.Put("a", "va");
170
1
  WriteBatchInternal::Append(&b1, &b2);
171
1
  ASSERT_EQ("Put(a, va)@200",
172
1
            PrintContents(&b1));
173
1
  ASSERT_EQ(1, b1.Count());
174
1
  b2.Clear();
175
1
  b2.Put("b", "vb");
176
1
  WriteBatchInternal::Append(&b1, &b2);
177
1
  ASSERT_EQ("Put(a, va)@200"
178
1
            "Put(b, vb)@201",
179
1
            PrintContents(&b1));
180
1
  ASSERT_EQ(2, b1.Count());
181
1
  b2.Delete("foo");
182
1
  WriteBatchInternal::Append(&b1, &b2);
183
1
  ASSERT_EQ("Put(a, va)@200"
184
1
            "Put(b, vb)@202"
185
1
            "Put(b, vb)@201"
186
1
            "Delete(foo)@203",
187
1
            PrintContents(&b1));
188
1
  ASSERT_EQ(4, b1.Count());
189
1
}
190
191
1
TEST_F(WriteBatchTest, SingleDeletion) {
192
1
  WriteBatch batch;
193
1
  WriteBatchInternal::SetSequence(&batch, 100);
194
1
  ASSERT_EQ("", PrintContents(&batch));
195
1
  ASSERT_EQ(0, batch.Count());
196
1
  batch.Put("a", "va");
197
1
  ASSERT_EQ("Put(a, va)@100", PrintContents(&batch));
198
1
  ASSERT_EQ(1, batch.Count());
199
1
  batch.SingleDelete("a");
200
1
  ASSERT_EQ(
201
1
      "SingleDelete(a)@101"
202
1
      "Put(a, va)@100",
203
1
      PrintContents(&batch));
204
1
  ASSERT_EQ(2, batch.Count());
205
1
}
206
207
namespace {
208
209
struct TestHandler : public WriteBatch::Handler {
210
  std::string seen;
211
  virtual Status PutCF(uint32_t column_family_id, const SliceParts& key,
212
13
                       const SliceParts& value) override {
213
13
    if (column_family_id == 0) {
214
9
      seen += "Put(" + key.TheOnlyPart().ToDebugString() + ", " +
215
9
              value.TheOnlyPart().ToDebugString() + ")";
216
4
    } else {
217
4
      seen += "PutCF(" + ToString(column_family_id) + ", " +
218
4
              key.TheOnlyPart().ToDebugString() + ", " + value.TheOnlyPart().ToDebugString() + ")";
219
4
    }
220
13
    return Status::OK();
221
13
  }
222
  virtual Status DeleteCF(uint32_t column_family_id,
223
4
                          const Slice& key) override {
224
4
    if (column_family_id == 0) {
225
2
      seen += "Delete(" + key.ToDebugString() + ")";
226
2
    } else {
227
2
      seen += "DeleteCF(" + ToString(column_family_id) + ", " +
228
2
              key.ToDebugString() + ")";
229
2
    }
230
4
    return Status::OK();
231
4
  }
232
  virtual Status SingleDeleteCF(uint32_t column_family_id,
233
4
                                const Slice& key) override {
234
4
    if (column_family_id == 0) {
235
2
      seen += "SingleDelete(" + key.ToDebugString() + ")";
236
2
    } else {
237
2
      seen += "SingleDeleteCF(" + ToString(column_family_id) + ", " +
238
2
              key.ToDebugString() + ")";
239
2
    }
240
4
    return Status::OK();
241
4
  }
242
  virtual Status MergeCF(uint32_t column_family_id, const Slice& key,
243
5
                         const Slice& value) override {
244
5
    if (column_family_id == 0) {
245
3
      seen += "Merge(" + key.ToDebugString() + ", " + value.ToDebugString() + ")";
246
2
    } else {
247
2
      seen += "MergeCF(" + ToString(column_family_id) + ", " +
248
2
              key.ToDebugString() + ", " + value.ToDebugString() + ")";
249
2
    }
250
5
    return Status::OK();
251
5
  }
252
3
  void LogData(const Slice& blob) override {
253
3
    seen += "LogData(" + blob.ToDebugString() + ")";
254
3
  }
255
};
256
257
} // namespace
258
259
1
TEST_F(WriteBatchTest, PutNotImplemented) {
260
1
  WriteBatch batch;
261
1
  batch.Put(Slice("k1"), Slice("v1"));
262
1
  ASSERT_EQ(1, batch.Count());
263
1
  ASSERT_EQ("Put(k1, v1)@0", PrintContents(&batch));
264
265
1
  WriteBatch::Handler handler;
266
1
  ASSERT_OK(batch.Iterate(&handler));
267
1
}
268
269
1
TEST_F(WriteBatchTest, DeleteNotImplemented) {
270
1
  WriteBatch batch;
271
1
  batch.Delete(Slice("k2"));
272
1
  ASSERT_EQ(1, batch.Count());
273
1
  ASSERT_EQ("Delete(k2)@0", PrintContents(&batch));
274
275
1
  WriteBatch::Handler handler;
276
1
  ASSERT_OK(batch.Iterate(&handler));
277
1
}
278
279
1
TEST_F(WriteBatchTest, SingleDeleteNotImplemented) {
280
1
  WriteBatch batch;
281
1
  batch.SingleDelete(Slice("k2"));
282
1
  ASSERT_EQ(1, batch.Count());
283
1
  ASSERT_EQ("SingleDelete(k2)@0", PrintContents(&batch));
284
285
1
  WriteBatch::Handler handler;
286
1
  ASSERT_OK(batch.Iterate(&handler));
287
1
}
288
289
1
TEST_F(WriteBatchTest, MergeNotImplemented) {
290
1
  WriteBatch batch;
291
1
  batch.Merge(Slice("foo"), Slice("bar"));
292
1
  ASSERT_EQ(1, batch.Count());
293
1
  ASSERT_EQ("Merge(foo, bar)@0", PrintContents(&batch));
294
295
1
  WriteBatch::Handler handler;
296
1
  ASSERT_OK(batch.Iterate(&handler));
297
1
}
298
299
1
TEST_F(WriteBatchTest, Blob) {
300
1
  WriteBatch batch;
301
1
  batch.Put(Slice("k1"), Slice("v1"));
302
1
  batch.Put(Slice("k2"), Slice("v2"));
303
1
  batch.Put(Slice("k3"), Slice("v3"));
304
1
  batch.PutLogData(Slice("blob1"));
305
1
  batch.Delete(Slice("k2"));
306
1
  batch.SingleDelete(Slice("k3"));
307
1
  batch.PutLogData(Slice("blob2"));
308
1
  batch.Merge(Slice("foo"), Slice("bar"));
309
1
  ASSERT_EQ(6, batch.Count());
310
1
  ASSERT_EQ(
311
1
      "Merge(foo, bar)@5"
312
1
      "Put(k1, v1)@0"
313
1
      "Delete(k2)@3"
314
1
      "Put(k2, v2)@1"
315
1
      "SingleDelete(k3)@4"
316
1
      "Put(k3, v3)@2",
317
1
      PrintContents(&batch));
318
319
1
  TestHandler handler;
320
1
  ASSERT_OK(batch.Iterate(&handler));
321
1
  ASSERT_EQ(
322
1
      "Put(k1, v1)"
323
1
      "Put(k2, v2)"
324
1
      "Put(k3, v3)"
325
1
      "LogData(blob1)"
326
1
      "Delete(k2)"
327
1
      "SingleDelete(k3)"
328
1
      "LogData(blob2)"
329
1
      "Merge(foo, bar)",
330
1
      handler.seen);
331
1
}
332
333
// It requires more than 30GB of memory to run the test. With single memory
334
// allocation of more than 30GB.
335
// Not all platform can run it. Also it runs a long time. So disable it.
336
TEST_F(WriteBatchTest, DISABLED_ManyUpdates) {
337
  // Insert key and value of 3GB and push total batch size to 12GB.
338
  static const size_t kKeyValueSize = 4u;
339
  static const uint32_t kNumUpdates = 3 << 30;
340
  std::string raw(kKeyValueSize, 'A');
341
  WriteBatch batch(kNumUpdates * (4 + kKeyValueSize * 2) + 1024u);
342
  char c = 'A';
343
  for (uint32_t i = 0; i < kNumUpdates; i++) {
344
    if (c > 'Z') {
345
      c = 'A';
346
    }
347
    raw[0] = c;
348
    raw[raw.length() - 1] = c;
349
    c++;
350
    batch.Put(raw, raw);
351
  }
352
353
  ASSERT_EQ(kNumUpdates, batch.Count());
354
355
  struct NoopHandler : public WriteBatch::Handler {
356
    uint32_t num_seen = 0;
357
    char expected_char = 'A';
358
    virtual Status PutCF(uint32_t column_family_id, const SliceParts& key,
359
                         const SliceParts& value) override {
360
      EXPECT_EQ(kKeyValueSize, key.TheOnlyPart().size());
361
      EXPECT_EQ(kKeyValueSize, value.TheOnlyPart().size());
362
      EXPECT_EQ(expected_char, key.TheOnlyPart()[0]);
363
      EXPECT_EQ(expected_char, value.TheOnlyPart()[0]);
364
      EXPECT_EQ(expected_char, key.TheOnlyPart()[kKeyValueSize - 1]);
365
      EXPECT_EQ(expected_char, value.TheOnlyPart()[kKeyValueSize - 1]);
366
      expected_char++;
367
      if (expected_char > 'Z') {
368
        expected_char = 'A';
369
      }
370
      ++num_seen;
371
      return Status::OK();
372
    }
373
    virtual Status DeleteCF(uint32_t column_family_id,
374
0
                            const Slice& key) override {
375
0
      EXPECT_TRUE(false);
376
0
      return Status::OK();
377
0
    }
378
    virtual Status SingleDeleteCF(uint32_t column_family_id,
379
0
                                  const Slice& key) override {
380
0
      EXPECT_TRUE(false);
381
0
      return Status::OK();
382
0
    }
383
    virtual Status MergeCF(uint32_t column_family_id, const Slice& key,
384
0
                           const Slice& value) override {
385
0
      EXPECT_TRUE(false);
386
0
      return Status::OK();
387
0
    }
388
0
    void LogData(const Slice& blob) override { EXPECT_TRUE(false); }
389
0
    bool Continue() override { return num_seen < kNumUpdates; }
390
  } handler;
391
392
  ASSERT_OK(batch.Iterate(&handler));
393
  ASSERT_EQ(kNumUpdates, handler.num_seen);
394
}
395
396
// The test requires more than 18GB memory to run it, with single memory
397
// allocation of more than 12GB. Not all the platform can run it. So disable it.
398
TEST_F(WriteBatchTest, DISABLED_LargeKeyValue) {
399
  // Insert key and value of 3GB and push total batch size to 12GB.
400
  static const size_t kKeyValueSize = 3221225472u;
401
  std::string raw(kKeyValueSize, 'A');
402
  WriteBatch batch(12884901888u + 1024u);
403
  for (char i = 0; i < 2; i++) {
404
    raw[0] = 'A' + i;
405
    raw[raw.length() - 1] = 'A' - i;
406
    batch.Put(raw, raw);
407
  }
408
409
  ASSERT_EQ(2, batch.Count());
410
411
  struct NoopHandler : public WriteBatch::Handler {
412
    int num_seen = 0;
413
    virtual Status PutCF(uint32_t column_family_id, const SliceParts& key,
414
                         const SliceParts& value) override {
415
      EXPECT_EQ(kKeyValueSize, key.TheOnlyPart().size());
416
      EXPECT_EQ(kKeyValueSize, value.TheOnlyPart().size());
417
      EXPECT_EQ('A' + num_seen, key.TheOnlyPart()[0]);
418
      EXPECT_EQ('A' + num_seen, value.TheOnlyPart()[0]);
419
      EXPECT_EQ('A' - num_seen, key.TheOnlyPart()[kKeyValueSize - 1]);
420
      EXPECT_EQ('A' - num_seen, value.TheOnlyPart()[kKeyValueSize - 1]);
421
      ++num_seen;
422
      return Status::OK();
423
    }
424
    virtual Status DeleteCF(uint32_t column_family_id,
425
0
                            const Slice& key) override {
426
0
      EXPECT_TRUE(false);
427
0
      return Status::OK();
428
0
    }
429
    virtual Status SingleDeleteCF(uint32_t column_family_id,
430
0
                                  const Slice& key) override {
431
0
      EXPECT_TRUE(false);
432
0
      return Status::OK();
433
0
    }
434
    virtual Status MergeCF(uint32_t column_family_id, const Slice& key,
435
0
                           const Slice& value) override {
436
0
      EXPECT_TRUE(false);
437
0
      return Status::OK();
438
0
    }
439
0
    void LogData(const Slice& blob) override { EXPECT_TRUE(false); }
440
0
    bool Continue() override { return num_seen < 2; }
441
  } handler;
442
443
  ASSERT_OK(batch.Iterate(&handler));
444
  ASSERT_EQ(2, handler.num_seen);
445
}
446
447
1
TEST_F(WriteBatchTest, Continue) {
448
1
  WriteBatch batch;
449
450
1
  struct Handler : public TestHandler {
451
1
    int num_seen = 0;
452
1
    virtual Status PutCF(uint32_t column_family_id, const SliceParts& key,
453
2
                         const SliceParts& value) override {
454
2
      ++num_seen;
455
2
      return TestHandler::PutCF(column_family_id, key, value);
456
2
    }
457
1
    virtual Status DeleteCF(uint32_t column_family_id,
458
1
                            const Slice& key) override {
459
1
      ++num_seen;
460
1
      return TestHandler::DeleteCF(column_family_id, key);
461
1
    }
462
1
    virtual Status SingleDeleteCF(uint32_t column_family_id,
463
1
                                  const Slice& key) override {
464
1
      ++num_seen;
465
1
      return TestHandler::SingleDeleteCF(column_family_id, key);
466
1
    }
467
1
    virtual Status MergeCF(uint32_t column_family_id, const Slice& key,
468
0
                           const Slice& value) override {
469
0
      ++num_seen;
470
0
      return TestHandler::MergeCF(column_family_id, key, value);
471
0
    }
472
1
    void LogData(const Slice& blob) override {
473
1
      ++num_seen;
474
1
      TestHandler::LogData(blob);
475
1
    }
476
6
    bool Continue() override { return num_seen < 5; }
477
1
  } handler;
478
479
1
  batch.Put(Slice("k1"), Slice("v1"));
480
1
  batch.Put(Slice("k2"), Slice("v2"));
481
1
  batch.PutLogData(Slice("blob1"));
482
1
  batch.Delete(Slice("k1"));
483
1
  batch.SingleDelete(Slice("k2"));
484
1
  batch.PutLogData(Slice("blob2"));
485
1
  batch.Merge(Slice("foo"), Slice("bar"));
486
1
  auto status = batch.Iterate(&handler);
487
1
  LOG(INFO) << "Iterate result: " << status;
488
1
  ASSERT_EQ(
489
1
      "Put(k1, v1)"
490
1
      "Put(k2, v2)"
491
1
      "LogData(blob1)"
492
1
      "Delete(k1)"
493
1
      "SingleDelete(k2)",
494
1
      handler.seen);
495
1
}
496
497
1
TEST_F(WriteBatchTest, PutGatherSlices) {
498
1
  WriteBatch batch;
499
1
  batch.Put(Slice("foo"), Slice("bar"));
500
501
1
  {
502
    // Try a write where the key is one slice but the value is two
503
1
    Slice key_slice("baz");
504
1
    Slice value_slices[2] = { Slice("header"), Slice("payload") };
505
1
    batch.Put(SliceParts(&key_slice, 1),
506
1
              SliceParts(value_slices, 2));
507
1
  }
508
509
1
  {
510
    // One where the key is composite but the value is a single slice
511
1
    Slice key_slices[3] = { Slice("key"), Slice("part2"), Slice("part3") };
512
1
    Slice value_slice("value");
513
1
    batch.Put(SliceParts(key_slices, 3),
514
1
              SliceParts(&value_slice, 1));
515
1
  }
516
517
1
  WriteBatchInternal::SetSequence(&batch, 100);
518
1
  ASSERT_EQ("Put(baz, headerpayload)@101"
519
1
            "Put(foo, bar)@100"
520
1
            "Put(keypart2part3, value)@102",
521
1
            PrintContents(&batch));
522
1
  ASSERT_EQ(3, batch.Count());
523
1
}
524
525
namespace {
526
class ColumnFamilyHandleImplDummy : public ColumnFamilyHandleImpl {
527
 public:
528
  explicit ColumnFamilyHandleImplDummy(int id)
529
8
      : ColumnFamilyHandleImpl(nullptr, nullptr, nullptr), id_(id) {}
530
31
  uint32_t GetID() const override { return id_; }
531
7
  const Comparator* user_comparator() const override {
532
7
    return BytewiseComparator();
533
7
  }
534
535
 private:
536
  uint32_t id_;
537
};
538
539
}  // anonymous namespace
540
541
1
TEST_F(WriteBatchTest, ColumnFamiliesBatchTest) {
542
1
  WriteBatch batch;
543
1
  ColumnFamilyHandleImplDummy zero(0), two(2), three(3), eight(8);
544
1
  batch.Put(&zero, Slice("foo"), Slice("bar"));
545
1
  batch.Put(&two, Slice("twofoo"), Slice("bar2"));
546
1
  batch.Put(&eight, Slice("eightfoo"), Slice("bar8"));
547
1
  batch.Delete(&eight, Slice("eightfoo"));
548
1
  batch.SingleDelete(&two, Slice("twofoo"));
549
1
  batch.Merge(&three, Slice("threethree"), Slice("3three"));
550
1
  batch.Put(&zero, Slice("foo"), Slice("bar"));
551
1
  batch.Merge(Slice("omom"), Slice("nom"));
552
553
1
  TestHandler handler;
554
1
  ASSERT_OK(batch.Iterate(&handler));
555
1
  ASSERT_EQ(
556
1
      "Put(foo, bar)"
557
1
      "PutCF(2, twofoo, bar2)"
558
1
      "PutCF(8, eightfoo, bar8)"
559
1
      "DeleteCF(8, eightfoo)"
560
1
      "SingleDeleteCF(2, twofoo)"
561
1
      "MergeCF(3, threethree, 3three)"
562
1
      "Put(foo, bar)"
563
1
      "Merge(omom, nom)",
564
1
      handler.seen);
565
1
}
566
567
#ifndef ROCKSDB_LITE
568
1
TEST_F(WriteBatchTest, ColumnFamiliesBatchWithIndexTest) {
569
1
  WriteBatchWithIndex batch;
570
1
  ColumnFamilyHandleImplDummy zero(0), two(2), three(3), eight(8);
571
1
  batch.Put(&zero, Slice("foo"), Slice("bar"));
572
1
  batch.Put(&two, Slice("twofoo"), Slice("bar2"));
573
1
  batch.Put(&eight, Slice("eightfoo"), Slice("bar8"));
574
1
  batch.Delete(&eight, Slice("eightfoo"));
575
1
  batch.SingleDelete(&two, Slice("twofoo"));
576
1
  batch.Merge(&three, Slice("threethree"), Slice("3three"));
577
1
  batch.Put(&zero, Slice("foo"), Slice("bar"));
578
1
  batch.Merge(Slice("omom"), Slice("nom"));
579
580
1
  std::unique_ptr<WBWIIterator> iter;
581
582
1
  iter.reset(batch.NewIterator(&eight));
583
1
  iter->Seek("eightfoo");
584
1
  ASSERT_OK(iter->status());
585
1
  ASSERT_TRUE(iter->Valid());
586
1
  ASSERT_EQ(WriteType::kPutRecord, iter->Entry().type);
587
1
  ASSERT_EQ("eightfoo", iter->Entry().key.ToString());
588
1
  ASSERT_EQ("bar8", iter->Entry().value.ToString());
589
590
1
  iter->Next();
591
1
  ASSERT_OK(iter->status());
592
1
  ASSERT_TRUE(iter->Valid());
593
1
  ASSERT_EQ(WriteType::kDeleteRecord, iter->Entry().type);
594
1
  ASSERT_EQ("eightfoo", iter->Entry().key.ToString());
595
596
1
  iter->Next();
597
1
  ASSERT_OK(iter->status());
598
1
  ASSERT_TRUE(!iter->Valid());
599
600
1
  iter.reset(batch.NewIterator(&two));
601
1
  iter->Seek("twofoo");
602
1
  ASSERT_OK(iter->status());
603
1
  ASSERT_TRUE(iter->Valid());
604
1
  ASSERT_EQ(WriteType::kPutRecord, iter->Entry().type);
605
1
  ASSERT_EQ("twofoo", iter->Entry().key.ToString());
606
1
  ASSERT_EQ("bar2", iter->Entry().value.ToString());
607
608
1
  iter->Next();
609
1
  ASSERT_OK(iter->status());
610
1
  ASSERT_TRUE(iter->Valid());
611
1
  ASSERT_EQ(WriteType::kSingleDeleteRecord, iter->Entry().type);
612
1
  ASSERT_EQ("twofoo", iter->Entry().key.ToString());
613
614
1
  iter->Next();
615
1
  ASSERT_OK(iter->status());
616
1
  ASSERT_TRUE(!iter->Valid());
617
618
1
  iter.reset(batch.NewIterator());
619
1
  iter->Seek("gggg");
620
1
  ASSERT_OK(iter->status());
621
1
  ASSERT_TRUE(iter->Valid());
622
1
  ASSERT_EQ(WriteType::kMergeRecord, iter->Entry().type);
623
1
  ASSERT_EQ("omom", iter->Entry().key.ToString());
624
1
  ASSERT_EQ("nom", iter->Entry().value.ToString());
625
626
1
  iter->Next();
627
1
  ASSERT_OK(iter->status());
628
1
  ASSERT_TRUE(!iter->Valid());
629
630
1
  iter.reset(batch.NewIterator(&zero));
631
1
  iter->Seek("foo");
632
1
  ASSERT_OK(iter->status());
633
1
  ASSERT_TRUE(iter->Valid());
634
1
  ASSERT_EQ(WriteType::kPutRecord, iter->Entry().type);
635
1
  ASSERT_EQ("foo", iter->Entry().key.ToString());
636
1
  ASSERT_EQ("bar", iter->Entry().value.ToString());
637
638
1
  iter->Next();
639
1
  ASSERT_OK(iter->status());
640
1
  ASSERT_TRUE(iter->Valid());
641
1
  ASSERT_EQ(WriteType::kPutRecord, iter->Entry().type);
642
1
  ASSERT_EQ("foo", iter->Entry().key.ToString());
643
1
  ASSERT_EQ("bar", iter->Entry().value.ToString());
644
645
1
  iter->Next();
646
1
  ASSERT_OK(iter->status());
647
1
  ASSERT_TRUE(iter->Valid());
648
1
  ASSERT_EQ(WriteType::kMergeRecord, iter->Entry().type);
649
1
  ASSERT_EQ("omom", iter->Entry().key.ToString());
650
1
  ASSERT_EQ("nom", iter->Entry().value.ToString());
651
652
1
  iter->Next();
653
1
  ASSERT_OK(iter->status());
654
1
  ASSERT_TRUE(!iter->Valid());
655
656
1
  TestHandler handler;
657
1
  ASSERT_OK(batch.GetWriteBatch()->Iterate(&handler));
658
1
  ASSERT_EQ(
659
1
      "Put(foo, bar)"
660
1
      "PutCF(2, twofoo, bar2)"
661
1
      "PutCF(8, eightfoo, bar8)"
662
1
      "DeleteCF(8, eightfoo)"
663
1
      "SingleDeleteCF(2, twofoo)"
664
1
      "MergeCF(3, threethree, 3three)"
665
1
      "Put(foo, bar)"
666
1
      "Merge(omom, nom)",
667
1
      handler.seen);
668
1
}
669
#endif  // !ROCKSDB_LITE
670
671
1
TEST_F(WriteBatchTest, SavePointTest) {
672
1
  Status s;
673
1
  WriteBatch batch;
674
1
  batch.SetSavePoint();
675
676
1
  batch.Put("A", "a");
677
1
  batch.Put("B", "b");
678
1
  batch.SetSavePoint();
679
680
1
  batch.Put("C", "c");
681
1
  batch.Delete("A");
682
1
  batch.SetSavePoint();
683
1
  batch.SetSavePoint();
684
685
1
  ASSERT_OK(batch.RollbackToSavePoint());
686
1
  ASSERT_EQ(
687
1
      "Delete(A)@3"
688
1
      "Put(A, a)@0"
689
1
      "Put(B, b)@1"
690
1
      "Put(C, c)@2",
691
1
      PrintContents(&batch));
692
693
1
  ASSERT_OK(batch.RollbackToSavePoint());
694
1
  ASSERT_OK(batch.RollbackToSavePoint());
695
1
  ASSERT_EQ(
696
1
      "Put(A, a)@0"
697
1
      "Put(B, b)@1",
698
1
      PrintContents(&batch));
699
700
1
  batch.Delete("A");
701
1
  batch.Put("B", "bb");
702
703
1
  ASSERT_OK(batch.RollbackToSavePoint());
704
1
  ASSERT_EQ("", PrintContents(&batch));
705
706
1
  s = batch.RollbackToSavePoint();
707
1
  ASSERT_TRUE(s.IsNotFound());
708
1
  ASSERT_EQ("", PrintContents(&batch));
709
710
1
  batch.Put("D", "d");
711
1
  batch.Delete("A");
712
713
1
  batch.SetSavePoint();
714
715
1
  batch.Put("A", "aaa");
716
717
1
  ASSERT_OK(batch.RollbackToSavePoint());
718
1
  ASSERT_EQ(
719
1
      "Delete(A)@1"
720
1
      "Put(D, d)@0",
721
1
      PrintContents(&batch));
722
723
1
  batch.SetSavePoint();
724
725
1
  batch.Put("D", "d");
726
1
  batch.Delete("A");
727
728
1
  ASSERT_OK(batch.RollbackToSavePoint());
729
1
  ASSERT_EQ(
730
1
      "Delete(A)@1"
731
1
      "Put(D, d)@0",
732
1
      PrintContents(&batch));
733
734
1
  s = batch.RollbackToSavePoint();
735
1
  ASSERT_TRUE(s.IsNotFound());
736
1
  ASSERT_EQ(
737
1
      "Delete(A)@1"
738
1
      "Put(D, d)@0",
739
1
      PrintContents(&batch));
740
741
1
  WriteBatch batch2;
742
743
1
  s = batch2.RollbackToSavePoint();
744
1
  ASSERT_TRUE(s.IsNotFound());
745
1
  ASSERT_EQ("", PrintContents(&batch2));
746
747
1
  batch2.Delete("A");
748
1
  batch2.SetSavePoint();
749
750
1
  s = batch2.RollbackToSavePoint();
751
1
  ASSERT_OK(s);
752
1
  ASSERT_EQ("Delete(A)@0", PrintContents(&batch2));
753
754
1
  batch2.Clear();
755
1
  ASSERT_EQ("", PrintContents(&batch2));
756
757
1
  batch2.SetSavePoint();
758
759
1
  batch2.Delete("B");
760
1
  ASSERT_EQ("Delete(B)@0", PrintContents(&batch2));
761
762
1
  batch2.SetSavePoint();
763
1
  s = batch2.RollbackToSavePoint();
764
1
  ASSERT_OK(s);
765
1
  ASSERT_EQ("Delete(B)@0", PrintContents(&batch2));
766
767
1
  s = batch2.RollbackToSavePoint();
768
1
  ASSERT_OK(s);
769
1
  ASSERT_EQ("", PrintContents(&batch2));
770
771
1
  s = batch2.RollbackToSavePoint();
772
1
  ASSERT_TRUE(s.IsNotFound());
773
1
  ASSERT_EQ("", PrintContents(&batch2));
774
1
}
775
776
}  // namespace rocksdb
777
778
13.2k
int main(int argc, char** argv) {
779
13.2k
  ::testing::InitGoogleTest(&argc, argv);
780
13.2k
  return RUN_ALL_TESTS();
781
13.2k
}