fork of https://github.com/oxigraph/rocksdb and https://github.com/facebook/rocksdb for nextgraph and oxigraph
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
283 lines
9.6 KiB
283 lines
9.6 KiB
12 years ago
|
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file. See the AUTHORS file for names of contributors.
|
||
11 years ago
|
#ifndef ROCKSDB_LITE
|
||
12 years ago
|
|
||
11 years ago
|
#include "utilities/ttl/db_ttl_impl.h"
|
||
|
|
||
|
#include "utilities/db_ttl.h"
|
||
12 years ago
|
#include "db/filename.h"
|
||
11 years ago
|
#include "db/write_batch_internal.h"
|
||
12 years ago
|
#include "util/coding.h"
|
||
11 years ago
|
#include "rocksdb/env.h"
|
||
|
#include "rocksdb/iterator.h"
|
||
12 years ago
|
|
||
11 years ago
|
namespace rocksdb {
|
||
12 years ago
|
|
||
11 years ago
|
void DBWithTTLImpl::SanitizeOptions(int32_t ttl, ColumnFamilyOptions* options) {
|
||
11 years ago
|
if (options->compaction_filter) {
|
||
|
options->compaction_filter =
|
||
|
new TtlCompactionFilter(ttl, options->compaction_filter);
|
||
12 years ago
|
} else {
|
||
11 years ago
|
options->compaction_filter_factory =
|
||
|
std::shared_ptr<CompactionFilterFactory>(new TtlCompactionFilterFactory(
|
||
|
ttl, options->compaction_filter_factory));
|
||
12 years ago
|
}
|
||
12 years ago
|
|
||
11 years ago
|
if (options->merge_operator) {
|
||
|
options->merge_operator.reset(
|
||
|
new TtlMergeOperator(options->merge_operator));
|
||
12 years ago
|
}
|
||
12 years ago
|
}
|
||
|
|
||
11 years ago
|
// Open the db inside DBWithTTLImpl because options needs pointer to its ttl
|
||
|
DBWithTTLImpl::DBWithTTLImpl(DB* db) : DBWithTTL(db) {}
|
||
|
|
||
|
DBWithTTLImpl::~DBWithTTLImpl() { delete GetOptions().compaction_filter; }
|
||
11 years ago
|
|
||
11 years ago
|
Status UtilityDB::OpenTtlDB(const Options& options, const std::string& dbname,
|
||
|
StackableDB** dbptr, int32_t ttl, bool read_only) {
|
||
|
DBWithTTL* db;
|
||
|
Status s = DBWithTTL::Open(options, dbname, &db, ttl, read_only);
|
||
|
if (s.ok()) {
|
||
|
*dbptr = db;
|
||
|
} else {
|
||
|
*dbptr = nullptr;
|
||
|
}
|
||
|
return s;
|
||
12 years ago
|
}
|
||
|
|
||
11 years ago
|
Status DBWithTTL::Open(const Options& options, const std::string& dbname,
|
||
|
DBWithTTL** dbptr, int32_t ttl, bool read_only) {
|
||
11 years ago
|
|
||
|
DBOptions db_options(options);
|
||
|
ColumnFamilyOptions cf_options(options);
|
||
|
std::vector<ColumnFamilyDescriptor> column_families;
|
||
|
column_families.push_back(
|
||
|
ColumnFamilyDescriptor(kDefaultColumnFamilyName, cf_options));
|
||
|
std::vector<ColumnFamilyHandle*> handles;
|
||
11 years ago
|
Status s = DBWithTTL::Open(db_options, dbname, column_families, &handles,
|
||
|
dbptr, {ttl}, read_only);
|
||
11 years ago
|
if (s.ok()) {
|
||
|
assert(handles.size() == 1);
|
||
|
// i can delete the handle since DBImpl is always holding a reference to
|
||
|
// default column family
|
||
|
delete handles[0];
|
||
|
}
|
||
|
return s;
|
||
|
}
|
||
|
|
||
11 years ago
|
Status DBWithTTL::Open(
|
||
11 years ago
|
const DBOptions& db_options, const std::string& dbname,
|
||
|
const std::vector<ColumnFamilyDescriptor>& column_families,
|
||
11 years ago
|
std::vector<ColumnFamilyHandle*>* handles, DBWithTTL** dbptr,
|
||
11 years ago
|
std::vector<int32_t> ttls, bool read_only) {
|
||
|
|
||
|
if (ttls.size() != column_families.size()) {
|
||
|
return Status::InvalidArgument(
|
||
|
"ttls size has to be the same as number of column families");
|
||
|
}
|
||
|
|
||
|
std::vector<ColumnFamilyDescriptor> column_families_sanitized =
|
||
|
column_families;
|
||
|
for (size_t i = 0; i < column_families_sanitized.size(); ++i) {
|
||
11 years ago
|
DBWithTTLImpl::SanitizeOptions(ttls[i],
|
||
|
&column_families_sanitized[i].options);
|
||
11 years ago
|
}
|
||
11 years ago
|
DB* db;
|
||
|
|
||
11 years ago
|
Status st;
|
||
11 years ago
|
if (read_only) {
|
||
11 years ago
|
st = DB::OpenForReadOnly(db_options, dbname, column_families_sanitized,
|
||
|
handles, &db);
|
||
11 years ago
|
} else {
|
||
11 years ago
|
st = DB::Open(db_options, dbname, column_families_sanitized, handles, &db);
|
||
11 years ago
|
}
|
||
|
if (st.ok()) {
|
||
11 years ago
|
*dbptr = new DBWithTTLImpl(db);
|
||
11 years ago
|
} else {
|
||
11 years ago
|
*dbptr = nullptr;
|
||
12 years ago
|
}
|
||
|
return st;
|
||
|
}
|
||
|
|
||
11 years ago
|
Status DBWithTTLImpl::CreateColumnFamilyWithTtl(
|
||
|
const ColumnFamilyOptions& options, const std::string& column_family_name,
|
||
|
ColumnFamilyHandle** handle, int ttl) {
|
||
|
ColumnFamilyOptions sanitized_options = options;
|
||
|
DBWithTTLImpl::SanitizeOptions(ttl, &sanitized_options);
|
||
|
|
||
|
return DBWithTTL::CreateColumnFamily(sanitized_options, column_family_name,
|
||
|
handle);
|
||
|
}
|
||
|
|
||
|
Status DBWithTTLImpl::CreateColumnFamily(const ColumnFamilyOptions& options,
|
||
|
const std::string& column_family_name,
|
||
|
ColumnFamilyHandle** handle) {
|
||
|
return CreateColumnFamilyWithTtl(options, column_family_name, handle, 0);
|
||
|
}
|
||
|
|
||
12 years ago
|
// Gives back the current time
|
||
11 years ago
|
Status DBWithTTLImpl::GetCurrentTime(int64_t* curtime) {
|
||
|
return Env::Default()->GetCurrentTime(curtime);
|
||
12 years ago
|
}
|
||
|
|
||
|
// Appends the current timestamp to the string.
|
||
|
// Returns false if could not get the current_time, true if append succeeds
|
||
11 years ago
|
Status DBWithTTLImpl::AppendTS(const Slice& val, std::string* val_with_ts) {
|
||
|
val_with_ts->reserve(kTSLength + val.size());
|
||
12 years ago
|
char ts_string[kTSLength];
|
||
11 years ago
|
int64_t curtime;
|
||
11 years ago
|
Status st = GetCurrentTime(&curtime);
|
||
12 years ago
|
if (!st.ok()) {
|
||
|
return st;
|
||
|
}
|
||
11 years ago
|
EncodeFixed32(ts_string, (int32_t)curtime);
|
||
11 years ago
|
val_with_ts->append(val.data(), val.size());
|
||
|
val_with_ts->append(ts_string, kTSLength);
|
||
12 years ago
|
return st;
|
||
|
}
|
||
|
|
||
12 years ago
|
// Returns corruption if the length of the string is lesser than timestamp, or
|
||
|
// timestamp refers to a time lesser than ttl-feature release time
|
||
11 years ago
|
Status DBWithTTLImpl::SanityCheckTimestamp(const Slice& str) {
|
||
12 years ago
|
if (str.size() < kTSLength) {
|
||
12 years ago
|
return Status::Corruption("Error: value's length less than timestamp's\n");
|
||
|
}
|
||
|
// Checks that TS is not lesser than kMinTimestamp
|
||
|
// Gaurds against corruption & normal database opened incorrectly in ttl mode
|
||
11 years ago
|
int32_t timestamp_value = DecodeFixed32(str.data() + str.size() - kTSLength);
|
||
|
if (timestamp_value < kMinTimestamp) {
|
||
12 years ago
|
return Status::Corruption("Error: Timestamp < ttl feature release time!\n");
|
||
|
}
|
||
|
return Status::OK();
|
||
|
}
|
||
|
|
||
12 years ago
|
// Checks if the string is stale or not according to TTl provided
|
||
11 years ago
|
bool DBWithTTLImpl::IsStale(const Slice& value, int32_t ttl) {
|
||
|
if (ttl <= 0) { // Data is fresh if TTL is non-positive
|
||
12 years ago
|
return false;
|
||
|
}
|
||
11 years ago
|
int64_t curtime;
|
||
11 years ago
|
if (!GetCurrentTime(&curtime).ok()) {
|
||
|
return false; // Treat the data as fresh if could not get current time
|
||
12 years ago
|
}
|
||
12 years ago
|
int32_t timestamp_value =
|
||
11 years ago
|
DecodeFixed32(value.data() + value.size() - kTSLength);
|
||
12 years ago
|
return (timestamp_value + ttl) < curtime;
|
||
12 years ago
|
}
|
||
|
|
||
|
// Strips the TS from the end of the string
|
||
11 years ago
|
Status DBWithTTLImpl::StripTS(std::string* str) {
|
||
12 years ago
|
Status st;
|
||
12 years ago
|
if (str->length() < kTSLength) {
|
||
|
return Status::Corruption("Bad timestamp in key-value");
|
||
|
}
|
||
12 years ago
|
// Erasing characters which hold the TS
|
||
|
str->erase(str->length() - kTSLength, kTSLength);
|
||
|
return st;
|
||
|
}
|
||
|
|
||
11 years ago
|
Status DBWithTTLImpl::Put(const WriteOptions& options,
|
||
|
ColumnFamilyHandle* column_family, const Slice& key,
|
||
|
const Slice& val) {
|
||
12 years ago
|
WriteBatch batch;
|
||
11 years ago
|
batch.Put(column_family, key, val);
|
||
11 years ago
|
return Write(options, &batch);
|
||
12 years ago
|
}
|
||
|
|
||
11 years ago
|
Status DBWithTTLImpl::Get(const ReadOptions& options,
|
||
|
ColumnFamilyHandle* column_family, const Slice& key,
|
||
|
std::string* value) {
|
||
11 years ago
|
Status st = db_->Get(options, column_family, key, value);
|
||
12 years ago
|
if (!st.ok()) {
|
||
|
return st;
|
||
|
}
|
||
12 years ago
|
st = SanityCheckTimestamp(*value);
|
||
|
if (!st.ok()) {
|
||
|
return st;
|
||
|
}
|
||
12 years ago
|
return StripTS(value);
|
||
|
}
|
||
|
|
||
11 years ago
|
std::vector<Status> DBWithTTLImpl::MultiGet(
|
||
11 years ago
|
const ReadOptions& options,
|
||
11 years ago
|
const std::vector<ColumnFamilyHandle*>& column_family,
|
||
11 years ago
|
const std::vector<Slice>& keys, std::vector<std::string>* values) {
|
||
11 years ago
|
return std::vector<Status>(
|
||
|
keys.size(), Status::NotSupported("MultiGet not supported with TTL"));
|
||
12 years ago
|
}
|
||
|
|
||
11 years ago
|
bool DBWithTTLImpl::KeyMayExist(const ReadOptions& options,
|
||
|
ColumnFamilyHandle* column_family,
|
||
|
const Slice& key, std::string* value,
|
||
|
bool* value_found) {
|
||
11 years ago
|
bool ret = db_->KeyMayExist(options, column_family, key, value, value_found);
|
||
12 years ago
|
if (ret && value != nullptr && value_found != nullptr && *value_found) {
|
||
|
if (!SanityCheckTimestamp(*value).ok() || !StripTS(value).ok()) {
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
return ret;
|
||
12 years ago
|
}
|
||
|
|
||
11 years ago
|
Status DBWithTTLImpl::Merge(const WriteOptions& options,
|
||
|
ColumnFamilyHandle* column_family, const Slice& key,
|
||
|
const Slice& value) {
|
||
12 years ago
|
WriteBatch batch;
|
||
11 years ago
|
batch.Merge(column_family, key, value);
|
||
11 years ago
|
return Write(options, &batch);
|
||
12 years ago
|
}
|
||
|
|
||
11 years ago
|
Status DBWithTTLImpl::Write(const WriteOptions& opts, WriteBatch* updates) {
|
||
12 years ago
|
class Handler : public WriteBatch::Handler {
|
||
|
public:
|
||
|
WriteBatch updates_ttl;
|
||
|
Status batch_rewrite_status;
|
||
11 years ago
|
virtual Status PutCF(uint32_t column_family_id, const Slice& key,
|
||
|
const Slice& value) {
|
||
12 years ago
|
std::string value_with_ts;
|
||
11 years ago
|
Status st = AppendTS(value, &value_with_ts);
|
||
12 years ago
|
if (!st.ok()) {
|
||
|
batch_rewrite_status = st;
|
||
|
} else {
|
||
11 years ago
|
WriteBatchInternal::Put(&updates_ttl, column_family_id, key,
|
||
|
value_with_ts);
|
||
12 years ago
|
}
|
||
11 years ago
|
return Status::OK();
|
||
12 years ago
|
}
|
||
11 years ago
|
virtual Status MergeCF(uint32_t column_family_id, const Slice& key,
|
||
|
const Slice& value) {
|
||
12 years ago
|
std::string value_with_ts;
|
||
11 years ago
|
Status st = AppendTS(value, &value_with_ts);
|
||
12 years ago
|
if (!st.ok()) {
|
||
|
batch_rewrite_status = st;
|
||
|
} else {
|
||
11 years ago
|
WriteBatchInternal::Merge(&updates_ttl, column_family_id, key,
|
||
|
value_with_ts);
|
||
12 years ago
|
}
|
||
11 years ago
|
return Status::OK();
|
||
12 years ago
|
}
|
||
11 years ago
|
virtual Status DeleteCF(uint32_t column_family_id, const Slice& key) {
|
||
|
WriteBatchInternal::Delete(&updates_ttl, column_family_id, key);
|
||
|
return Status::OK();
|
||
12 years ago
|
}
|
||
11 years ago
|
virtual void LogData(const Slice& blob) { updates_ttl.PutLogData(blob); }
|
||
12 years ago
|
};
|
||
|
Handler handler;
|
||
|
updates->Iterate(&handler);
|
||
|
if (!handler.batch_rewrite_status.ok()) {
|
||
|
return handler.batch_rewrite_status;
|
||
|
} else {
|
||
|
return db_->Write(opts, &(handler.updates_ttl));
|
||
|
}
|
||
12 years ago
|
}
|
||
|
|
||
11 years ago
|
Iterator* DBWithTTLImpl::NewIterator(const ReadOptions& opts,
|
||
|
ColumnFamilyHandle* column_family) {
|
||
11 years ago
|
return new TtlIterator(db_->NewIterator(opts, column_family));
|
||
12 years ago
|
}
|
||
|
|
||
11 years ago
|
} // namespace rocksdb
|
||
11 years ago
|
#endif // ROCKSDB_LITE
|