aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firestore/core/src/firebase/firestore/local/leveldb_transaction.h
blob: a6ddce2d5d9082a30bd7063be99a6db5ffd7c396 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
/*
 * Copyright 2018 Google
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_TRANSACTION_H_
#define FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_TRANSACTION_H_

#include <cstdint>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <utility>

#include "absl/strings/string_view.h"
#include "leveldb/db.h"

#if __OBJC__
#import <Protobuf/GPBProtocolBuffers.h>
#endif

namespace firebase {
namespace firestore {
namespace local {

/**
 * LevelDBTransaction tracks pending changes to entries in leveldb, including
 * deletions. It also provides an Iterator to traverse a merged view of pending
 * changes and committed values.
 */
class LevelDbTransaction {
  using Deletions = std::set<std::string>;
  using Mutations = std::map<std::string, std::string>;

 public:
  /**
   * Iterator iterates over a merged view of pending changes from the
   * transaction and any unchanged values in the underlying leveldb instance.
   */
  class Iterator {
   public:
    explicit Iterator(LevelDbTransaction* txn);

    /**
     * Returns true if this iterator points to an entry
     */
    bool Valid();

    /**
     * Seeks this iterator to the first key equal to or greater than the given
     * key
     */
    void Seek(const std::string& key);

    /**
     * Advances the iterator to the next entry
     */
    void Next();

    /**
     * Returns the key of the current entry
     */
    absl::string_view key();

    /**
     * Returns the value of the current entry
     */
    absl::string_view value();

   private:
    /**
     * Advances to the next non-deleted key in leveldb.
     */
    void AdvanceLDB();

    /**
     * Returns true if the given slice matches a key present in the deletions_
     * set.
     */
    bool IsDeleted(leveldb::Slice slice);

    /**
     * Syncs with the underlying transaction. If the transaction has been
     * updated, the mutation iterator may need to be reset. Returns true if this
     * resulted in moving to a new underlying entry (i.e. the entry represented
     * by current_ was deleted).
     */
    bool SyncToTransaction();

    /**
     * Given the current state of the internal iterators, set is_valid_,
     * is_mutation_, and current_.
     */
    void UpdateCurrent();

    std::unique_ptr<leveldb::Iterator> db_iter_;

    // The last observed version of the underlying transaction
    int32_t last_version_;
    // The underlying transaction.
    LevelDbTransaction* txn_;
    Mutations::iterator mutations_iter_;
    // We save the current key and value so that once an iterator is Valid(), it
    // remains so at least until the next call to Seek() or Next(), even if the
    // underlying data is deleted.
    std::pair<std::string, std::string> current_;
    // True if current_ represents an entry in the mutations_ map, rather than
    // committed data.
    bool is_mutation_;
    // True if the iterator pointed to a valid entry the last time Next() or
    // Seek() was called.
    bool is_valid_;
  };

  explicit LevelDbTransaction(
      leveldb::DB* db,
      absl::string_view label,
      const leveldb::ReadOptions& read_options = DefaultReadOptions(),
      const leveldb::WriteOptions& write_options = DefaultWriteOptions());

  LevelDbTransaction(const LevelDbTransaction& other) = delete;

  LevelDbTransaction& operator=(const LevelDbTransaction& other) = delete;

  /**
   * Returns a default set of ReadOptions
   */
  static const leveldb::ReadOptions& DefaultReadOptions();

  /**
   * Returns a default set of WriteOptions
   */
  static const leveldb::WriteOptions& DefaultWriteOptions();

  /**
   * Remove the database entry (if any) for "key".  It is not an error if "key"
   * did not exist in the database.
   */
  void Delete(const absl::string_view& key);

#if __OBJC__
  /**
   * Schedules the row identified by `key` to be set to the given protocol
   * buffer message when this transaction commits.
   */
  void Put(const absl::string_view& key, GPBMessage* message) {
    NSData* data = [message data];
    std::string key_string(key);
    mutations_[key_string] = std::string((const char*)data.bytes, data.length);
    version_++;
  }
#endif

  /**
   * Schedules the row identified by `key` to be set to `value` when this
   * transaction commits.
   */
  void Put(const absl::string_view& key, const absl::string_view& value);

  /**
   * Sets the contents of `value` to the latest known value for the given key,
   * including any pending mutations and `Status::OK` is returned. If the key
   * doesn't exist in leveldb, or it is scheduled for deletion in this
   * transaction, `Status::NotFound` is returned.
   */
  leveldb::Status Get(const absl::string_view& key, std::string* value);

  /**
   * Returns a new Iterator over the pending changes in this transaction, merged
   * with the existing values already in leveldb.
   */
  std::unique_ptr<Iterator> NewIterator();

  /**
   * Commits the transaction. All pending changes are written. The transaction
   * should not be used after calling this method.
   */
  void Commit();

  std::string ToString();

 private:
  leveldb::DB* db_;
  Mutations mutations_;
  Deletions deletions_;
  leveldb::ReadOptions read_options_;
  leveldb::WriteOptions write_options_;
  int32_t version_;
  std::string label_;
};

}  // namespace local
}  // namespace firestore
}  // namespace firebase

#endif  // FIRESTORE_CORE_SRC_FIREBASE_FIRESTORE_LOCAL_LEVELDB_TRANSACTION_H_