Move various string utility functions into string_util

Summary:
This is an effort to club all string related utility functions into one common place, in string_util, so that it is easier for everyone to know what string processing functions are available. Right now they seem to be spread out across multiple modules, like logging and options_helper.

Check the sub-commits for easier reviewing.
Closes https://github.com/facebook/rocksdb/pull/2094

Differential Revision: D4837730

Pulled By: sagar0

fbshipit-source-id: 344278a
main
Sagar Vemuri 8 years ago committed by Facebook Github Bot
parent 1d068f6067
commit 343b59d6ee
  1. 1
      CMakeLists.txt
  2. 2
      db/compaction.cc
  3. 2
      db/corruption_test.cc
  4. 3
      db/cuckoo_table_db_test.cc
  5. 1
      db/dbformat.cc
  6. 3
      db/version_edit.cc
  7. 2
      db/version_set.cc
  8. 2
      java/rocksjni/write_batch_test.cc
  9. 2
      monitoring/thread_status_impl.cc
  10. 196
      options/options_helper.cc
  11. 39
      options/options_helper.h
  12. 1
      options/options_test.cc
  13. 1
      src.mk
  14. 2
      table/block_based_filter_block_test.cc
  15. 2
      table/full_filter_block_test.cc
  16. 2
      tools/reduce_levels_test.cc
  17. 164
      util/logging.cc
  18. 46
      util/logging.h
  19. 347
      util/string_util.cc
  20. 98
      util/string_util.h
  21. 1
      utilities/date_tiered/date_tiered_test.cc
  22. 4
      utilities/ttl/ttl_test.cc

@ -413,7 +413,6 @@ set(SOURCES
util/filter_policy.cc util/filter_policy.cc
util/hash.cc util/hash.cc
util/log_buffer.cc util/log_buffer.cc
util/logging.cc
util/murmurhash.cc util/murmurhash.cc
util/random.cc util/random.cc
util/rate_limiter.cc util/rate_limiter.cc

@ -18,7 +18,7 @@
#include "db/column_family.h" #include "db/column_family.h"
#include "rocksdb/compaction_filter.h" #include "rocksdb/compaction_filter.h"
#include "util/logging.h" #include "util/string_util.h"
#include "util/sync_point.h" #include "util/sync_point.h"
namespace rocksdb { namespace rocksdb {

@ -24,7 +24,7 @@
#include "rocksdb/table.h" #include "rocksdb/table.h"
#include "rocksdb/write_batch.h" #include "rocksdb/write_batch.h"
#include "util/filename.h" #include "util/filename.h"
#include "util/logging.h" #include "util/string_util.h"
#include "util/testharness.h" #include "util/testharness.h"
#include "util/testutil.h" #include "util/testutil.h"

@ -8,9 +8,10 @@
#include "db/db_impl.h" #include "db/db_impl.h"
#include "rocksdb/db.h" #include "rocksdb/db.h"
#include "rocksdb/env.h" #include "rocksdb/env.h"
#include "table/meta_blocks.h"
#include "table/cuckoo_table_factory.h" #include "table/cuckoo_table_factory.h"
#include "table/cuckoo_table_reader.h" #include "table/cuckoo_table_reader.h"
#include "table/meta_blocks.h"
#include "util/string_util.h"
#include "util/testharness.h" #include "util/testharness.h"
#include "util/testutil.h" #include "util/testutil.h"

@ -17,6 +17,7 @@
#include "monitoring/perf_context_imp.h" #include "monitoring/perf_context_imp.h"
#include "port/port.h" #include "port/port.h"
#include "util/coding.h" #include "util/coding.h"
#include "util/string_util.h"
namespace rocksdb { namespace rocksdb {

@ -10,10 +10,11 @@
#include "db/version_edit.h" #include "db/version_edit.h"
#include "db/version_set.h" #include "db/version_set.h"
#include "rocksdb/slice.h"
#include "util/coding.h" #include "util/coding.h"
#include "util/event_logger.h" #include "util/event_logger.h"
#include "util/string_util.h"
#include "util/sync_point.h" #include "util/sync_point.h"
#include "rocksdb/slice.h"
namespace rocksdb { namespace rocksdb {

@ -47,8 +47,8 @@
#include "util/coding.h" #include "util/coding.h"
#include "util/file_reader_writer.h" #include "util/file_reader_writer.h"
#include "util/filename.h" #include "util/filename.h"
#include "util/logging.h"
#include "util/stop_watch.h" #include "util/stop_watch.h"
#include "util/string_util.h"
#include "util/sync_point.h" #include "util/sync_point.h"
namespace rocksdb { namespace rocksdb {

@ -22,7 +22,7 @@
#include "rocksdb/write_buffer_manager.h" #include "rocksdb/write_buffer_manager.h"
#include "rocksjni/portal.h" #include "rocksjni/portal.h"
#include "table/scoped_arena_iterator.h" #include "table/scoped_arena_iterator.h"
#include "util/logging.h" #include "util/string_util.h"
#include "util/testharness.h" #include "util/testharness.h"
/* /*

@ -8,7 +8,7 @@
#include "rocksdb/env.h" #include "rocksdb/env.h"
#include "rocksdb/thread_status.h" #include "rocksdb/thread_status.h"
#include "util/logging.h" #include "util/string_util.h"
#include "util/thread_operation.h" #include "util/thread_operation.h"
namespace rocksdb { namespace rocksdb {

@ -21,13 +21,10 @@
#include "rocksdb/table.h" #include "rocksdb/table.h"
#include "table/block_based_table_factory.h" #include "table/block_based_table_factory.h"
#include "table/plain_table_factory.h" #include "table/plain_table_factory.h"
#include "util/logging.h"
#include "util/string_util.h" #include "util/string_util.h"
namespace rocksdb { namespace rocksdb {
const std::string kNullptrString = "nullptr";
DBOptions BuildDBOptions(const ImmutableDBOptions& immutable_db_options, DBOptions BuildDBOptions(const ImmutableDBOptions& immutable_db_options,
const MutableDBOptions& mutable_db_options) { const MutableDBOptions& mutable_db_options) {
DBOptions options; DBOptions options;
@ -178,132 +175,8 @@ ColumnFamilyOptions BuildColumnFamilyOptions(
} }
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
bool isSpecialChar(const char c) {
if (c == '\\' || c == '#' || c == ':' || c == '\r' || c == '\n') {
return true;
}
return false;
}
namespace { namespace {
using
CharMap = std::pair<char, char>;
}
char UnescapeChar(const char c) {
static const CharMap convert_map[] = {{'r', '\r'},
{'n', '\n'}};
auto iter = std::find_if(std::begin(convert_map),
std::end(convert_map),
[c](const CharMap& p) { return p.first == c; });
if (iter == std::end(convert_map)) {
return c;
}
return iter->second;
}
char EscapeChar(const char c) {
static const CharMap convert_map[] = {{'\n', 'n'},
{'\r', 'r'}};
auto iter = std::find_if(std::begin(convert_map),
std::end(convert_map),
[c](const CharMap& p) { return p.first == c; });
if (iter == std::end(convert_map)) {
return c;
}
return iter->second;
}
std::string EscapeOptionString(const std::string& raw_string) {
std::string output;
for (auto c : raw_string) {
if (isSpecialChar(c)) {
output += '\\';
output += EscapeChar(c);
} else {
output += c;
}
}
return output;
}
std::string UnescapeOptionString(const std::string& escaped_string) {
bool escaped = false;
std::string output;
for (auto c : escaped_string) {
if (escaped) {
output += UnescapeChar(c);
escaped = false;
} else {
if (c == '\\') {
escaped = true;
continue;
}
output += c;
}
}
return output;
}
uint64_t ParseUint64(const std::string& value) {
size_t endchar;
#ifndef CYGWIN
uint64_t num = std::stoull(value.c_str(), &endchar);
#else
char* endptr;
uint64_t num = std::strtoul(value.c_str(), &endptr, 0);
endchar = endptr - value.c_str();
#endif
if (endchar < value.length()) {
char c = value[endchar];
if (c == 'k' || c == 'K')
num <<= 10LL;
else if (c == 'm' || c == 'M')
num <<= 20LL;
else if (c == 'g' || c == 'G')
num <<= 30LL;
else if (c == 't' || c == 'T')
num <<= 40LL;
}
return num;
}
namespace {
std::string trim(const std::string& str) {
if (str.empty()) return std::string();
size_t start = 0;
size_t end = str.size() - 1;
while (isspace(str[start]) != 0 && start <= end) {
++start;
}
while (isspace(str[end]) != 0 && start <= end) {
--end;
}
if (start <= end) {
return str.substr(start, end - start + 1);
}
return std::string();
}
bool SerializeIntVector(const std::vector<int>& vec, std::string* value) {
*value = "";
for (size_t i = 0; i < vec.size(); ++i) {
if (i > 0) {
*value += ":";
}
*value += ToString(vec[i]);
}
return true;
}
template <typename T> template <typename T>
bool ParseEnum(const std::unordered_map<std::string, T>& type_map, bool ParseEnum(const std::unordered_map<std::string, T>& type_map,
const std::string& type, T* value) { const std::string& type, T* value) {
@ -347,75 +220,6 @@ bool SerializeVectorCompressionType(const std::vector<CompressionType>& types,
return true; return true;
} }
bool ParseBoolean(const std::string& type, const std::string& value) {
if (value == "true" || value == "1") {
return true;
} else if (value == "false" || value == "0") {
return false;
}
throw std::invalid_argument(type);
}
size_t ParseSizeT(const std::string& value) {
return static_cast<size_t>(ParseUint64(value));
}
uint32_t ParseUint32(const std::string& value) {
uint64_t num = ParseUint64(value);
if ((num >> 32LL) == 0) {
return static_cast<uint32_t>(num);
} else {
throw std::out_of_range(value);
}
}
int ParseInt(const std::string& value) {
size_t endchar;
#ifndef CYGWIN
int num = std::stoi(value.c_str(), &endchar);
#else
char* endptr;
int num = std::strtoul(value.c_str(), &endptr, 0);
endchar = endptr - value.c_str();
#endif
if (endchar < value.length()) {
char c = value[endchar];
if (c == 'k' || c == 'K')
num <<= 10;
else if (c == 'm' || c == 'M')
num <<= 20;
else if (c == 'g' || c == 'G')
num <<= 30;
}
return num;
}
std::vector<int> ParseVectorInt(const std::string& value) {
std::vector<int> result;
size_t start = 0;
while (start < value.size()) {
size_t end = value.find(':', start);
if (end == std::string::npos) {
result.push_back(ParseInt(value.substr(start)));
break;
} else {
result.push_back(ParseInt(value.substr(start, end - start)));
start = end + 1;
}
}
return result;
}
double ParseDouble(const std::string& value) {
#ifndef CYGWIN
return std::stod(value);
#else
return std::strtod(value.c_str(), 0);
#endif
}
bool ParseVectorCompressionType( bool ParseVectorCompressionType(
const std::string& value, const std::string& value,
std::vector<CompressionType>* compression_per_level) { std::vector<CompressionType>* compression_per_level) {

@ -39,44 +39,6 @@ static std::map<CompactionPri, std::string> compaction_pri_to_string = {
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
// Returns true if the input char "c" is considered as a special character
// that will be escaped when EscapeOptionString() is called.
//
// @param c the input char
// @return true if the input char "c" is considered as a special character.
// @see EscapeOptionString
bool isSpecialChar(const char c);
// If the input char is an escaped char, it will return the its
// associated raw-char. Otherwise, the function will simply return
// the original input char.
char UnescapeChar(const char c);
// If the input char is a control char, it will return the its
// associated escaped char. Otherwise, the function will simply return
// the original input char.
char EscapeChar(const char c);
// Converts a raw string to an escaped string. Escaped-characters are
// defined via the isSpecialChar() function. When a char in the input
// string "raw_string" is classified as a special characters, then it
// will be prefixed by '\' in the output.
//
// It's inverse function is UnescapeOptionString().
// @param raw_string the input string
// @return the '\' escaped string of the input "raw_string"
// @see isSpecialChar, UnescapeOptionString
std::string EscapeOptionString(const std::string& raw_string);
// The inverse function of EscapeOptionString. It converts
// an '\' escaped string back to a raw string.
//
// @param escaped_string the input '\' escaped string
// @return the raw string of the input "escaped_string"
std::string UnescapeOptionString(const std::string& escaped_string);
uint64_t ParseUint64(const std::string& value);
Status GetMutableOptionsFromStrings( Status GetMutableOptionsFromStrings(
const MutableCFOptions& base_options, const MutableCFOptions& base_options,
const std::unordered_map<std::string, std::string>& options_map, const std::unordered_map<std::string, std::string>& options_map,
@ -750,7 +712,6 @@ static std::unordered_map<std::string, InfoLogLevel> info_log_level_string_map =
{"FATAL_LEVEL", InfoLogLevel::FATAL_LEVEL}, {"FATAL_LEVEL", InfoLogLevel::FATAL_LEVEL},
{"HEADER_LEVEL", InfoLogLevel::HEADER_LEVEL}}; {"HEADER_LEVEL", InfoLogLevel::HEADER_LEVEL}};
extern const std::string kNullptrString;
#endif // !ROCKSDB_LITE #endif // !ROCKSDB_LITE
} // namespace rocksdb } // namespace rocksdb

@ -25,6 +25,7 @@
#include "rocksdb/utilities/leveldb_options.h" #include "rocksdb/utilities/leveldb_options.h"
#include "util/random.h" #include "util/random.h"
#include "util/stderr_logger.h" #include "util/stderr_logger.h"
#include "util/string_util.h"
#include "util/testharness.h" #include "util/testharness.h"
#include "util/testutil.h" #include "util/testutil.h"

@ -134,7 +134,6 @@ LIB_SOURCES = \
util/filter_policy.cc \ util/filter_policy.cc \
util/hash.cc \ util/hash.cc \
util/log_buffer.cc \ util/log_buffer.cc \
util/logging.cc \
util/murmurhash.cc \ util/murmurhash.cc \
util/random.cc \ util/random.cc \
util/rate_limiter.cc \ util/rate_limiter.cc \

@ -12,7 +12,7 @@
#include "rocksdb/filter_policy.h" #include "rocksdb/filter_policy.h"
#include "util/coding.h" #include "util/coding.h"
#include "util/hash.h" #include "util/hash.h"
#include "util/logging.h" #include "util/string_util.h"
#include "util/testharness.h" #include "util/testharness.h"
#include "util/testutil.h" #include "util/testutil.h"

@ -8,7 +8,7 @@
#include "rocksdb/filter_policy.h" #include "rocksdb/filter_policy.h"
#include "util/coding.h" #include "util/coding.h"
#include "util/hash.h" #include "util/hash.h"
#include "util/logging.h" #include "util/string_util.h"
#include "util/testharness.h" #include "util/testharness.h"
#include "util/testutil.h" #include "util/testutil.h"

@ -11,7 +11,7 @@
#include "rocksdb/db.h" #include "rocksdb/db.h"
#include "rocksdb/utilities/ldb_cmd.h" #include "rocksdb/utilities/ldb_cmd.h"
#include "tools/ldb_cmd_impl.h" #include "tools/ldb_cmd_impl.h"
#include "util/logging.h" #include "util/string_util.h"
#include "util/testharness.h" #include "util/testharness.h"
#include "util/testutil.h" #include "util/testutil.h"

@ -1,164 +0,0 @@
// Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
// This source code is licensed under the BSD-style license found in the
// LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory.
//
// 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 "util/logging.h"
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <cmath>
#include <inttypes.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include "rocksdb/env.h"
#include "rocksdb/slice.h"
namespace rocksdb {
// for micros < 10ms, print "XX us".
// for micros < 10sec, print "XX ms".
// for micros >= 10 sec, print "XX sec".
// for micros <= 1 hour, print Y:X M:S".
// for micros > 1 hour, print Z:Y:X H:M:S".
int AppendHumanMicros(uint64_t micros, char* output, int len,
bool fixed_format) {
if (micros < 10000 && !fixed_format) {
return snprintf(output, len, "%" PRIu64 " us", micros);
} else if (micros < 10000000 && !fixed_format) {
return snprintf(output, len, "%.3lf ms",
static_cast<double>(micros) / 1000);
} else if (micros < 1000000l * 60 && !fixed_format) {
return snprintf(output, len, "%.3lf sec",
static_cast<double>(micros) / 1000000);
} else if (micros < 1000000ll * 60 * 60 && !fixed_format) {
return snprintf(output, len, "%02" PRIu64 ":%05.3f M:S",
micros / 1000000 / 60,
static_cast<double>(micros % 60000000) / 1000000);
} else {
return snprintf(output, len,
"%02" PRIu64 ":%02" PRIu64 ":%05.3f H:M:S",
micros / 1000000 / 3600,
(micros / 1000000 / 60) % 60,
static_cast<double>(micros % 60000000) / 1000000);
}
}
// for sizes >=10TB, print "XXTB"
// for sizes >=10GB, print "XXGB"
// etc.
// append file size summary to output and return the len
int AppendHumanBytes(uint64_t bytes, char* output, int len) {
const uint64_t ull10 = 10;
if (bytes >= ull10 << 40) {
return snprintf(output, len, "%" PRIu64 "TB", bytes >> 40);
} else if (bytes >= ull10 << 30) {
return snprintf(output, len, "%" PRIu64 "GB", bytes >> 30);
} else if (bytes >= ull10 << 20) {
return snprintf(output, len, "%" PRIu64 "MB", bytes >> 20);
} else if (bytes >= ull10 << 10) {
return snprintf(output, len, "%" PRIu64 "KB", bytes >> 10);
} else {
return snprintf(output, len, "%" PRIu64 "B", bytes);
}
}
void AppendNumberTo(std::string* str, uint64_t num) {
char buf[30];
snprintf(buf, sizeof(buf), "%" PRIu64, num);
str->append(buf);
}
void AppendEscapedStringTo(std::string* str, const Slice& value) {
for (size_t i = 0; i < value.size(); i++) {
char c = value[i];
if (c >= ' ' && c <= '~') {
str->push_back(c);
} else {
char buf[10];
snprintf(buf, sizeof(buf), "\\x%02x",
static_cast<unsigned int>(c) & 0xff);
str->append(buf);
}
}
}
std::string NumberToString(uint64_t num) {
std::string r;
AppendNumberTo(&r, num);
return r;
}
std::string NumberToHumanString(int64_t num) {
char buf[19];
int64_t absnum = num < 0 ? -num : num;
if (absnum < 10000) {
snprintf(buf, sizeof(buf), "%" PRIi64, num);
} else if (absnum < 10000000) {
snprintf(buf, sizeof(buf), "%" PRIi64 "K", num / 1000);
} else if (absnum < 10000000000LL) {
snprintf(buf, sizeof(buf), "%" PRIi64 "M", num / 1000000);
} else {
snprintf(buf, sizeof(buf), "%" PRIi64 "G", num / 1000000000);
}
return std::string(buf);
}
std::string BytesToHumanString(uint64_t bytes) {
const char* size_name[] = {"KB", "MB", "GB", "TB"};
double final_size = static_cast<double>(bytes);
size_t size_idx;
// always start with KB
final_size /= 1024;
size_idx = 0;
while (size_idx < 3 && final_size >= 1024) {
final_size /= 1024;
size_idx++;
}
char buf[20];
snprintf(buf, sizeof(buf), "%.2f %s", final_size, size_name[size_idx]);
return std::string(buf);
}
std::string EscapeString(const Slice& value) {
std::string r;
AppendEscapedStringTo(&r, value);
return r;
}
bool ConsumeDecimalNumber(Slice* in, uint64_t* val) {
uint64_t v = 0;
int digits = 0;
while (!in->empty()) {
char c = (*in)[0];
if (c >= '0' && c <= '9') {
++digits;
const unsigned int delta = (c - '0');
static const uint64_t kMaxUint64 = ~static_cast<uint64_t>(0);
if (v > kMaxUint64/10 ||
(v == kMaxUint64/10 && delta > kMaxUint64%10)) {
// Overflow
return false;
}
v = (v * 10) + delta;
in->remove_prefix(1);
} else {
break;
}
}
*val = v;
return (digits > 0);
}
} // namespace rocksdb

@ -11,9 +11,6 @@
// with macros. // with macros.
#pragma once #pragma once
#include <stdio.h>
#include <stdint.h>
#include <string>
#include "port/port.h" #include "port/port.h"
// Helper macros that include information about file name and line number // Helper macros that include information about file name and line number
@ -51,46 +48,3 @@
#define ROCKS_LOG_BUFFER_MAX_SZ(LOG_BUF, MAX_LOG_SIZE, FMT, ...) \ #define ROCKS_LOG_BUFFER_MAX_SZ(LOG_BUF, MAX_LOG_SIZE, FMT, ...) \
rocksdb::LogToBuffer(LOG_BUF, MAX_LOG_SIZE, PREPEND_FILE_LINE(FMT), \ rocksdb::LogToBuffer(LOG_BUF, MAX_LOG_SIZE, PREPEND_FILE_LINE(FMT), \
##__VA_ARGS__) ##__VA_ARGS__)
namespace rocksdb {
class Slice;
// Append a human-readable time in micros.
int AppendHumanMicros(uint64_t micros, char* output, int len,
bool fixed_format);
// Append a human-readable size in bytes
int AppendHumanBytes(uint64_t bytes, char* output, int len);
// Append a human-readable printout of "num" to *str
extern void AppendNumberTo(std::string* str, uint64_t num);
// Append a human-readable printout of "value" to *str.
// Escapes any non-printable characters found in "value".
extern void AppendEscapedStringTo(std::string* str, const Slice& value);
// Return a string printout of "num"
extern std::string NumberToString(uint64_t num);
// Return a human-readable version of num.
// for num >= 10.000, prints "xxK"
// for num >= 10.000.000, prints "xxM"
// for num >= 10.000.000.000, prints "xxG"
extern std::string NumberToHumanString(int64_t num);
// Return a human-readable version of bytes
// ex: 1048576 -> 1.00 GB
extern std::string BytesToHumanString(uint64_t bytes);
// Return a human-readable version of "value".
// Escapes any non-printable characters found in "value".
extern std::string EscapeString(const Slice& value);
// Parse a human-readable number from "*in" into *value. On success,
// advances "*in" past the consumed number and sets "*val" to the
// numeric value. Otherwise, returns false and leaves *in in an
// unspecified state.
extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val);
} // namespace rocksdb

@ -3,13 +3,30 @@
// LICENSE file in the root directory of this source tree. An additional grant // LICENSE file in the root directory of this source tree. An additional grant
// of patent rights can be found in the PATENTS file in the same directory. // of patent rights can be found in the PATENTS file in the same directory.
// //
#include "util/string_util.h"
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <errno.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <cmath>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <utility>
#include <vector> #include <vector>
#include "util/string_util.h" #include "rocksdb/env.h"
#include "rocksdb/slice.h"
namespace rocksdb { namespace rocksdb {
const std::string kNullptrString = "nullptr";
std::vector<std::string> StringSplit(const std::string& arg, char delim) { std::vector<std::string> StringSplit(const std::string& arg, char delim) {
std::vector<std::string> splits; std::vector<std::string> splits;
std::stringstream ss(arg); std::stringstream ss(arg);
@ -20,4 +37,332 @@ std::vector<std::string> StringSplit(const std::string& arg, char delim) {
return splits; return splits;
} }
// for micros < 10ms, print "XX us".
// for micros < 10sec, print "XX ms".
// for micros >= 10 sec, print "XX sec".
// for micros <= 1 hour, print Y:X M:S".
// for micros > 1 hour, print Z:Y:X H:M:S".
int AppendHumanMicros(uint64_t micros, char* output, int len,
bool fixed_format) {
if (micros < 10000 && !fixed_format) {
return snprintf(output, len, "%" PRIu64 " us", micros);
} else if (micros < 10000000 && !fixed_format) {
return snprintf(output, len, "%.3lf ms",
static_cast<double>(micros) / 1000);
} else if (micros < 1000000l * 60 && !fixed_format) {
return snprintf(output, len, "%.3lf sec",
static_cast<double>(micros) / 1000000);
} else if (micros < 1000000ll * 60 * 60 && !fixed_format) {
return snprintf(output, len, "%02" PRIu64 ":%05.3f M:S",
micros / 1000000 / 60,
static_cast<double>(micros % 60000000) / 1000000);
} else {
return snprintf(output, len, "%02" PRIu64 ":%02" PRIu64 ":%05.3f H:M:S",
micros / 1000000 / 3600, (micros / 1000000 / 60) % 60,
static_cast<double>(micros % 60000000) / 1000000);
}
}
// for sizes >=10TB, print "XXTB"
// for sizes >=10GB, print "XXGB"
// etc.
// append file size summary to output and return the len
int AppendHumanBytes(uint64_t bytes, char* output, int len) {
const uint64_t ull10 = 10;
if (bytes >= ull10 << 40) {
return snprintf(output, len, "%" PRIu64 "TB", bytes >> 40);
} else if (bytes >= ull10 << 30) {
return snprintf(output, len, "%" PRIu64 "GB", bytes >> 30);
} else if (bytes >= ull10 << 20) {
return snprintf(output, len, "%" PRIu64 "MB", bytes >> 20);
} else if (bytes >= ull10 << 10) {
return snprintf(output, len, "%" PRIu64 "KB", bytes >> 10);
} else {
return snprintf(output, len, "%" PRIu64 "B", bytes);
}
}
void AppendNumberTo(std::string* str, uint64_t num) {
char buf[30];
snprintf(buf, sizeof(buf), "%" PRIu64, num);
str->append(buf);
}
void AppendEscapedStringTo(std::string* str, const Slice& value) {
for (size_t i = 0; i < value.size(); i++) {
char c = value[i];
if (c >= ' ' && c <= '~') {
str->push_back(c);
} else {
char buf[10];
snprintf(buf, sizeof(buf), "\\x%02x",
static_cast<unsigned int>(c) & 0xff);
str->append(buf);
}
}
}
std::string NumberToString(uint64_t num) {
std::string r;
AppendNumberTo(&r, num);
return r;
}
std::string NumberToHumanString(int64_t num) {
char buf[19];
int64_t absnum = num < 0 ? -num : num;
if (absnum < 10000) {
snprintf(buf, sizeof(buf), "%" PRIi64, num);
} else if (absnum < 10000000) {
snprintf(buf, sizeof(buf), "%" PRIi64 "K", num / 1000);
} else if (absnum < 10000000000LL) {
snprintf(buf, sizeof(buf), "%" PRIi64 "M", num / 1000000);
} else {
snprintf(buf, sizeof(buf), "%" PRIi64 "G", num / 1000000000);
}
return std::string(buf);
}
std::string BytesToHumanString(uint64_t bytes) {
const char* size_name[] = {"KB", "MB", "GB", "TB"};
double final_size = static_cast<double>(bytes);
size_t size_idx;
// always start with KB
final_size /= 1024;
size_idx = 0;
while (size_idx < 3 && final_size >= 1024) {
final_size /= 1024;
size_idx++;
}
char buf[20];
snprintf(buf, sizeof(buf), "%.2f %s", final_size, size_name[size_idx]);
return std::string(buf);
}
std::string EscapeString(const Slice& value) {
std::string r;
AppendEscapedStringTo(&r, value);
return r;
}
bool ConsumeDecimalNumber(Slice* in, uint64_t* val) {
uint64_t v = 0;
int digits = 0;
while (!in->empty()) {
char c = (*in)[0];
if (c >= '0' && c <= '9') {
++digits;
const unsigned int delta = (c - '0');
static const uint64_t kMaxUint64 = ~static_cast<uint64_t>(0);
if (v > kMaxUint64 / 10 ||
(v == kMaxUint64 / 10 && delta > kMaxUint64 % 10)) {
// Overflow
return false;
}
v = (v * 10) + delta;
in->remove_prefix(1);
} else {
break;
}
}
*val = v;
return (digits > 0);
}
bool isSpecialChar(const char c) {
if (c == '\\' || c == '#' || c == ':' || c == '\r' || c == '\n') {
return true;
}
return false;
}
namespace {
using CharMap = std::pair<char, char>;
}
char UnescapeChar(const char c) {
static const CharMap convert_map[] = {{'r', '\r'}, {'n', '\n'}};
auto iter = std::find_if(std::begin(convert_map), std::end(convert_map),
[c](const CharMap& p) { return p.first == c; });
if (iter == std::end(convert_map)) {
return c;
}
return iter->second;
}
char EscapeChar(const char c) {
static const CharMap convert_map[] = {{'\n', 'n'}, {'\r', 'r'}};
auto iter = std::find_if(std::begin(convert_map), std::end(convert_map),
[c](const CharMap& p) { return p.first == c; });
if (iter == std::end(convert_map)) {
return c;
}
return iter->second;
}
std::string EscapeOptionString(const std::string& raw_string) {
std::string output;
for (auto c : raw_string) {
if (isSpecialChar(c)) {
output += '\\';
output += EscapeChar(c);
} else {
output += c;
}
}
return output;
}
std::string UnescapeOptionString(const std::string& escaped_string) {
bool escaped = false;
std::string output;
for (auto c : escaped_string) {
if (escaped) {
output += UnescapeChar(c);
escaped = false;
} else {
if (c == '\\') {
escaped = true;
continue;
}
output += c;
}
}
return output;
}
std::string trim(const std::string& str) {
if (str.empty()) return std::string();
size_t start = 0;
size_t end = str.size() - 1;
while (isspace(str[start]) != 0 && start <= end) {
++start;
}
while (isspace(str[end]) != 0 && start <= end) {
--end;
}
if (start <= end) {
return str.substr(start, end - start + 1);
}
return std::string();
}
#ifndef ROCKSDB_LITE
bool ParseBoolean(const std::string& type, const std::string& value) {
if (value == "true" || value == "1") {
return true;
} else if (value == "false" || value == "0") {
return false;
}
throw std::invalid_argument(type);
}
uint32_t ParseUint32(const std::string& value) {
uint64_t num = ParseUint64(value);
if ((num >> 32LL) == 0) {
return static_cast<uint32_t>(num);
} else {
throw std::out_of_range(value);
}
}
#endif
uint64_t ParseUint64(const std::string& value) {
size_t endchar;
#ifndef CYGWIN
uint64_t num = std::stoull(value.c_str(), &endchar);
#else
char* endptr;
uint64_t num = std::strtoul(value.c_str(), &endptr, 0);
endchar = endptr - value.c_str();
#endif
if (endchar < value.length()) {
char c = value[endchar];
if (c == 'k' || c == 'K')
num <<= 10LL;
else if (c == 'm' || c == 'M')
num <<= 20LL;
else if (c == 'g' || c == 'G')
num <<= 30LL;
else if (c == 't' || c == 'T')
num <<= 40LL;
}
return num;
}
int ParseInt(const std::string& value) {
size_t endchar;
#ifndef CYGWIN
int num = std::stoi(value.c_str(), &endchar);
#else
char* endptr;
int num = std::strtoul(value.c_str(), &endptr, 0);
endchar = endptr - value.c_str();
#endif
if (endchar < value.length()) {
char c = value[endchar];
if (c == 'k' || c == 'K')
num <<= 10;
else if (c == 'm' || c == 'M')
num <<= 20;
else if (c == 'g' || c == 'G')
num <<= 30;
}
return num;
}
double ParseDouble(const std::string& value) {
#ifndef CYGWIN
return std::stod(value);
#else
return std::strtod(value.c_str(), 0);
#endif
}
size_t ParseSizeT(const std::string& value) {
return static_cast<size_t>(ParseUint64(value));
}
std::vector<int> ParseVectorInt(const std::string& value) {
std::vector<int> result;
size_t start = 0;
while (start < value.size()) {
size_t end = value.find(':', start);
if (end == std::string::npos) {
result.push_back(ParseInt(value.substr(start)));
break;
} else {
result.push_back(ParseInt(value.substr(start, end - start)));
start = end + 1;
}
}
return result;
}
bool SerializeIntVector(const std::vector<int>& vec, std::string* value) {
*value = "";
for (size_t i = 0; i < vec.size(); ++i) {
if (i > 0) {
*value += ":";
}
*value += ToString(vec[i]);
}
return true;
}
} // namespace rocksdb } // namespace rocksdb

@ -8,10 +8,13 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <unordered_map>
#include <vector> #include <vector>
namespace rocksdb { namespace rocksdb {
class Slice;
extern std::vector<std::string> StringSplit(const std::string& arg, char delim); extern std::vector<std::string> StringSplit(const std::string& arg, char delim);
template <typename T> template <typename T>
@ -27,4 +30,99 @@ inline std::string ToString(T value) {
#endif #endif
} }
// Append a human-readable printout of "num" to *str
extern void AppendNumberTo(std::string* str, uint64_t num);
// Append a human-readable printout of "value" to *str.
// Escapes any non-printable characters found in "value".
extern void AppendEscapedStringTo(std::string* str, const Slice& value);
// Return a string printout of "num"
extern std::string NumberToString(uint64_t num);
// Return a human-readable version of num.
// for num >= 10.000, prints "xxK"
// for num >= 10.000.000, prints "xxM"
// for num >= 10.000.000.000, prints "xxG"
extern std::string NumberToHumanString(int64_t num);
// Return a human-readable version of bytes
// ex: 1048576 -> 1.00 GB
extern std::string BytesToHumanString(uint64_t bytes);
// Append a human-readable time in micros.
int AppendHumanMicros(uint64_t micros, char* output, int len,
bool fixed_format);
// Append a human-readable size in bytes
int AppendHumanBytes(uint64_t bytes, char* output, int len);
// Return a human-readable version of "value".
// Escapes any non-printable characters found in "value".
extern std::string EscapeString(const Slice& value);
// Parse a human-readable number from "*in" into *value. On success,
// advances "*in" past the consumed number and sets "*val" to the
// numeric value. Otherwise, returns false and leaves *in in an
// unspecified state.
extern bool ConsumeDecimalNumber(Slice* in, uint64_t* val);
// Returns true if the input char "c" is considered as a special character
// that will be escaped when EscapeOptionString() is called.
//
// @param c the input char
// @return true if the input char "c" is considered as a special character.
// @see EscapeOptionString
bool isSpecialChar(const char c);
// If the input char is an escaped char, it will return the its
// associated raw-char. Otherwise, the function will simply return
// the original input char.
char UnescapeChar(const char c);
// If the input char is a control char, it will return the its
// associated escaped char. Otherwise, the function will simply return
// the original input char.
char EscapeChar(const char c);
// Converts a raw string to an escaped string. Escaped-characters are
// defined via the isSpecialChar() function. When a char in the input
// string "raw_string" is classified as a special characters, then it
// will be prefixed by '\' in the output.
//
// It's inverse function is UnescapeOptionString().
// @param raw_string the input string
// @return the '\' escaped string of the input "raw_string"
// @see isSpecialChar, UnescapeOptionString
std::string EscapeOptionString(const std::string& raw_string);
// The inverse function of EscapeOptionString. It converts
// an '\' escaped string back to a raw string.
//
// @param escaped_string the input '\' escaped string
// @return the raw string of the input "escaped_string"
std::string UnescapeOptionString(const std::string& escaped_string);
std::string trim(const std::string& str);
#ifndef ROCKSDB_LITE
bool ParseBoolean(const std::string& type, const std::string& value);
uint32_t ParseUint32(const std::string& value);
#endif
uint64_t ParseUint64(const std::string& value);
int ParseInt(const std::string& value);
double ParseDouble(const std::string& value);
size_t ParseSizeT(const std::string& value);
std::vector<int> ParseVectorInt(const std::string& value);
bool SerializeIntVector(const std::vector<int>& vec, std::string* value);
extern const std::string kNullptrString;
} // namespace rocksdb } // namespace rocksdb

@ -14,6 +14,7 @@
#include "rocksdb/compaction_filter.h" #include "rocksdb/compaction_filter.h"
#include "rocksdb/utilities/date_tiered_db.h" #include "rocksdb/utilities/date_tiered_db.h"
#include "util/logging.h" #include "util/logging.h"
#include "util/string_util.h"
#include "util/testharness.h" #include "util/testharness.h"
namespace rocksdb { namespace rocksdb {

@ -4,12 +4,12 @@
#ifndef ROCKSDB_LITE #ifndef ROCKSDB_LITE
#include <map>
#include <memory> #include <memory>
#include "rocksdb/compaction_filter.h" #include "rocksdb/compaction_filter.h"
#include "rocksdb/utilities/db_ttl.h" #include "rocksdb/utilities/db_ttl.h"
#include "util/string_util.h"
#include "util/testharness.h" #include "util/testharness.h"
#include "util/logging.h"
#include <map>
#ifndef OS_WIN #ifndef OS_WIN
#include <unistd.h> #include <unistd.h>
#endif #endif

Loading…
Cancel
Save