Coverage Report

Created: 2026-08-14 08:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/rocksdb/utilities/secondary_index/secondary_index_mixin.h
Line
Count
Source
1
//  Copyright (c) Meta Platforms, Inc. and affiliates.
2
//
3
//  This source code is licensed under both the GPLv2 (found in the
4
//  COPYING file in the root directory) and Apache 2.0 License
5
//  (found in the LICENSE.Apache file in the root directory).
6
7
#pragma once
8
9
#include <cassert>
10
#include <memory>
11
#include <optional>
12
#include <string>
13
#include <vector>
14
15
#include "db/wide/wide_columns_helper.h"
16
#include "rocksdb/options.h"
17
#include "rocksdb/utilities/secondary_index.h"
18
#include "rocksdb/wide_columns.h"
19
#include "util/autovector.h"
20
#include "utilities/secondary_index/secondary_index_helper.h"
21
22
namespace ROCKSDB_NAMESPACE {
23
24
template <typename Txn>
25
class SecondaryIndexMixin : public Txn {
26
 public:
27
  template <typename... Args>
28
  explicit SecondaryIndexMixin(
29
      const std::vector<std::shared_ptr<SecondaryIndex>>* secondary_indices,
30
      Args&&... args)
31
0
      : Txn(std::forward<Args>(args)...),
32
0
        secondary_indices_(secondary_indices) {
33
0
    assert(secondary_indices_);
34
0
    assert(!secondary_indices_->empty());
35
0
  }
36
37
  using Txn::Put;
38
  Status Put(ColumnFamilyHandle* column_family, const Slice& key,
39
0
             const Slice& value, const bool assume_tracked = false) override {
40
0
    return PerformWithSavePoint([&]() {
41
0
      const bool do_validate = !assume_tracked;
42
0
      return PutWithSecondaryIndices(column_family, key, value, do_validate);
43
0
    });
44
0
  }
45
  Status Put(ColumnFamilyHandle* column_family, const SliceParts& key,
46
             const SliceParts& value,
47
0
             const bool assume_tracked = false) override {
48
0
    std::string key_str;
49
0
    const Slice key_slice(key, &key_str);
50
51
0
    std::string value_str;
52
0
    const Slice value_slice(value, &value_str);
53
54
0
    return Put(column_family, key_slice, value_slice, assume_tracked);
55
0
  }
56
57
  Status PutEntity(ColumnFamilyHandle* column_family, const Slice& key,
58
                   const WideColumns& columns,
59
0
                   bool assume_tracked = false) override {
60
0
    return PerformWithSavePoint([&]() {
61
0
      const bool do_validate = !assume_tracked;
62
0
      return PutEntityWithSecondaryIndices(column_family, key, columns,
63
0
                                           do_validate);
64
0
    });
65
0
  }
66
67
  using Txn::Merge;
68
  Status Merge(ColumnFamilyHandle* /* column_family */, const Slice& /* key */,
69
               const Slice& /* value */,
70
0
               const bool /* assume_tracked */ = false) override {
71
0
    return Status::NotSupported(
72
0
        "Merge with secondary indices not yet supported");
73
0
  }
74
75
  using Txn::Delete;
76
  Status Delete(ColumnFamilyHandle* column_family, const Slice& key,
77
0
                const bool assume_tracked = false) override {
78
0
    return PerformWithSavePoint([&]() {
79
0
      const bool do_validate = !assume_tracked;
80
0
      return DeleteWithSecondaryIndices(column_family, key, do_validate);
81
0
    });
82
0
  }
83
  Status Delete(ColumnFamilyHandle* column_family, const SliceParts& key,
84
0
                const bool assume_tracked = false) override {
85
0
    std::string key_str;
86
0
    const Slice key_slice(key, &key_str);
87
88
0
    return Delete(column_family, key_slice, assume_tracked);
89
0
  }
90
91
  using Txn::SingleDelete;
92
  Status SingleDelete(ColumnFamilyHandle* column_family, const Slice& key,
93
0
                      const bool assume_tracked = false) override {
94
0
    return PerformWithSavePoint([&]() {
95
0
      const bool do_validate = !assume_tracked;
96
0
      return SingleDeleteWithSecondaryIndices(column_family, key, do_validate);
97
0
    });
98
0
  }
99
  Status SingleDelete(ColumnFamilyHandle* column_family, const SliceParts& key,
100
0
                      const bool assume_tracked = false) override {
101
0
    std::string key_str;
102
0
    const Slice key_slice(key, &key_str);
103
104
0
    return SingleDelete(column_family, key_slice, assume_tracked);
105
0
  }
106
107
  using Txn::PutUntracked;
108
  Status PutUntracked(ColumnFamilyHandle* column_family, const Slice& key,
109
0
                      const Slice& value) override {
110
0
    return PerformWithSavePoint([&]() {
111
0
      constexpr bool do_validate = false;
112
0
      return PutWithSecondaryIndices(column_family, key, value, do_validate);
113
0
    });
114
0
  }
115
  Status PutUntracked(ColumnFamilyHandle* column_family, const SliceParts& key,
116
0
                      const SliceParts& value) override {
117
0
    std::string key_str;
118
0
    const Slice key_slice(key, &key_str);
119
120
0
    std::string value_str;
121
0
    const Slice value_slice(value, &value_str);
122
123
0
    return PutUntracked(column_family, key_slice, value_slice);
124
0
  }
125
126
  Status PutEntityUntracked(ColumnFamilyHandle* column_family, const Slice& key,
127
0
                            const WideColumns& columns) override {
128
0
    return PerformWithSavePoint([&]() {
129
0
      constexpr bool do_validate = false;
130
0
      return PutEntityWithSecondaryIndices(column_family, key, columns,
131
0
                                           do_validate);
132
0
    });
133
0
  }
134
135
  using Txn::MergeUntracked;
136
  Status MergeUntracked(ColumnFamilyHandle* /* column_family */,
137
                        const Slice& /* key */,
138
0
                        const Slice& /* value */) override {
139
0
    return Status::NotSupported(
140
0
        "MergeUntracked with secondary indices not yet supported");
141
0
  }
142
143
  using Txn::DeleteUntracked;
144
  Status DeleteUntracked(ColumnFamilyHandle* column_family,
145
0
                         const Slice& key) override {
146
0
    return PerformWithSavePoint([&]() {
147
0
      constexpr bool do_validate = false;
148
0
      return DeleteWithSecondaryIndices(column_family, key, do_validate);
149
0
    });
150
0
  }
151
  Status DeleteUntracked(ColumnFamilyHandle* column_family,
152
0
                         const SliceParts& key) override {
153
0
    std::string key_str;
154
0
    const Slice key_slice(key, &key_str);
155
156
0
    return DeleteUntracked(column_family, key_slice);
157
0
  }
158
159
  using Txn::SingleDeleteUntracked;
160
  Status SingleDeleteUntracked(ColumnFamilyHandle* column_family,
161
0
                               const Slice& key) override {
162
0
    return PerformWithSavePoint([&]() {
163
0
      constexpr bool do_validate = false;
164
0
      return SingleDeleteWithSecondaryIndices(column_family, key, do_validate);
165
0
    });
166
0
  }
167
168
 private:
169
  class IndexData {
170
   public:
171
    IndexData(const SecondaryIndex* index, const Slice& previous_column_value)
172
0
        : index_(index), previous_column_value_(previous_column_value) {
173
0
      assert(index_);
174
0
    }
175
176
0
    const SecondaryIndex* index() const { return index_; }
177
0
    const Slice& previous_column_value() const {
178
0
      return previous_column_value_;
179
0
    }
180
0
    std::optional<std::variant<Slice, std::string>>& updated_column_value() {
181
0
      return updated_column_value_;
182
0
    }
183
0
    Slice primary_column_value() const {
184
0
      return updated_column_value_.has_value()
185
0
                 ? SecondaryIndexHelper::AsSlice(*updated_column_value_)
186
0
                 : previous_column_value_;
187
0
    }
188
189
   private:
190
    const SecondaryIndex* index_;
191
    Slice previous_column_value_;
192
    std::optional<std::variant<Slice, std::string>> updated_column_value_;
193
  };
194
195
  template <typename Operation>
196
0
  Status PerformWithSavePoint(Operation&& operation) {
197
0
    Txn::SetSavePoint();
198
199
0
    const Status s = operation();
200
201
0
    if (!s.ok()) {
202
0
      [[maybe_unused]] const Status st = Txn::RollbackToSavePoint();
203
0
      assert(st.ok());
204
205
0
      return s;
206
0
    }
207
208
0
    [[maybe_unused]] const Status st = Txn::PopSavePoint();
209
0
    assert(st.ok());
210
211
0
    return Status::OK();
212
0
  }
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PerformWithSavePoint<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::Put(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, rocksdb::Slice const&, bool)::{lambda()#1}>(rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::Put(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, rocksdb::Slice const&, bool)::{lambda()#1}&&)
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PerformWithSavePoint<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PutEntity(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, std::__1::vector<rocksdb::WideColumn, std::__1::allocator<rocksdb::WideColumn> > const&, bool)::{lambda()#1}>(rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PutEntity(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, std::__1::vector<rocksdb::WideColumn, std::__1::allocator<rocksdb::WideColumn> > const&, bool)::{lambda()#1}&&)
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PerformWithSavePoint<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::Delete(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool)::{lambda()#1}>(rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::Delete(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool)::{lambda()#1}&&)
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PerformWithSavePoint<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::SingleDelete(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool)::{lambda()#1}>(rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::SingleDelete(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool)::{lambda()#1}&&)
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PerformWithSavePoint<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PutUntracked(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, rocksdb::Slice const&)::{lambda()#1}>(rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PutUntracked(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, rocksdb::Slice const&)::{lambda()#1}&&)
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PerformWithSavePoint<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PutEntityUntracked(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, std::__1::vector<rocksdb::WideColumn, std::__1::allocator<rocksdb::WideColumn> > const&)::{lambda()#1}>(rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PutEntityUntracked(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, std::__1::vector<rocksdb::WideColumn, std::__1::allocator<rocksdb::WideColumn> > const&)::{lambda()#1}&&)
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PerformWithSavePoint<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::DeleteUntracked(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&)::{lambda()#1}>(rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::DeleteUntracked(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&)::{lambda()#1}&&)
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PerformWithSavePoint<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::SingleDeleteUntracked(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&)::{lambda()#1}>(rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::SingleDeleteUntracked(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&)::{lambda()#1}&&)
213
214
  Status GetPrimaryEntryForUpdate(ColumnFamilyHandle* column_family,
215
                                  const Slice& primary_key,
216
                                  PinnableWideColumns* existing_primary_columns,
217
0
                                  bool do_validate) {
218
0
    assert(column_family);
219
0
    assert(existing_primary_columns);
220
221
0
    constexpr bool exclusive = true;
222
223
0
    return Txn::GetEntityForUpdate(ReadOptions(), column_family, primary_key,
224
0
                                   existing_primary_columns, exclusive,
225
0
                                   do_validate);
226
0
  }
227
228
  Status RemoveSecondaryEntry(const SecondaryIndex* secondary_index,
229
                              const Slice& primary_key,
230
0
                              const Slice& existing_primary_column_value) {
231
0
    assert(secondary_index);
232
233
0
    std::variant<Slice, std::string> secondary_key_prefix;
234
235
0
    {
236
0
      const Status s = secondary_index->GetSecondaryKeyPrefix(
237
0
          primary_key, existing_primary_column_value, &secondary_key_prefix);
238
0
      if (!s.ok()) {
239
0
        return s;
240
0
      }
241
0
    }
242
243
0
    {
244
0
      const Status s =
245
0
          secondary_index->FinalizeSecondaryKeyPrefix(&secondary_key_prefix);
246
0
      if (!s.ok()) {
247
0
        return s;
248
0
      }
249
0
    }
250
251
0
    const std::string secondary_key =
252
0
        SecondaryIndexHelper::AsString(secondary_key_prefix) +
253
0
        primary_key.ToString();
254
255
0
    return Txn::SingleDelete(secondary_index->GetSecondaryColumnFamily(),
256
0
                             secondary_key);
257
0
  }
258
259
  Status AddPrimaryEntry(ColumnFamilyHandle* column_family,
260
0
                         const Slice& primary_key, const Slice& primary_value) {
261
0
    assert(column_family);
262
263
0
    constexpr bool assume_tracked = true;
264
265
0
    return Txn::Put(column_family, primary_key, primary_value, assume_tracked);
266
0
  }
267
268
  Status AddPrimaryEntry(ColumnFamilyHandle* column_family,
269
                         const Slice& primary_key,
270
0
                         const WideColumns& primary_columns) {
271
0
    assert(column_family);
272
273
0
    constexpr bool assume_tracked = true;
274
275
0
    return Txn::PutEntity(column_family, primary_key, primary_columns,
276
0
                          assume_tracked);
277
0
  }
278
279
  Status AddSecondaryEntry(const SecondaryIndex* secondary_index,
280
                           const Slice& primary_key,
281
                           const Slice& primary_column_value,
282
0
                           const Slice& previous_column_value) {
283
0
    assert(secondary_index);
284
285
0
    std::variant<Slice, std::string> secondary_key_prefix;
286
287
0
    {
288
0
      const Status s = secondary_index->GetSecondaryKeyPrefix(
289
0
          primary_key, primary_column_value, &secondary_key_prefix);
290
0
      if (!s.ok()) {
291
0
        return s;
292
0
      }
293
0
    }
294
295
0
    {
296
0
      const Status s =
297
0
          secondary_index->FinalizeSecondaryKeyPrefix(&secondary_key_prefix);
298
0
      if (!s.ok()) {
299
0
        return s;
300
0
      }
301
0
    }
302
303
0
    std::optional<std::variant<Slice, std::string>> secondary_value;
304
305
0
    {
306
0
      const Status s = secondary_index->GetSecondaryValue(
307
0
          primary_key, primary_column_value, previous_column_value,
308
0
          &secondary_value);
309
0
      if (!s.ok()) {
310
0
        return s;
311
0
      }
312
0
    }
313
314
0
    {
315
0
      const std::string secondary_key =
316
0
          SecondaryIndexHelper::AsString(secondary_key_prefix) +
317
0
          primary_key.ToString();
318
319
0
      const Status s =
320
0
          Txn::Put(secondary_index->GetSecondaryColumnFamily(), secondary_key,
321
0
                   secondary_value.has_value()
322
0
                       ? SecondaryIndexHelper::AsSlice(*secondary_value)
323
0
                       : Slice());
324
0
      if (!s.ok()) {
325
0
        return s;
326
0
      }
327
0
    }
328
329
0
    return Status::OK();
330
0
  }
331
332
  Status RemoveSecondaryEntries(ColumnFamilyHandle* column_family,
333
                                const Slice& primary_key,
334
0
                                const WideColumns& existing_columns) {
335
0
    assert(column_family);
336
337
0
    for (const auto& secondary_index : *secondary_indices_) {
338
0
      assert(secondary_index);
339
340
0
      if (secondary_index->GetPrimaryColumnFamily() != column_family) {
341
0
        continue;
342
0
      }
343
344
0
      const auto it = WideColumnsHelper::Find(
345
0
          existing_columns.cbegin(), existing_columns.cend(),
346
0
          secondary_index->GetPrimaryColumnName());
347
0
      if (it == existing_columns.cend()) {
348
0
        continue;
349
0
      }
350
351
0
      const Status st =
352
0
          RemoveSecondaryEntry(secondary_index.get(), primary_key, it->value());
353
0
      if (!st.ok()) {
354
0
        return st;
355
0
      }
356
0
    }
357
358
0
    return Status::OK();
359
0
  }
360
361
  Status UpdatePrimaryColumnValues(ColumnFamilyHandle* column_family,
362
                                   const Slice& primary_key,
363
                                   Slice& primary_value,
364
0
                                   autovector<IndexData>& applicable_indices) {
365
0
    assert(column_family);
366
0
    assert(applicable_indices.empty());
367
368
0
    applicable_indices.reserve(secondary_indices_->size());
369
370
0
    for (const auto& secondary_index : *secondary_indices_) {
371
0
      assert(secondary_index);
372
373
0
      if (secondary_index->GetPrimaryColumnFamily() != column_family) {
374
0
        continue;
375
0
      }
376
377
0
      if (secondary_index->GetPrimaryColumnName() != kDefaultWideColumnName) {
378
0
        continue;
379
0
      }
380
381
0
      applicable_indices.emplace_back(
382
0
          IndexData(secondary_index.get(), primary_value));
383
384
0
      auto& index_data = applicable_indices.back();
385
386
0
      const Status s = secondary_index->UpdatePrimaryColumnValue(
387
0
          primary_key, index_data.previous_column_value(),
388
0
          &index_data.updated_column_value());
389
0
      if (!s.ok()) {
390
0
        return s;
391
0
      }
392
393
0
      primary_value = index_data.primary_column_value();
394
0
    }
395
396
0
    return Status::OK();
397
0
  }
398
399
  Status UpdatePrimaryColumnValues(ColumnFamilyHandle* column_family,
400
                                   const Slice& primary_key,
401
                                   WideColumns& primary_columns,
402
0
                                   autovector<IndexData>& applicable_indices) {
403
0
    assert(column_family);
404
0
    assert(applicable_indices.empty());
405
406
    // TODO: as an optimization, we can avoid calling SortColumns a second time
407
    // in WriteBatchInternal::PutEntity
408
0
    WideColumnsHelper::SortColumns(primary_columns);
409
410
0
    applicable_indices.reserve(secondary_indices_->size());
411
412
0
    for (const auto& secondary_index : *secondary_indices_) {
413
0
      assert(secondary_index);
414
415
0
      if (secondary_index->GetPrimaryColumnFamily() != column_family) {
416
0
        continue;
417
0
      }
418
419
0
      const auto it = WideColumnsHelper::Find(
420
0
          primary_columns.begin(), primary_columns.end(),
421
0
          secondary_index->GetPrimaryColumnName());
422
0
      if (it == primary_columns.end()) {
423
0
        continue;
424
0
      }
425
426
0
      applicable_indices.emplace_back(
427
0
          IndexData(secondary_index.get(), it->value()));
428
429
0
      auto& index_data = applicable_indices.back();
430
431
0
      const Status s = secondary_index->UpdatePrimaryColumnValue(
432
0
          primary_key, index_data.previous_column_value(),
433
0
          &index_data.updated_column_value());
434
0
      if (!s.ok()) {
435
0
        return s;
436
0
      }
437
438
0
      it->value() = index_data.primary_column_value();
439
0
    }
440
441
0
    return Status::OK();
442
0
  }
443
444
  Status AddSecondaryEntries(const Slice& primary_key,
445
0
                             const autovector<IndexData>& applicable_indices) {
446
0
    for (const auto& index_data : applicable_indices) {
447
0
      const Status s = AddSecondaryEntry(index_data.index(), primary_key,
448
0
                                         index_data.primary_column_value(),
449
0
                                         index_data.previous_column_value());
450
0
      if (!s.ok()) {
451
0
        return s;
452
0
      }
453
0
    }
454
455
0
    return Status::OK();
456
0
  }
457
458
  template <typename Value>
459
  Status PutWithSecondaryIndicesImpl(ColumnFamilyHandle* column_family,
460
                                     const Slice& key,
461
                                     const Value& value_or_columns,
462
0
                                     bool do_validate) {
463
    // TODO: we could avoid removing and recreating secondary entries for
464
    // which neither the secondary key prefix nor the value has changed
465
466
0
    if (!column_family) {
467
0
      column_family = Txn::DefaultColumnFamily();
468
0
    }
469
470
0
    const Slice& primary_key = key;
471
472
0
    {
473
0
      PinnableWideColumns existing_primary_columns;
474
475
0
      const Status s = GetPrimaryEntryForUpdate(
476
0
          column_family, primary_key, &existing_primary_columns, do_validate);
477
0
      if (!s.ok()) {
478
0
        if (!s.IsNotFound()) {
479
0
          return s;
480
0
        }
481
0
      } else {
482
0
        const Status st = RemoveSecondaryEntries(
483
0
            column_family, primary_key, existing_primary_columns.columns());
484
0
        if (!st.ok()) {
485
0
          return st;
486
0
        }
487
0
      }
488
0
    }
489
490
0
    auto primary_value_or_columns = value_or_columns;
491
0
    autovector<IndexData> applicable_indices;
492
493
0
    {
494
0
      const Status s = UpdatePrimaryColumnValues(column_family, primary_key,
495
0
                                                 primary_value_or_columns,
496
0
                                                 applicable_indices);
497
0
      if (!s.ok()) {
498
0
        return s;
499
0
      }
500
0
    }
501
502
0
    {
503
0
      const Status s =
504
0
          AddPrimaryEntry(column_family, primary_key, primary_value_or_columns);
505
0
      if (!s.ok()) {
506
0
        return s;
507
0
      }
508
0
    }
509
510
0
    {
511
0
      const Status s = AddSecondaryEntries(primary_key, applicable_indices);
512
0
      if (!s.ok()) {
513
0
        return s;
514
0
      }
515
0
    }
516
517
0
    return Status::OK();
518
0
  }
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PutWithSecondaryIndicesImpl<rocksdb::Slice>(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, rocksdb::Slice const&, bool)
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::PutWithSecondaryIndicesImpl<std::__1::vector<rocksdb::WideColumn, std::__1::allocator<rocksdb::WideColumn> > >(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, std::__1::vector<rocksdb::WideColumn, std::__1::allocator<rocksdb::WideColumn> > const&, bool)
519
520
  Status PutWithSecondaryIndices(ColumnFamilyHandle* column_family,
521
                                 const Slice& key, const Slice& value,
522
0
                                 bool do_validate) {
523
0
    return PutWithSecondaryIndicesImpl(column_family, key, value, do_validate);
524
0
  }
525
526
  Status PutEntityWithSecondaryIndices(ColumnFamilyHandle* column_family,
527
                                       const Slice& key,
528
                                       const WideColumns& columns,
529
0
                                       bool do_validate) {
530
0
    return PutWithSecondaryIndicesImpl(column_family, key, columns,
531
0
                                       do_validate);
532
0
  }
533
534
  template <typename Operation>
535
  Status DeleteWithSecondaryIndicesImpl(ColumnFamilyHandle* column_family,
536
                                        const Slice& key, bool do_validate,
537
0
                                        Operation&& operation) {
538
0
    if (!column_family) {
539
0
      column_family = Txn::DefaultColumnFamily();
540
0
    }
541
542
0
    {
543
0
      PinnableWideColumns existing_primary_columns;
544
545
0
      const Status s = GetPrimaryEntryForUpdate(
546
0
          column_family, key, &existing_primary_columns, do_validate);
547
0
      if (!s.ok()) {
548
0
        if (!s.IsNotFound()) {
549
0
          return s;
550
0
        }
551
552
0
        return Status::OK();
553
0
      } else {
554
0
        const Status st = RemoveSecondaryEntries(
555
0
            column_family, key, existing_primary_columns.columns());
556
0
        if (!st.ok()) {
557
0
          return st;
558
0
        }
559
0
      }
560
0
    }
561
562
0
    {
563
0
      const Status s = operation(column_family, key);
564
0
      if (!s.ok()) {
565
0
        return s;
566
0
      }
567
0
    }
568
569
0
    return Status::OK();
570
0
  }
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::DeleteWithSecondaryIndicesImpl<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::DeleteWithSecondaryIndices(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool)::{lambda(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&)#1}>(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool, rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::DeleteWithSecondaryIndices(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool)::{lambda(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&)#1}&&)
Unexecuted instantiation: rocksdb::Status rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::DeleteWithSecondaryIndicesImpl<rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::SingleDeleteWithSecondaryIndices(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool)::{lambda(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&)#1}>(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool, rocksdb::SecondaryIndexMixin<rocksdb::WriteCommittedTxn>::SingleDeleteWithSecondaryIndices(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&, bool)::{lambda(rocksdb::ColumnFamilyHandle*, rocksdb::Slice const&)#1}&&)
571
572
  Status DeleteWithSecondaryIndices(ColumnFamilyHandle* column_family,
573
0
                                    const Slice& key, bool do_validate) {
574
0
    return DeleteWithSecondaryIndicesImpl(
575
0
        column_family, key, do_validate,
576
0
        [&](ColumnFamilyHandle* cfh, const Slice& primary_key) {
577
0
          assert(cfh);
578
579
0
          constexpr bool assume_tracked = true;
580
581
0
          return Txn::Delete(cfh, primary_key, assume_tracked);
582
0
        });
583
0
  }
584
585
  Status SingleDeleteWithSecondaryIndices(ColumnFamilyHandle* column_family,
586
0
                                          const Slice& key, bool do_validate) {
587
0
    return DeleteWithSecondaryIndicesImpl(
588
0
        column_family, key, do_validate,
589
0
        [&](ColumnFamilyHandle* cfh, const Slice& primary_key) {
590
0
          assert(cfh);
591
592
0
          constexpr bool assume_tracked = true;
593
594
0
          return Txn::SingleDelete(cfh, primary_key, assume_tracked);
595
0
        });
596
0
  }
597
598
  const std::vector<std::shared_ptr<SecondaryIndex>>* secondary_indices_;
599
};
600
601
}  // namespace ROCKSDB_NAMESPACE