diff --git a/HISTORY.md b/HISTORY.md index 133d76a03..599d8ca49 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -29,6 +29,11 @@ * `rocksdb_comparator_with_ts_create` to create timestamp aware comparator * Put, Get, Delete, SingleDelete, MultiGet APIs has corresponding timestamp aware APIs with suffix `with_ts` * And Add C API's for Transaction, SstFileWriter, Compaction as mentioned [here](https://github.com/facebook/rocksdb/wiki/User-defined-Timestamp-(Experimental)) +* Add metadata related structs and functions in C API, including + * `rocksdb_get_column_family_metadata()` and `rocksdb_get_column_family_metadata_cf()` to obtain `rocksdb_column_family_metadata_t`. + * `rocksdb_column_family_metadata_t` and its get functions & destroy function. + * `rocksdb_level_metadata_t` and its and its get functions & destroy function. + * `rocksdb_file_metadata_t` and its and get functions & destroy functions. * The contract for implementations of Comparator::IsSameLengthImmediateSuccessor has been updated to work around a design bug in `auto_prefix_mode`. * The API documentation for `auto_prefix_mode` now notes some corner cases in which it returns different results than `total_order_seek`, due to design bugs that are not easily fixed. Users using built-in comparators and keys at least the size of a fixed prefix length are not affected. * Obsoleted the NUM_DATA_BLOCKS_READ_PER_LEVEL stat and introduced the NUM_LEVEL_READ_PER_MULTIGET and MULTIGET_COROUTINE_COUNT stats diff --git a/db/c.cc b/db/c.cc index d1d0aafe1..b3ebe7ccc 100644 --- a/db/c.cc +++ b/db/c.cc @@ -59,6 +59,7 @@ using ROCKSDB_NAMESPACE::Cache; using ROCKSDB_NAMESPACE::Checkpoint; using ROCKSDB_NAMESPACE::ColumnFamilyDescriptor; using ROCKSDB_NAMESPACE::ColumnFamilyHandle; +using ROCKSDB_NAMESPACE::ColumnFamilyMetaData; using ROCKSDB_NAMESPACE::ColumnFamilyOptions; using ROCKSDB_NAMESPACE::CompactionFilter; using ROCKSDB_NAMESPACE::CompactionFilterFactory; @@ -78,6 +79,7 @@ using ROCKSDB_NAMESPACE::FlushOptions; using ROCKSDB_NAMESPACE::InfoLogLevel; using ROCKSDB_NAMESPACE::IngestExternalFileOptions; using ROCKSDB_NAMESPACE::Iterator; +using ROCKSDB_NAMESPACE::LevelMetaData; using ROCKSDB_NAMESPACE::LiveFileMetaData; using ROCKSDB_NAMESPACE::Logger; using ROCKSDB_NAMESPACE::LRUCacheOptions; @@ -105,6 +107,7 @@ using ROCKSDB_NAMESPACE::Slice; using ROCKSDB_NAMESPACE::SliceParts; using ROCKSDB_NAMESPACE::SliceTransform; using ROCKSDB_NAMESPACE::Snapshot; +using ROCKSDB_NAMESPACE::SstFileMetaData; using ROCKSDB_NAMESPACE::SstFileWriter; using ROCKSDB_NAMESPACE::Status; using ROCKSDB_NAMESPACE::TablePropertiesCollectorFactory; @@ -178,6 +181,15 @@ struct rocksdb_cache_t { }; struct rocksdb_livefiles_t { std::vector rep; }; struct rocksdb_column_family_handle_t { ColumnFamilyHandle* rep; }; +struct rocksdb_column_family_metadata_t { + ColumnFamilyMetaData rep; +}; +struct rocksdb_level_metadata_t { + const LevelMetaData* rep; +}; +struct rocksdb_sst_file_metadata_t { + const SstFileMetaData* rep; +}; struct rocksdb_envoptions_t { EnvOptions rep; }; struct rocksdb_ingestexternalfileoptions_t { IngestExternalFileOptions rep; }; struct rocksdb_sstfilewriter_t { SstFileWriter* rep; }; @@ -5131,6 +5143,119 @@ void rocksdb_delete_file_in_range_cf( (limit_key ? (b = Slice(limit_key, limit_key_len), &b) : nullptr))); } +/* MetaData */ + +rocksdb_column_family_metadata_t* rocksdb_get_column_family_metadata( + rocksdb_t* db) { + rocksdb_column_family_metadata_t* meta = new rocksdb_column_family_metadata_t; + db->rep->GetColumnFamilyMetaData(&meta->rep); + return meta; +} + +rocksdb_column_family_metadata_t* rocksdb_get_column_family_metadata_cf( + rocksdb_t* db, rocksdb_column_family_handle_t* column_family) { + rocksdb_column_family_metadata_t* meta = new rocksdb_column_family_metadata_t; + db->rep->GetColumnFamilyMetaData(column_family->rep, &meta->rep); + return meta; +} + +void rocksdb_column_family_metadata_destroy( + rocksdb_column_family_metadata_t* cf_meta) { + delete cf_meta; +} + +uint64_t rocksdb_column_family_metadata_get_size( + rocksdb_column_family_metadata_t* cf_meta) { + return cf_meta->rep.size; +} + +size_t rocksdb_column_family_metadata_get_file_count( + rocksdb_column_family_metadata_t* cf_meta) { + return cf_meta->rep.file_count; +} + +char* rocksdb_column_family_metadata_get_name( + rocksdb_column_family_metadata_t* cf_meta) { + return strdup(cf_meta->rep.name.c_str()); +} + +size_t rocksdb_column_family_metadata_get_level_count( + rocksdb_column_family_metadata_t* cf_meta) { + return cf_meta->rep.levels.size(); +} + +rocksdb_level_metadata_t* rocksdb_column_family_metadata_get_level_metadata( + rocksdb_column_family_metadata_t* cf_meta, size_t i) { + if (i >= cf_meta->rep.levels.size()) { + return NULL; + } + rocksdb_level_metadata_t* level_meta = + (rocksdb_level_metadata_t*)malloc(sizeof(rocksdb_level_metadata_t)); + level_meta->rep = &cf_meta->rep.levels[i]; + + return level_meta; +} + +void rocksdb_level_metadata_destroy(rocksdb_level_metadata_t* level_meta) { + // Only free the base pointer as its parent rocksdb_column_family_metadata_t + // has the ownership of its rep. + free(level_meta); +} + +int rocksdb_level_metadata_get_level(rocksdb_level_metadata_t* level_meta) { + return level_meta->rep->level; +} + +uint64_t rocksdb_level_metadata_get_size(rocksdb_level_metadata_t* level_meta) { + return level_meta->rep->size; +} + +size_t rocksdb_level_metadata_get_file_count( + rocksdb_level_metadata_t* level_meta) { + return level_meta->rep->files.size(); +} + +rocksdb_sst_file_metadata_t* rocksdb_level_metadata_get_sst_file_metadata( + rocksdb_level_metadata_t* level_meta, size_t i) { + if (i >= level_meta->rep->files.size()) { + return nullptr; + } + rocksdb_sst_file_metadata_t* file_meta = + (rocksdb_sst_file_metadata_t*)malloc(sizeof(rocksdb_sst_file_metadata_t)); + file_meta->rep = &level_meta->rep->files[i]; + return file_meta; +} + +void rocksdb_sst_file_metadata_destroy(rocksdb_sst_file_metadata_t* file_meta) { + // Only free the base pointer as its parent rocksdb_level_metadata_t + // has the ownership of its rep. + free(file_meta); +} + +char* rocksdb_sst_file_metadata_get_relative_filename( + rocksdb_sst_file_metadata_t* file_meta) { + return strdup(file_meta->rep->relative_filename.c_str()); +} + +uint64_t rocksdb_sst_file_metadata_get_size( + rocksdb_sst_file_metadata_t* file_meta) { + return file_meta->rep->size; +} + +char* rocksdb_sst_file_metadata_get_smallestkey( + rocksdb_sst_file_metadata_t* file_meta, size_t* key_len) { + *key_len = file_meta->rep->smallestkey.size(); + return CopyString(file_meta->rep->smallestkey); +} + +char* rocksdb_sst_file_metadata_get_largestkey( + rocksdb_sst_file_metadata_t* file_meta, size_t* key_len) { + *key_len = file_meta->rep->largestkey.size(); + return CopyString(file_meta->rep->largestkey); +} + +/* Transactions */ + rocksdb_transactiondb_options_t* rocksdb_transactiondb_options_create() { return new rocksdb_transactiondb_options_t; } diff --git a/db/c_test.c b/db/c_test.c index 9bbae537b..c99955018 100644 --- a/db/c_test.c +++ b/db/c_test.c @@ -272,6 +272,92 @@ static rocksdb_compactionfilter_t* CFilterCreate( CFilterName); } +void CheckMetaData(rocksdb_column_family_metadata_t* cf_meta, + const char* expected_cf_name) { + char* cf_name = rocksdb_column_family_metadata_get_name(cf_meta); + assert(strcmp(cf_name, expected_cf_name) == 0); + rocksdb_free(cf_name); + + size_t cf_size = rocksdb_column_family_metadata_get_size(cf_meta); + assert(cf_size > 0); + size_t cf_file_count = rocksdb_column_family_metadata_get_size(cf_meta); + assert(cf_file_count > 0); + + uint64_t total_level_size = 0; + size_t total_file_count = 0; + size_t level_count = rocksdb_column_family_metadata_get_level_count(cf_meta); + assert(level_count > 0); + for (size_t l = 0; l < level_count; ++l) { + rocksdb_level_metadata_t* level_meta = + rocksdb_column_family_metadata_get_level_metadata(cf_meta, l); + assert(level_meta); + assert(rocksdb_level_metadata_get_level(level_meta) >= (int)l); + uint64_t level_size = rocksdb_level_metadata_get_size(level_meta); + uint64_t file_size_in_level = 0; + + size_t file_count = rocksdb_level_metadata_get_file_count(level_meta); + total_file_count += file_count; + for (size_t f = 0; f < file_count; ++f) { + rocksdb_sst_file_metadata_t* file_meta = + rocksdb_level_metadata_get_sst_file_metadata(level_meta, f); + assert(file_meta); + + uint64_t file_size = rocksdb_sst_file_metadata_get_size(file_meta); + assert(file_size > 0); + file_size_in_level += file_size; + + char* file_name = + rocksdb_sst_file_metadata_get_relative_filename(file_meta); + assert(file_name); + assert(strlen(file_name) > 0); + rocksdb_free(file_name); + + size_t smallest_key_len; + char* smallest_key = rocksdb_sst_file_metadata_get_smallestkey( + file_meta, &smallest_key_len); + assert(smallest_key); + assert(smallest_key_len > 0); + size_t largest_key_len; + char* largest_key = + rocksdb_sst_file_metadata_get_largestkey(file_meta, &largest_key_len); + assert(largest_key); + assert(largest_key_len > 0); + rocksdb_free(smallest_key); + rocksdb_free(largest_key); + + rocksdb_sst_file_metadata_destroy(file_meta); + } + assert(level_size == file_size_in_level); + total_level_size += level_size; + rocksdb_level_metadata_destroy(level_meta); + } + assert(total_file_count > 0); + assert(cf_size == total_level_size); +} + +void GetAndCheckMetaData(rocksdb_t* db) { + rocksdb_column_family_metadata_t* cf_meta = + rocksdb_get_column_family_metadata(db); + + CheckMetaData(cf_meta, "default"); + + rocksdb_column_family_metadata_destroy(cf_meta); +} + +void GetAndCheckMetaDataCf(rocksdb_t* db, + rocksdb_column_family_handle_t* handle, + const char* cf_name) { + // Compact to make sure we have at least one sst file to obtain datadata. + rocksdb_compact_range_cf(db, handle, NULL, 0, NULL, 0); + + rocksdb_column_family_metadata_t* cf_meta = + rocksdb_get_column_family_metadata_cf(db, handle); + + CheckMetaData(cf_meta, cf_name); + + rocksdb_column_family_metadata_destroy(cf_meta); +} + static rocksdb_t* CheckCompaction(rocksdb_t* db, rocksdb_options_t* options, rocksdb_readoptions_t* roptions, rocksdb_writeoptions_t* woptions) { @@ -304,6 +390,8 @@ static rocksdb_t* CheckCompaction(rocksdb_t* db, rocksdb_options_t* options, CheckGet(db, roptions, "foo", "foovalue"); CheckGet(db, roptions, "bar", NULL); CheckGet(db, roptions, "baz", "newbazvalue"); + + GetAndCheckMetaData(db); return db; } @@ -1443,6 +1531,8 @@ int main(int argc, char** argv) { CheckNoError(err); rocksdb_iter_destroy(iter); + GetAndCheckMetaDataCf(db, handles[1], cf_names[1]); + rocksdb_drop_column_family(db, handles[1], &err); CheckNoError(err); for (i = 0; i < 2; i++) { diff --git a/include/rocksdb/c.h b/include/rocksdb/c.h index 93737c4bd..933650d5e 100644 --- a/include/rocksdb/c.h +++ b/include/rocksdb/c.h @@ -110,6 +110,10 @@ typedef struct rocksdb_writeoptions_t rocksdb_writeoptions_t; typedef struct rocksdb_universal_compaction_options_t rocksdb_universal_compaction_options_t; typedef struct rocksdb_livefiles_t rocksdb_livefiles_t; typedef struct rocksdb_column_family_handle_t rocksdb_column_family_handle_t; +typedef struct rocksdb_column_family_metadata_t + rocksdb_column_family_metadata_t; +typedef struct rocksdb_level_metadata_t rocksdb_level_metadata_t; +typedef struct rocksdb_sst_file_metadata_t rocksdb_sst_file_metadata_t; typedef struct rocksdb_envoptions_t rocksdb_envoptions_t; typedef struct rocksdb_ingestexternalfileoptions_t rocksdb_ingestexternalfileoptions_t; typedef struct rocksdb_sstfilewriter_t rocksdb_sstfilewriter_t; @@ -2165,6 +2169,124 @@ extern ROCKSDB_LIBRARY_API void rocksdb_delete_file_in_range_cf( const char* start_key, size_t start_key_len, const char* limit_key, size_t limit_key_len, char** errptr); +/* MetaData */ + +extern ROCKSDB_LIBRARY_API rocksdb_column_family_metadata_t* +rocksdb_get_column_family_metadata(rocksdb_t* db); + +/** + * Returns the rocksdb_column_family_metadata_t of the specified + * column family. + * + * Note that the caller is responsible to release the returned memory + * using rocksdb_column_family_metadata_destroy. + */ +extern ROCKSDB_LIBRARY_API rocksdb_column_family_metadata_t* +rocksdb_get_column_family_metadata_cf( + rocksdb_t* db, rocksdb_column_family_handle_t* column_family); + +extern ROCKSDB_LIBRARY_API void rocksdb_column_family_metadata_destroy( + rocksdb_column_family_metadata_t* cf_meta); + +extern ROCKSDB_LIBRARY_API uint64_t rocksdb_column_family_metadata_get_size( + rocksdb_column_family_metadata_t* cf_meta); + +extern ROCKSDB_LIBRARY_API size_t rocksdb_column_family_metadata_get_file_count( + rocksdb_column_family_metadata_t* cf_meta); + +extern ROCKSDB_LIBRARY_API char* rocksdb_column_family_metadata_get_name( + rocksdb_column_family_metadata_t* cf_meta); + +extern ROCKSDB_LIBRARY_API size_t +rocksdb_column_family_metadata_get_level_count( + rocksdb_column_family_metadata_t* cf_meta); + +/** + * Returns the rocksdb_level_metadata_t of the ith level from the specified + * column family metadata. + * + * If the specified i is greater than or equal to the number of levels + * in the specified column family, then NULL will be returned. + * + * Note that the caller is responsible to release the returned memory + * using rocksdb_level_metadata_destroy before releasing its parent + * rocksdb_column_family_metadata_t. + */ +extern ROCKSDB_LIBRARY_API rocksdb_level_metadata_t* +rocksdb_column_family_metadata_get_level_metadata( + rocksdb_column_family_metadata_t* cf_meta, size_t i); + +/** + * Releases the specified rocksdb_level_metadata_t. + * + * Note that the specified rocksdb_level_metadata_t must be released + * before the release of its parent rocksdb_column_family_metadata_t. + */ +extern ROCKSDB_LIBRARY_API void rocksdb_level_metadata_destroy( + rocksdb_level_metadata_t* level_meta); + +extern ROCKSDB_LIBRARY_API int rocksdb_level_metadata_get_level( + rocksdb_level_metadata_t* level_meta); + +extern ROCKSDB_LIBRARY_API uint64_t +rocksdb_level_metadata_get_size(rocksdb_level_metadata_t* level_meta); + +extern ROCKSDB_LIBRARY_API size_t +rocksdb_level_metadata_get_file_count(rocksdb_level_metadata_t* level_meta); + +/** + * Returns the sst_file_metadata_t of the ith file from the specified level + * metadata. + * + * If the specified i is greater than or equal to the number of files + * in the specified level, then NULL will be returned. + * + * Note that the caller is responsible to release the returned memory + * using rocksdb_sst_file_metadata_destroy before releasing its + * parent rocksdb_level_metadata_t. + */ +extern ROCKSDB_LIBRARY_API rocksdb_sst_file_metadata_t* +rocksdb_level_metadata_get_sst_file_metadata( + rocksdb_level_metadata_t* level_meta, size_t i); + +/** + * Releases the specified rocksdb_sst_file_metadata_t. + * + * Note that the specified rocksdb_sst_file_metadata_t must be released + * before the release of its parent rocksdb_level_metadata_t. + */ +extern ROCKSDB_LIBRARY_API void rocksdb_sst_file_metadata_destroy( + rocksdb_sst_file_metadata_t* file_meta); + +extern ROCKSDB_LIBRARY_API char* +rocksdb_sst_file_metadata_get_relative_filename( + rocksdb_sst_file_metadata_t* file_meta); + +extern ROCKSDB_LIBRARY_API uint64_t +rocksdb_sst_file_metadata_get_size(rocksdb_sst_file_metadata_t* file_meta); + +/** + * Returns the smallest key of the specified sst file. + * The caller is responsible for releasing the returned memory. + * + * @param file_meta the metadata of an SST file to obtain its smallest key. + * @param len the out value which will contain the length of the returned key + * after the function call. + */ +extern ROCKSDB_LIBRARY_API char* rocksdb_sst_file_metadata_get_smallestkey( + rocksdb_sst_file_metadata_t* file_meta, size_t* len); + +/** + * Returns the smallest key of the specified sst file. + * The caller is responsible for releasing the returned memory. + * + * @param file_meta the metadata of an SST file to obtain its smallest key. + * @param len the out value which will contain the length of the returned key + * after the function call. + */ +extern ROCKSDB_LIBRARY_API char* rocksdb_sst_file_metadata_get_largestkey( + rocksdb_sst_file_metadata_t* file_meta, size_t* len); + /* Transactions */ extern ROCKSDB_LIBRARY_API rocksdb_column_family_handle_t*