1cd45cd1b3
Summary: Introducing FIFO compactions with TTL. FIFO compaction is based on size only which makes it tricky to enable in production as use cases can have organic growth. A user requested an option to drop files based on the time of their creation instead of the total size. To address that request: - Added a new TTL option to FIFO compaction options. - Updated FIFO compaction score to take TTL into consideration. - Added a new table property, creation_time, to keep track of when the SST file is created. - Creation_time is set as below: - On Flush: Set to the time of flush. - On Compaction: Set to the max creation_time of all the files involved in the compaction. - On Repair and Recovery: Set to the time of repair/recovery. - Old files created prior to this code change will have a creation_time of 0. - FIFO compaction with TTL is enabled when ttl > 0. All files older than ttl will be deleted during compaction. i.e. `if (file.creation_time < (current_time - ttl)) then delete(file)`. This will enable cases where you might want to delete all files older than, say, 1 day. - FIFO compaction will fall back to the prior way of deleting files based on size if: - the creation_time of all files involved in compaction is 0. - the total size (of all SST files combined) does not drop below `compaction_options_fifo.max_table_files_size` even if the files older than ttl are deleted. This feature is not supported if max_open_files != -1 or with table formats other than Block-based. **Test Plan:** Added tests. **Benchmark results:** Base: FIFO with max size: 100MB :: ``` svemuri@dev15905 ~/rocksdb (fifo-compaction) $ TEST_TMPDIR=/dev/shm ./db_bench --benchmarks=readwhilewriting --num=5000000 --threads=16 --compaction_style=2 --fifo_compaction_max_table_files_size_mb=100 readwhilewriting : 1.924 micros/op 519858 ops/sec; 13.6 MB/s (1176277 of 5000000 found) ``` With TTL (a low one for testing) :: ``` svemuri@dev15905 ~/rocksdb (fifo-compaction) $ TEST_TMPDIR=/dev/shm ./db_bench --benchmarks=readwhilewriting --num=5000000 --threads=16 --compaction_style=2 --fifo_compaction_max_table_files_size_mb=100 --fifo_compaction_ttl=20 readwhilewriting : 1.902 micros/op 525817 ops/sec; 13.7 MB/s (1185057 of 5000000 found) ``` Example Log lines: ``` 2017/06/26-15:17:24.609249 7fd5a45ff700 (Original Log Time 2017/06/26-15:17:24.609177) [db/compaction_picker.cc:1471] [default] FIFO compaction: picking file 40 with creation time 1498515423 for deletion 2017/06/26-15:17:24.609255 7fd5a45ff700 (Original Log Time 2017/06/26-15:17:24.609234) [db/db_impl_compaction_flush.cc:1541] [default] Deleted 1 files ... 2017/06/26-15:17:25.553185 7fd5a61a5800 [DEBUG] [db/db_impl_files.cc:309] [JOB 0] Delete /dev/shm/dbbench/000040.sst type=2 #40 -- OK 2017/06/26-15:17:25.553205 7fd5a61a5800 EVENT_LOG_v1 {"time_micros": 1498515445553199, "job": 0, "event": "table_file_deletion", "file_number": 40} ``` SST Files remaining in the dbbench dir, after db_bench execution completed: ``` svemuri@dev15905 ~/rocksdb (fifo-compaction) $ ls -l /dev/shm//dbbench/*.sst -rw-r--r--. 1 svemuri users 30749887 Jun 26 15:17 /dev/shm//dbbench/000042.sst -rw-r--r--. 1 svemuri users 30768779 Jun 26 15:17 /dev/shm//dbbench/000044.sst -rw-r--r--. 1 svemuri users 30757481 Jun 26 15:17 /dev/shm//dbbench/000046.sst ``` Closes https://github.com/facebook/rocksdb/pull/2480 Differential Revision: D5305116 Pulled By: sagar0 fbshipit-source-id: 3e5cfcf5dd07ed2211b5b37492eb235b45139174
219 lines
8.2 KiB
C++
219 lines
8.2 KiB
C++
// 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.
|
|
#pragma once
|
|
|
|
#include <stdint.h>
|
|
#include <string>
|
|
#include <map>
|
|
#include "rocksdb/status.h"
|
|
#include "rocksdb/types.h"
|
|
|
|
namespace rocksdb {
|
|
|
|
// -- Table Properties
|
|
// Other than basic table properties, each table may also have the user
|
|
// collected properties.
|
|
// The value of the user-collected properties are encoded as raw bytes --
|
|
// users have to interprete these values by themselves.
|
|
// Note: To do prefix seek/scan in `UserCollectedProperties`, you can do
|
|
// something similar to:
|
|
//
|
|
// UserCollectedProperties props = ...;
|
|
// for (auto pos = props.lower_bound(prefix);
|
|
// pos != props.end() && pos->first.compare(0, prefix.size(), prefix) == 0;
|
|
// ++pos) {
|
|
// ...
|
|
// }
|
|
typedef std::map<std::string, std::string> UserCollectedProperties;
|
|
|
|
// table properties' human-readable names in the property block.
|
|
struct TablePropertiesNames {
|
|
static const std::string kDataSize;
|
|
static const std::string kIndexSize;
|
|
static const std::string kIndexPartitions;
|
|
static const std::string kTopLevelIndexSize;
|
|
static const std::string kFilterSize;
|
|
static const std::string kRawKeySize;
|
|
static const std::string kRawValueSize;
|
|
static const std::string kNumDataBlocks;
|
|
static const std::string kNumEntries;
|
|
static const std::string kFormatVersion;
|
|
static const std::string kFixedKeyLen;
|
|
static const std::string kFilterPolicy;
|
|
static const std::string kColumnFamilyName;
|
|
static const std::string kColumnFamilyId;
|
|
static const std::string kComparator;
|
|
static const std::string kMergeOperator;
|
|
static const std::string kPrefixExtractorName;
|
|
static const std::string kPropertyCollectors;
|
|
static const std::string kCompression;
|
|
static const std::string kCreationTime;
|
|
};
|
|
|
|
extern const std::string kPropertiesBlock;
|
|
extern const std::string kCompressionDictBlock;
|
|
extern const std::string kRangeDelBlock;
|
|
|
|
enum EntryType {
|
|
kEntryPut,
|
|
kEntryDelete,
|
|
kEntrySingleDelete,
|
|
kEntryMerge,
|
|
kEntryOther,
|
|
};
|
|
|
|
// `TablePropertiesCollector` provides the mechanism for users to collect
|
|
// their own properties that they are interested in. This class is essentially
|
|
// a collection of callback functions that will be invoked during table
|
|
// building. It is construced with TablePropertiesCollectorFactory. The methods
|
|
// don't need to be thread-safe, as we will create exactly one
|
|
// TablePropertiesCollector object per table and then call it sequentially
|
|
class TablePropertiesCollector {
|
|
public:
|
|
virtual ~TablePropertiesCollector() {}
|
|
|
|
// DEPRECATE User defined collector should implement AddUserKey(), though
|
|
// this old function still works for backward compatible reason.
|
|
// Add() will be called when a new key/value pair is inserted into the table.
|
|
// @params key the user key that is inserted into the table.
|
|
// @params value the value that is inserted into the table.
|
|
virtual Status Add(const Slice& /*key*/, const Slice& /*value*/) {
|
|
return Status::InvalidArgument(
|
|
"TablePropertiesCollector::Add() deprecated.");
|
|
}
|
|
|
|
// AddUserKey() will be called when a new key/value pair is inserted into the
|
|
// table.
|
|
// @params key the user key that is inserted into the table.
|
|
// @params value the value that is inserted into the table.
|
|
virtual Status AddUserKey(const Slice& key, const Slice& value,
|
|
EntryType /*type*/, SequenceNumber /*seq*/,
|
|
uint64_t /*file_size*/) {
|
|
// For backwards-compatibility.
|
|
return Add(key, value);
|
|
}
|
|
|
|
// Finish() will be called when a table has already been built and is ready
|
|
// for writing the properties block.
|
|
// @params properties User will add their collected statistics to
|
|
// `properties`.
|
|
virtual Status Finish(UserCollectedProperties* properties) = 0;
|
|
|
|
// Return the human-readable properties, where the key is property name and
|
|
// the value is the human-readable form of value.
|
|
virtual UserCollectedProperties GetReadableProperties() const = 0;
|
|
|
|
// The name of the properties collector can be used for debugging purpose.
|
|
virtual const char* Name() const = 0;
|
|
|
|
// EXPERIMENTAL Return whether the output file should be further compacted
|
|
virtual bool NeedCompact() const { return false; }
|
|
};
|
|
|
|
// Constructs TablePropertiesCollector. Internals create a new
|
|
// TablePropertiesCollector for each new table
|
|
class TablePropertiesCollectorFactory {
|
|
public:
|
|
struct Context {
|
|
uint32_t column_family_id;
|
|
static const uint32_t kUnknownColumnFamily;
|
|
};
|
|
|
|
virtual ~TablePropertiesCollectorFactory() {}
|
|
// has to be thread-safe
|
|
virtual TablePropertiesCollector* CreateTablePropertiesCollector(
|
|
TablePropertiesCollectorFactory::Context context) = 0;
|
|
|
|
// The name of the properties collector can be used for debugging purpose.
|
|
virtual const char* Name() const = 0;
|
|
};
|
|
|
|
// TableProperties contains a bunch of read-only properties of its associated
|
|
// table.
|
|
struct TableProperties {
|
|
public:
|
|
// the total size of all data blocks.
|
|
uint64_t data_size = 0;
|
|
// the size of index block.
|
|
uint64_t index_size = 0;
|
|
// Total number of index partitions if kTwoLevelIndexSearch is used
|
|
uint64_t index_partitions = 0;
|
|
// Size of the top-level index if kTwoLevelIndexSearch is used
|
|
uint64_t top_level_index_size = 0;
|
|
// the size of filter block.
|
|
uint64_t filter_size = 0;
|
|
// total raw key size
|
|
uint64_t raw_key_size = 0;
|
|
// total raw value size
|
|
uint64_t raw_value_size = 0;
|
|
// the number of blocks in this table
|
|
uint64_t num_data_blocks = 0;
|
|
// the number of entries in this table
|
|
uint64_t num_entries = 0;
|
|
// format version, reserved for backward compatibility
|
|
uint64_t format_version = 0;
|
|
// If 0, key is variable length. Otherwise number of bytes for each key.
|
|
uint64_t fixed_key_len = 0;
|
|
// ID of column family for this SST file, corresponding to the CF identified
|
|
// by column_family_name.
|
|
uint64_t column_family_id =
|
|
rocksdb::TablePropertiesCollectorFactory::Context::kUnknownColumnFamily;
|
|
// The time when the SST file was created.
|
|
// Since SST files are immutable, this is equivalent to last modified time.
|
|
uint64_t creation_time = 0;
|
|
|
|
// Name of the column family with which this SST file is associated.
|
|
// If column family is unknown, `column_family_name` will be an empty string.
|
|
std::string column_family_name;
|
|
|
|
// The name of the filter policy used in this table.
|
|
// If no filter policy is used, `filter_policy_name` will be an empty string.
|
|
std::string filter_policy_name;
|
|
|
|
// The name of the comparator used in this table.
|
|
std::string comparator_name;
|
|
|
|
// The name of the merge operator used in this table.
|
|
// If no merge operator is used, `merge_operator_name` will be "nullptr".
|
|
std::string merge_operator_name;
|
|
|
|
// The name of the prefix extractor used in this table
|
|
// If no prefix extractor is used, `prefix_extractor_name` will be "nullptr".
|
|
std::string prefix_extractor_name;
|
|
|
|
// The names of the property collectors factories used in this table
|
|
// separated by commas
|
|
// {collector_name[1]},{collector_name[2]},{collector_name[3]} ..
|
|
std::string property_collectors_names;
|
|
|
|
// The compression algo used to compress the SST files.
|
|
std::string compression_name;
|
|
|
|
// user collected properties
|
|
UserCollectedProperties user_collected_properties;
|
|
UserCollectedProperties readable_properties;
|
|
|
|
// The offset of the value of each property in the file.
|
|
std::map<std::string, uint64_t> properties_offsets;
|
|
|
|
// convert this object to a human readable form
|
|
// @prop_delim: delimiter for each property.
|
|
std::string ToString(const std::string& prop_delim = "; ",
|
|
const std::string& kv_delim = "=") const;
|
|
|
|
// Aggregate the numerical member variables of the specified
|
|
// TableProperties.
|
|
void Add(const TableProperties& tp);
|
|
};
|
|
|
|
// Extra properties
|
|
// Below is a list of non-basic properties that are collected by database
|
|
// itself. Especially some properties regarding to the internal keys (which
|
|
// is unknown to `table`).
|
|
extern uint64_t GetDeletedKeys(const UserCollectedProperties& props);
|
|
extern uint64_t GetMergeOperands(const UserCollectedProperties& props,
|
|
bool* property_present);
|
|
|
|
} // namespace rocksdb
|