db_ttl_impl.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved.
  2. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  3. // Use of this source code is governed by a BSD-style license that can be
  4. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  5. #pragma once
  6. #ifndef ROCKSDB_LITE
  7. #include <deque>
  8. #include <string>
  9. #include <vector>
  10. #include "db/db_impl/db_impl.h"
  11. #include "rocksdb/compaction_filter.h"
  12. #include "rocksdb/db.h"
  13. #include "rocksdb/env.h"
  14. #include "rocksdb/merge_operator.h"
  15. #include "rocksdb/utilities/db_ttl.h"
  16. #include "rocksdb/utilities/utility_db.h"
  17. #ifdef _WIN32
  18. // Windows API macro interference
  19. #undef GetCurrentTime
  20. #endif
  21. namespace ROCKSDB_NAMESPACE {
  22. class DBWithTTLImpl : public DBWithTTL {
  23. public:
  24. static void SanitizeOptions(int32_t ttl, ColumnFamilyOptions* options,
  25. Env* env);
  26. explicit DBWithTTLImpl(DB* db);
  27. virtual ~DBWithTTLImpl();
  28. virtual Status Close() override;
  29. Status CreateColumnFamilyWithTtl(const ColumnFamilyOptions& options,
  30. const std::string& column_family_name,
  31. ColumnFamilyHandle** handle,
  32. int ttl) override;
  33. Status CreateColumnFamily(const ColumnFamilyOptions& options,
  34. const std::string& column_family_name,
  35. ColumnFamilyHandle** handle) override;
  36. using StackableDB::Put;
  37. virtual Status Put(const WriteOptions& options,
  38. ColumnFamilyHandle* column_family, const Slice& key,
  39. const Slice& val) override;
  40. using StackableDB::Get;
  41. virtual Status Get(const ReadOptions& options,
  42. ColumnFamilyHandle* column_family, const Slice& key,
  43. PinnableSlice* value) override;
  44. using StackableDB::MultiGet;
  45. virtual std::vector<Status> MultiGet(
  46. const ReadOptions& options,
  47. const std::vector<ColumnFamilyHandle*>& column_family,
  48. const std::vector<Slice>& keys,
  49. std::vector<std::string>* values) override;
  50. using StackableDB::KeyMayExist;
  51. virtual bool KeyMayExist(const ReadOptions& options,
  52. ColumnFamilyHandle* column_family, const Slice& key,
  53. std::string* value,
  54. bool* value_found = nullptr) override;
  55. using StackableDB::Merge;
  56. virtual Status Merge(const WriteOptions& options,
  57. ColumnFamilyHandle* column_family, const Slice& key,
  58. const Slice& value) override;
  59. virtual Status Write(const WriteOptions& opts, WriteBatch* updates) override;
  60. using StackableDB::NewIterator;
  61. virtual Iterator* NewIterator(const ReadOptions& opts,
  62. ColumnFamilyHandle* column_family) override;
  63. virtual DB* GetBaseDB() override { return db_; }
  64. static bool IsStale(const Slice& value, int32_t ttl, Env* env);
  65. static Status AppendTS(const Slice& val, std::string* val_with_ts, Env* env);
  66. static Status SanityCheckTimestamp(const Slice& str);
  67. static Status StripTS(std::string* str);
  68. static Status StripTS(PinnableSlice* str);
  69. static const uint32_t kTSLength = sizeof(int32_t); // size of timestamp
  70. static const int32_t kMinTimestamp = 1368146402; // 05/09/2013:5:40PM GMT-8
  71. static const int32_t kMaxTimestamp = 2147483647; // 01/18/2038:7:14PM GMT-8
  72. void SetTtl(int32_t ttl) override { SetTtl(DefaultColumnFamily(), ttl); }
  73. void SetTtl(ColumnFamilyHandle *h, int32_t ttl) override;
  74. private:
  75. // remember whether the Close completes or not
  76. bool closed_;
  77. };
  78. class TtlIterator : public Iterator {
  79. public:
  80. explicit TtlIterator(Iterator* iter) : iter_(iter) { assert(iter_); }
  81. ~TtlIterator() { delete iter_; }
  82. bool Valid() const override { return iter_->Valid(); }
  83. void SeekToFirst() override { iter_->SeekToFirst(); }
  84. void SeekToLast() override { iter_->SeekToLast(); }
  85. void Seek(const Slice& target) override { iter_->Seek(target); }
  86. void SeekForPrev(const Slice& target) override { iter_->SeekForPrev(target); }
  87. void Next() override { iter_->Next(); }
  88. void Prev() override { iter_->Prev(); }
  89. Slice key() const override { return iter_->key(); }
  90. int32_t timestamp() const {
  91. return DecodeFixed32(iter_->value().data() + iter_->value().size() -
  92. DBWithTTLImpl::kTSLength);
  93. }
  94. Slice value() const override {
  95. // TODO: handle timestamp corruption like in general iterator semantics
  96. assert(DBWithTTLImpl::SanityCheckTimestamp(iter_->value()).ok());
  97. Slice trimmed_value = iter_->value();
  98. trimmed_value.size_ -= DBWithTTLImpl::kTSLength;
  99. return trimmed_value;
  100. }
  101. Status status() const override { return iter_->status(); }
  102. private:
  103. Iterator* iter_;
  104. };
  105. class TtlCompactionFilter : public CompactionFilter {
  106. public:
  107. TtlCompactionFilter(
  108. int32_t ttl, Env* env, const CompactionFilter* user_comp_filter,
  109. std::unique_ptr<const CompactionFilter> user_comp_filter_from_factory =
  110. nullptr)
  111. : ttl_(ttl),
  112. env_(env),
  113. user_comp_filter_(user_comp_filter),
  114. user_comp_filter_from_factory_(
  115. std::move(user_comp_filter_from_factory)) {
  116. // Unlike the merge operator, compaction filter is necessary for TTL, hence
  117. // this would be called even if user doesn't specify any compaction-filter
  118. if (!user_comp_filter_) {
  119. user_comp_filter_ = user_comp_filter_from_factory_.get();
  120. }
  121. }
  122. virtual bool Filter(int level, const Slice& key, const Slice& old_val,
  123. std::string* new_val, bool* value_changed) const
  124. override {
  125. if (DBWithTTLImpl::IsStale(old_val, ttl_, env_)) {
  126. return true;
  127. }
  128. if (user_comp_filter_ == nullptr) {
  129. return false;
  130. }
  131. assert(old_val.size() >= DBWithTTLImpl::kTSLength);
  132. Slice old_val_without_ts(old_val.data(),
  133. old_val.size() - DBWithTTLImpl::kTSLength);
  134. if (user_comp_filter_->Filter(level, key, old_val_without_ts, new_val,
  135. value_changed)) {
  136. return true;
  137. }
  138. if (*value_changed) {
  139. new_val->append(
  140. old_val.data() + old_val.size() - DBWithTTLImpl::kTSLength,
  141. DBWithTTLImpl::kTSLength);
  142. }
  143. return false;
  144. }
  145. virtual const char* Name() const override { return "Delete By TTL"; }
  146. private:
  147. int32_t ttl_;
  148. Env* env_;
  149. const CompactionFilter* user_comp_filter_;
  150. std::unique_ptr<const CompactionFilter> user_comp_filter_from_factory_;
  151. };
  152. class TtlCompactionFilterFactory : public CompactionFilterFactory {
  153. public:
  154. TtlCompactionFilterFactory(
  155. int32_t ttl, Env* env,
  156. std::shared_ptr<CompactionFilterFactory> comp_filter_factory)
  157. : ttl_(ttl), env_(env), user_comp_filter_factory_(comp_filter_factory) {}
  158. virtual std::unique_ptr<CompactionFilter> CreateCompactionFilter(
  159. const CompactionFilter::Context& context) override {
  160. std::unique_ptr<const CompactionFilter> user_comp_filter_from_factory =
  161. nullptr;
  162. if (user_comp_filter_factory_) {
  163. user_comp_filter_from_factory =
  164. user_comp_filter_factory_->CreateCompactionFilter(context);
  165. }
  166. return std::unique_ptr<TtlCompactionFilter>(new TtlCompactionFilter(
  167. ttl_, env_, nullptr, std::move(user_comp_filter_from_factory)));
  168. }
  169. void SetTtl(int32_t ttl) {
  170. ttl_ = ttl;
  171. }
  172. virtual const char* Name() const override {
  173. return "TtlCompactionFilterFactory";
  174. }
  175. private:
  176. int32_t ttl_;
  177. Env* env_;
  178. std::shared_ptr<CompactionFilterFactory> user_comp_filter_factory_;
  179. };
  180. class TtlMergeOperator : public MergeOperator {
  181. public:
  182. explicit TtlMergeOperator(const std::shared_ptr<MergeOperator>& merge_op,
  183. Env* env)
  184. : user_merge_op_(merge_op), env_(env) {
  185. assert(merge_op);
  186. assert(env);
  187. }
  188. virtual bool FullMergeV2(const MergeOperationInput& merge_in,
  189. MergeOperationOutput* merge_out) const override {
  190. const uint32_t ts_len = DBWithTTLImpl::kTSLength;
  191. if (merge_in.existing_value && merge_in.existing_value->size() < ts_len) {
  192. ROCKS_LOG_ERROR(merge_in.logger,
  193. "Error: Could not remove timestamp from existing value.");
  194. return false;
  195. }
  196. // Extract time-stamp from each operand to be passed to user_merge_op_
  197. std::vector<Slice> operands_without_ts;
  198. for (const auto& operand : merge_in.operand_list) {
  199. if (operand.size() < ts_len) {
  200. ROCKS_LOG_ERROR(
  201. merge_in.logger,
  202. "Error: Could not remove timestamp from operand value.");
  203. return false;
  204. }
  205. operands_without_ts.push_back(operand);
  206. operands_without_ts.back().remove_suffix(ts_len);
  207. }
  208. // Apply the user merge operator (store result in *new_value)
  209. bool good = true;
  210. MergeOperationOutput user_merge_out(merge_out->new_value,
  211. merge_out->existing_operand);
  212. if (merge_in.existing_value) {
  213. Slice existing_value_without_ts(merge_in.existing_value->data(),
  214. merge_in.existing_value->size() - ts_len);
  215. good = user_merge_op_->FullMergeV2(
  216. MergeOperationInput(merge_in.key, &existing_value_without_ts,
  217. operands_without_ts, merge_in.logger),
  218. &user_merge_out);
  219. } else {
  220. good = user_merge_op_->FullMergeV2(
  221. MergeOperationInput(merge_in.key, nullptr, operands_without_ts,
  222. merge_in.logger),
  223. &user_merge_out);
  224. }
  225. // Return false if the user merge operator returned false
  226. if (!good) {
  227. return false;
  228. }
  229. if (merge_out->existing_operand.data()) {
  230. merge_out->new_value.assign(merge_out->existing_operand.data(),
  231. merge_out->existing_operand.size());
  232. merge_out->existing_operand = Slice(nullptr, 0);
  233. }
  234. // Augment the *new_value with the ttl time-stamp
  235. int64_t curtime;
  236. if (!env_->GetCurrentTime(&curtime).ok()) {
  237. ROCKS_LOG_ERROR(
  238. merge_in.logger,
  239. "Error: Could not get current time to be attached internally "
  240. "to the new value.");
  241. return false;
  242. } else {
  243. char ts_string[ts_len];
  244. EncodeFixed32(ts_string, (int32_t)curtime);
  245. merge_out->new_value.append(ts_string, ts_len);
  246. return true;
  247. }
  248. }
  249. virtual bool PartialMergeMulti(const Slice& key,
  250. const std::deque<Slice>& operand_list,
  251. std::string* new_value, Logger* logger) const
  252. override {
  253. const uint32_t ts_len = DBWithTTLImpl::kTSLength;
  254. std::deque<Slice> operands_without_ts;
  255. for (const auto& operand : operand_list) {
  256. if (operand.size() < ts_len) {
  257. ROCKS_LOG_ERROR(logger,
  258. "Error: Could not remove timestamp from value.");
  259. return false;
  260. }
  261. operands_without_ts.push_back(
  262. Slice(operand.data(), operand.size() - ts_len));
  263. }
  264. // Apply the user partial-merge operator (store result in *new_value)
  265. assert(new_value);
  266. if (!user_merge_op_->PartialMergeMulti(key, operands_without_ts, new_value,
  267. logger)) {
  268. return false;
  269. }
  270. // Augment the *new_value with the ttl time-stamp
  271. int64_t curtime;
  272. if (!env_->GetCurrentTime(&curtime).ok()) {
  273. ROCKS_LOG_ERROR(
  274. logger,
  275. "Error: Could not get current time to be attached internally "
  276. "to the new value.");
  277. return false;
  278. } else {
  279. char ts_string[ts_len];
  280. EncodeFixed32(ts_string, (int32_t)curtime);
  281. new_value->append(ts_string, ts_len);
  282. return true;
  283. }
  284. }
  285. virtual const char* Name() const override { return "Merge By TTL"; }
  286. private:
  287. std::shared_ptr<MergeOperator> user_merge_op_;
  288. Env* env_;
  289. };
  290. } // namespace ROCKSDB_NAMESPACE
  291. #endif // ROCKSDB_LITE