diff --git a/db/db_bench.cc b/db/db_bench.cc index 176927ba6..e31270cc9 100644 --- a/db/db_bench.cc +++ b/db/db_bench.cc @@ -7,10 +7,12 @@ #include #include "db/db_impl.h" #include "db/version_set.h" +#include "db/db_statistics.h" #include "leveldb/cache.h" #include "leveldb/db.h" #include "leveldb/env.h" #include "leveldb/write_batch.h" +#include "leveldb/statistics.h" #include "port/port.h" #include "util/crc32c.h" #include "util/histogram.h" @@ -110,6 +112,10 @@ static int FLAGS_cache_numshardbits = -1; // Verify checksum for every block read from storage static bool FLAGS_verify_checksum = false; +// Database statistics +static bool FLAGS_statistics = false; +static class leveldb::DBStatistics* dbstats = NULL; + extern bool useOsBuffer; namespace leveldb { @@ -398,6 +404,15 @@ class Benchmark { #endif } + void PrintStatistics() { + if (FLAGS_statistics) { + fprintf(stdout, "File opened:%ld closed:%ld errors:%ld\n", + dbstats->getNumFileOpens(), + dbstats->getNumFileCloses(), + dbstats->getNumFileErrors()); + } + } + public: Benchmark() : cache_(FLAGS_cache_size >= 0 ? @@ -542,6 +557,7 @@ class Benchmark { RunBenchmark(num_threads, name, method); } } + PrintStatistics(); } private: @@ -710,6 +726,8 @@ class Benchmark { options.block_cache = cache_; options.write_buffer_size = FLAGS_write_buffer_size; options.filter_policy = filter_policy_; + options.max_open_files = FLAGS_open_files; + options.statistics = dbstats; Status s = DB::Open(options, FLAGS_db, &db_); if (!s.ok()) { fprintf(stderr, "open error: %s\n", s.ToString().c_str()); @@ -983,6 +1001,12 @@ int main(int argc, char** argv) { } else if (sscanf(argv[i], "--bufferedio=%d%c", &n, &junk) == 1 && (n == 0 || n == 1)) { useOsBuffer = n; + } else if (sscanf(argv[i], "--statistics=%d%c", &n, &junk) == 1 && + (n == 0 || n == 1)) { + if (n == 1) { + dbstats = new leveldb::DBStatistics(); + FLAGS_statistics = true; + } } else { fprintf(stderr, "Invalid flag '%s'\n", argv[i]); exit(1); diff --git a/db/db_statistics.h b/db/db_statistics.h new file mode 100644 index 000000000..350d52c2a --- /dev/null +++ b/db/db_statistics.h @@ -0,0 +1,36 @@ +// 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. + +#include +#include "leveldb/statistics.h" +#include "port/port.h" +#include "util/mutexlock.h" + +namespace leveldb { + +class DBStatistics: public Statistics { + public: + DBStatistics() { } + + void incNumFileOpens() { + MutexLock l(&mu_); + numFileOpens_++; + } + + void incNumFileCloses() { + MutexLock l(&mu_); + numFileCloses_++; + } + + void incNumFileErrors() { + MutexLock l(&mu_); + numFileErrors_++; + } + + private: + port::Mutex mu_; +}; +} + + diff --git a/db/table_cache.cc b/db/table_cache.cc index 497db2707..0e4061e66 100644 --- a/db/table_cache.cc +++ b/db/table_cache.cc @@ -5,6 +5,7 @@ #include "db/table_cache.h" #include "db/filename.h" +#include "db/db_statistics.h" #include "leveldb/env.h" #include "leveldb/table.h" #include "util/coding.h" @@ -16,10 +17,13 @@ struct TableAndFile { Table* table; }; +static class DBStatistics* dbstatistics; + static void DeleteEntry(const Slice& key, void* value) { TableAndFile* tf = reinterpret_cast(value); delete tf->table; delete tf->file; + dbstatistics ? dbstatistics->incNumFileCloses() : (void)0; delete tf; } @@ -36,6 +40,7 @@ TableCache::TableCache(const std::string& dbname, dbname_(dbname), options_(options), cache_(NewLRUCache(entries)) { + dbstatistics = (DBStatistics*)options->statistics; } TableCache::~TableCache() { @@ -48,12 +53,14 @@ Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, char buf[sizeof(file_number)]; EncodeFixed64(buf, file_number); Slice key(buf, sizeof(buf)); + DBStatistics* stats = (DBStatistics*) options_->statistics; *handle = cache_->Lookup(key); if (*handle == NULL) { std::string fname = TableFileName(dbname_, file_number); RandomAccessFile* file = NULL; Table* table = NULL; s = env_->NewRandomAccessFile(fname, &file); + stats ? stats->incNumFileOpens() : (void)0; if (s.ok()) { s = Table::Open(*options_, file, file_size, &table); } @@ -61,6 +68,7 @@ Status TableCache::FindTable(uint64_t file_number, uint64_t file_size, if (!s.ok()) { assert(table == NULL); delete file; + stats ? stats->incNumFileErrors() : (void)0; // We do not cache error results so that if the error is transient, // or somebody repairs the file, we recover automatically. } else { diff --git a/include/leveldb/options.h b/include/leveldb/options.h index 83fede3e6..597d49eb8 100644 --- a/include/leveldb/options.h +++ b/include/leveldb/options.h @@ -15,6 +15,7 @@ class Env; class FilterPolicy; class Logger; class Snapshot; +class Statistics; // DB contents are stored in a set of blocks, each of which holds a // sequence of key,value pairs. Each block may be compressed before @@ -135,6 +136,9 @@ struct Options { // Default: NULL const FilterPolicy* filter_policy; + // If non-null, then we should collect metrics about database operations + Statistics* statistics; + // Create an Options object with default values for all fields. Options(); }; diff --git a/include/leveldb/statistics.h b/include/leveldb/statistics.h new file mode 100644 index 000000000..4684f88ef --- /dev/null +++ b/include/leveldb/statistics.h @@ -0,0 +1,33 @@ +// 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. + +#ifndef STORAGE_LEVELDB_INCLUDE_STATISTICS_H_ +#define STORAGE_LEVELDB_INCLUDE_STATISTICS_H_ + +namespace leveldb { + +// Analyze the performance of a db +class Statistics { + public: + // Create an Statistics object with default values for all fields. + Statistics() : numFileOpens_(0), numFileCloses_(0), + numFileErrors_(0) {} + + virtual void incNumFileOpens() = 0; + virtual void incNumFileCloses() = 0; + virtual void incNumFileErrors() = 0; + + virtual long getNumFileOpens() { return numFileOpens_;} + virtual long getNumFileCloses() { return numFileCloses_;} + virtual long getNumFileErrors() { return numFileErrors_;} + + protected: + long numFileOpens_; + long numFileCloses_; + long numFileErrors_; +}; + +} // namespace leveldb + +#endif // STORAGE_LEVELDB_INCLUDE_STATISTICS_H_