diff --git a/CMakeLists.txt b/CMakeLists.txt index fab8397e9..428e23843 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -413,7 +413,6 @@ set(SOURCES util/filter_policy.cc util/hash.cc util/log_buffer.cc - util/logging.cc util/murmurhash.cc util/random.cc util/rate_limiter.cc diff --git a/db/compaction.cc b/db/compaction.cc index 1096133f0..315edaf8a 100644 --- a/db/compaction.cc +++ b/db/compaction.cc @@ -18,7 +18,7 @@ #include "db/column_family.h" #include "rocksdb/compaction_filter.h" -#include "util/logging.h" +#include "util/string_util.h" #include "util/sync_point.h" namespace rocksdb { diff --git a/db/corruption_test.cc b/db/corruption_test.cc index 1a2e906be..2349f0a94 100644 --- a/db/corruption_test.cc +++ b/db/corruption_test.cc @@ -24,7 +24,7 @@ #include "rocksdb/table.h" #include "rocksdb/write_batch.h" #include "util/filename.h" -#include "util/logging.h" +#include "util/string_util.h" #include "util/testharness.h" #include "util/testutil.h" diff --git a/db/cuckoo_table_db_test.cc b/db/cuckoo_table_db_test.cc index 1a75de6dd..e8f206d23 100644 --- a/db/cuckoo_table_db_test.cc +++ b/db/cuckoo_table_db_test.cc @@ -8,9 +8,10 @@ #include "db/db_impl.h" #include "rocksdb/db.h" #include "rocksdb/env.h" -#include "table/meta_blocks.h" #include "table/cuckoo_table_factory.h" #include "table/cuckoo_table_reader.h" +#include "table/meta_blocks.h" +#include "util/string_util.h" #include "util/testharness.h" #include "util/testutil.h" diff --git a/db/dbformat.cc b/db/dbformat.cc index ce1553be5..7298f1df1 100644 --- a/db/dbformat.cc +++ b/db/dbformat.cc @@ -17,6 +17,7 @@ #include "monitoring/perf_context_imp.h" #include "port/port.h" #include "util/coding.h" +#include "util/string_util.h" namespace rocksdb { diff --git a/db/version_edit.cc b/db/version_edit.cc index a030b6793..7a207d4ca 100644 --- a/db/version_edit.cc +++ b/db/version_edit.cc @@ -10,10 +10,11 @@ #include "db/version_edit.h" #include "db/version_set.h" +#include "rocksdb/slice.h" #include "util/coding.h" #include "util/event_logger.h" +#include "util/string_util.h" #include "util/sync_point.h" -#include "rocksdb/slice.h" namespace rocksdb { diff --git a/db/version_set.cc b/db/version_set.cc index ef650b8b5..96254a94d 100644 --- a/db/version_set.cc +++ b/db/version_set.cc @@ -47,8 +47,8 @@ #include "util/coding.h" #include "util/file_reader_writer.h" #include "util/filename.h" -#include "util/logging.h" #include "util/stop_watch.h" +#include "util/string_util.h" #include "util/sync_point.h" namespace rocksdb { diff --git a/java/rocksjni/write_batch_test.cc b/java/rocksjni/write_batch_test.cc index 695355594..e9e945a52 100644 --- a/java/rocksjni/write_batch_test.cc +++ b/java/rocksjni/write_batch_test.cc @@ -22,7 +22,7 @@ #include "rocksdb/write_buffer_manager.h" #include "rocksjni/portal.h" #include "table/scoped_arena_iterator.h" -#include "util/logging.h" +#include "util/string_util.h" #include "util/testharness.h" /* diff --git a/monitoring/thread_status_impl.cc b/monitoring/thread_status_impl.cc index 88ab0119b..6c5d9cc3e 100644 --- a/monitoring/thread_status_impl.cc +++ b/monitoring/thread_status_impl.cc @@ -8,7 +8,7 @@ #include "rocksdb/env.h" #include "rocksdb/thread_status.h" -#include "util/logging.h" +#include "util/string_util.h" #include "util/thread_operation.h" namespace rocksdb { diff --git a/options/options_helper.cc b/options/options_helper.cc index 9c9fd2fb0..15ee46c92 100644 --- a/options/options_helper.cc +++ b/options/options_helper.cc @@ -21,13 +21,10 @@ #include "rocksdb/table.h" #include "table/block_based_table_factory.h" #include "table/plain_table_factory.h" -#include "util/logging.h" #include "util/string_util.h" namespace rocksdb { -const std::string kNullptrString = "nullptr"; - DBOptions BuildDBOptions(const ImmutableDBOptions& immutable_db_options, const MutableDBOptions& mutable_db_options) { DBOptions options; @@ -178,132 +175,8 @@ ColumnFamilyOptions BuildColumnFamilyOptions( } #ifndef ROCKSDB_LITE -bool isSpecialChar(const char c) { - if (c == '\\' || c == '#' || c == ':' || c == '\r' || c == '\n') { - return true; - } - return false; -} - -namespace { - using - CharMap = std::pair; -} - -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& 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 bool ParseEnum(const std::unordered_map& type_map, const std::string& type, T* value) { @@ -347,75 +220,6 @@ bool SerializeVectorCompressionType(const std::vector& types, 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(ParseUint64(value)); -} - -uint32_t ParseUint32(const std::string& value) { - uint64_t num = ParseUint64(value); - if ((num >> 32LL) == 0) { - return static_cast(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 ParseVectorInt(const std::string& value) { - std::vector 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( const std::string& value, std::vector* compression_per_level) { diff --git a/options/options_helper.h b/options/options_helper.h index 93160d47f..23d6dc4e2 100644 --- a/options/options_helper.h +++ b/options/options_helper.h @@ -39,44 +39,6 @@ static std::map compaction_pri_to_string = { #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( const MutableCFOptions& base_options, const std::unordered_map& options_map, @@ -750,7 +712,6 @@ static std::unordered_map info_log_level_string_map = {"FATAL_LEVEL", InfoLogLevel::FATAL_LEVEL}, {"HEADER_LEVEL", InfoLogLevel::HEADER_LEVEL}}; -extern const std::string kNullptrString; #endif // !ROCKSDB_LITE } // namespace rocksdb diff --git a/options/options_test.cc b/options/options_test.cc index bc86c8131..73acc2c1a 100644 --- a/options/options_test.cc +++ b/options/options_test.cc @@ -25,6 +25,7 @@ #include "rocksdb/utilities/leveldb_options.h" #include "util/random.h" #include "util/stderr_logger.h" +#include "util/string_util.h" #include "util/testharness.h" #include "util/testutil.h" diff --git a/src.mk b/src.mk index ca776dd0f..77c95d9e3 100644 --- a/src.mk +++ b/src.mk @@ -134,7 +134,6 @@ LIB_SOURCES = \ util/filter_policy.cc \ util/hash.cc \ util/log_buffer.cc \ - util/logging.cc \ util/murmurhash.cc \ util/random.cc \ util/rate_limiter.cc \ diff --git a/table/block_based_filter_block_test.cc b/table/block_based_filter_block_test.cc index c28b0008d..f94f950a0 100644 --- a/table/block_based_filter_block_test.cc +++ b/table/block_based_filter_block_test.cc @@ -12,7 +12,7 @@ #include "rocksdb/filter_policy.h" #include "util/coding.h" #include "util/hash.h" -#include "util/logging.h" +#include "util/string_util.h" #include "util/testharness.h" #include "util/testutil.h" diff --git a/table/full_filter_block_test.cc b/table/full_filter_block_test.cc index 51ce1aaa9..40affe52a 100644 --- a/table/full_filter_block_test.cc +++ b/table/full_filter_block_test.cc @@ -8,7 +8,7 @@ #include "rocksdb/filter_policy.h" #include "util/coding.h" #include "util/hash.h" -#include "util/logging.h" +#include "util/string_util.h" #include "util/testharness.h" #include "util/testutil.h" diff --git a/tools/reduce_levels_test.cc b/tools/reduce_levels_test.cc index ee0f9ca0a..75638e59b 100644 --- a/tools/reduce_levels_test.cc +++ b/tools/reduce_levels_test.cc @@ -11,7 +11,7 @@ #include "rocksdb/db.h" #include "rocksdb/utilities/ldb_cmd.h" #include "tools/ldb_cmd_impl.h" -#include "util/logging.h" +#include "util/string_util.h" #include "util/testharness.h" #include "util/testutil.h" diff --git a/util/logging.cc b/util/logging.cc deleted file mode 100644 index 1281dc9b5..000000000 --- a/util/logging.cc +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#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(micros) / 1000); - } else if (micros < 1000000l * 60 && !fixed_format) { - return snprintf(output, len, "%.3lf sec", - static_cast(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(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(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(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(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(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 diff --git a/util/logging.h b/util/logging.h index 2aae6a3c0..ec64f4b18 100644 --- a/util/logging.h +++ b/util/logging.h @@ -11,9 +11,6 @@ // with macros. #pragma once -#include -#include -#include #include "port/port.h" // 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, ...) \ rocksdb::LogToBuffer(LOG_BUF, MAX_LOG_SIZE, PREPEND_FILE_LINE(FMT), \ ##__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 diff --git a/util/string_util.cc b/util/string_util.cc index d1830d27e..58f1a3ada 100644 --- a/util/string_util.cc +++ b/util/string_util.cc @@ -3,13 +3,30 @@ // 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. // +#include "util/string_util.h" + +#ifndef __STDC_FORMAT_MACROS +#define __STDC_FORMAT_MACROS +#endif + +#include +#include +#include +#include +#include +#include +#include #include #include +#include #include -#include "util/string_util.h" +#include "rocksdb/env.h" +#include "rocksdb/slice.h" namespace rocksdb { +const std::string kNullptrString = "nullptr"; + std::vector StringSplit(const std::string& arg, char delim) { std::vector splits; std::stringstream ss(arg); @@ -20,4 +37,332 @@ std::vector StringSplit(const std::string& arg, char delim) { 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(micros) / 1000); + } else if (micros < 1000000l * 60 && !fixed_format) { + return snprintf(output, len, "%.3lf sec", + static_cast(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(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(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(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(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(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 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(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(ParseUint64(value)); +} + +std::vector ParseVectorInt(const std::string& value) { + std::vector 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& 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 diff --git a/util/string_util.h b/util/string_util.h index 69899c5ea..c0c3a5e0d 100644 --- a/util/string_util.h +++ b/util/string_util.h @@ -8,10 +8,13 @@ #include #include +#include #include namespace rocksdb { +class Slice; + extern std::vector StringSplit(const std::string& arg, char delim); template @@ -27,4 +30,99 @@ inline std::string ToString(T value) { #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 ParseVectorInt(const std::string& value); + +bool SerializeIntVector(const std::vector& vec, std::string* value); + +extern const std::string kNullptrString; + } // namespace rocksdb diff --git a/utilities/date_tiered/date_tiered_test.cc b/utilities/date_tiered/date_tiered_test.cc index 1a1c8a8ff..55b72517f 100644 --- a/utilities/date_tiered/date_tiered_test.cc +++ b/utilities/date_tiered/date_tiered_test.cc @@ -14,6 +14,7 @@ #include "rocksdb/compaction_filter.h" #include "rocksdb/utilities/date_tiered_db.h" #include "util/logging.h" +#include "util/string_util.h" #include "util/testharness.h" namespace rocksdb { diff --git a/utilities/ttl/ttl_test.cc b/utilities/ttl/ttl_test.cc index 14a0d0313..233946060 100644 --- a/utilities/ttl/ttl_test.cc +++ b/utilities/ttl/ttl_test.cc @@ -4,12 +4,12 @@ #ifndef ROCKSDB_LITE +#include #include #include "rocksdb/compaction_filter.h" #include "rocksdb/utilities/db_ttl.h" +#include "util/string_util.h" #include "util/testharness.h" -#include "util/logging.h" -#include #ifndef OS_WIN #include #endif