diff --git a/CMakeLists.txt b/CMakeLists.txt index e7a2160b52c..348d7aa3d1e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,6 +116,7 @@ include(cmake/zlib.cmake) include(cmake/zstd.cmake) include(cmake/rocksdb.cmake) include(cmake/libevent.cmake) +include(cmake/fmt.cmake) if (USE_LUAJIT) include(cmake/luajit.cmake) @@ -132,6 +133,7 @@ list(APPEND EXTERNAL_LIBS event_with_headers) list(APPEND EXTERNAL_LIBS lz4) list(APPEND EXTERNAL_LIBS zstd) list(APPEND EXTERNAL_LIBS zlib_with_headers) +list(APPEND EXTERNAL_LIBS fmt) if (USE_LUAJIT) list(APPEND EXTERNAL_LIBS luajit) else() diff --git a/NOTICE b/NOTICE index b34a504d45b..3c72f25e2fa 100644 --- a/NOTICE +++ b/NOTICE @@ -189,6 +189,39 @@ zlib is a massively spiffy yet delicately unobtrusive compression library. It is misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. +For the library fmt(https://github.com/fmtlib/fmt): + +{fmt} is an open-source formatting library providing a fast and safe alternative to C stdio and C++ iostreams. +It is under the MIT license with an optional exception: + + Copyright (c) 2012 - present, Victor Zverovich + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + --- Optional exception to the license --- + + As an exception, if, as a result of your compiling your source code, portions + of this Software are embedded into a machine-executable object form of such + source code, you may redistribute such embedded portions in such object form + without including the above copyright and permission notices. + For src/types/geohash.*, src/common/rand.*, src/common/sha1.*, src/storage/scripting.* and some functions in src/common/util.cc are modified from Redis. diff --git a/cmake/fmt.cmake b/cmake/fmt.cmake new file mode 100644 index 00000000000..094930e4d50 --- /dev/null +++ b/cmake/fmt.cmake @@ -0,0 +1,27 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. + +include_guard() + +include(cmake/utils.cmake) + +FetchContent_DeclareGitHubWithMirror(fmt + fmtlib/fmt 9.1.0 + MD5=e6754011ff56bfc37631fcc90961e377 +) + +FetchContent_MakeAvailableWithArgs(fmt) diff --git a/src/cluster/cluster.cc b/src/cluster/cluster.cc index 50b4561abf5..d9bb378bcb2 100644 --- a/src/cluster/cluster.cc +++ b/src/cluster/cluster.cc @@ -26,6 +26,7 @@ #include #include "commands/redis_cmd.h" +#include "fmt/format.h" #include "parse_util.h" #include "replication.h" #include "server/server.h" @@ -313,7 +314,7 @@ Status Cluster::ImportSlot(Redis::Connection *conn, int slot, int state) { switch (state) { case kImportStart: if (!svr_->slot_import_->Start(conn->GetFD(), slot)) { - return Status(Status::NotOK, "Can't start importing slot " + std::to_string(slot)); + return {Status::NotOK, fmt::format("Can't start importing slot {}", slot)}; } // Set link importing conn->SetImporting(); @@ -330,7 +331,7 @@ Status Cluster::ImportSlot(Redis::Connection *conn, int slot, int state) { if (!svr_->slot_import_->Success(slot)) { LOG(ERROR) << "[import] Failed to set slot importing success, maybe slot is wrong" << ", received slot: " << slot << ", current slot: " << svr_->slot_import_->GetSlot(); - return Status(Status::NotOK, "Failed to set slot " + std::to_string(slot) + " importing success"); + return {Status::NotOK, fmt::format("Failed to set slot {} importing success", slot)}; } LOG(INFO) << "[import] Succeed to import slot " << slot; break; @@ -338,12 +339,12 @@ Status Cluster::ImportSlot(Redis::Connection *conn, int slot, int state) { if (!svr_->slot_import_->Fail(slot)) { LOG(ERROR) << "[import] Failed to set slot importing error, maybe slot is wrong" << ", received slot: " << slot << ", current slot: " << svr_->slot_import_->GetSlot(); - return Status(Status::NotOK, "Failed to set slot " + std::to_string(slot) + " importing error"); + return {Status::NotOK, fmt::format("Failed to set slot {} importing error", slot)}; } LOG(INFO) << "[import] Failed to import slot " << slot; break; default: - return Status(Status::NotOK, errInvalidImportState); + return {Status::NotOK, errInvalidImportState}; } return Status::OK(); } @@ -469,9 +470,9 @@ std::string Cluster::GenNodesDescription() { // Generate slots info when occur different node with start or end of slot if (i == kClusterSlots || n != slots_nodes_[i]) { if (start == i - 1) { - n->slots_info_ += std::to_string(start) + " "; + n->slots_info_ += fmt::format("{} ", start); } else { - n->slots_info_ += std::to_string(start) + "-" + std::to_string(i - 1) + " "; + n->slots_info_ += fmt::format("{}-{} ", start, i - 1); } if (i == kClusterSlots) break; n = slots_nodes_[i]; @@ -486,8 +487,7 @@ std::string Cluster::GenNodesDescription() { std::string node_str; // ID, host, port node_str.append(n->id_ + " "); - node_str.append(n->host_ + ":" + std::to_string(n->port_) + "@" + std::to_string(n->port_ + kClusterPortIncr) + - " "); + node_str.append(fmt::format("{}:{}@{} ", n->host_, n->port_, n->port_ + kClusterPortIncr)); // Flags if (n->id_ == myid_) node_str.append("myself,"); @@ -499,8 +499,7 @@ std::string Cluster::GenNodesDescription() { // Ping sent, pong received, config epoch, link status auto now = Util::GetTimeStampMS(); - node_str.append(std::to_string(now - 1) + " " + std::to_string(now) + " " + std::to_string(version_) + " " + - "connected"); + node_str.append(fmt::format("{} {} {} connected", now - 1, now, version_)); // Slots if (n->slots_info_.size() > 0) n->slots_info_.pop_back(); // Trim space @@ -642,24 +641,24 @@ Status Cluster::CanExecByMySelf(const Redis::CommandAttributes *attributes, cons int cur_slot = GetSlotNumFromKey(cmd_tokens[i]); if (slot == -1) slot = cur_slot; if (slot != cur_slot) { - return Status(Status::RedisExecErr, "CROSSSLOT Attempted to access keys that don't hash to the same slot"); + return {Status::RedisExecErr, "CROSSSLOT Attempted to access keys that don't hash to the same slot"}; } } if (slot == -1) return Status::OK(); if (slots_nodes_[slot] == nullptr) { - return Status(Status::ClusterDown, "CLUSTERDOWN Hash slot not served"); + return {Status::ClusterDown, "CLUSTERDOWN Hash slot not served"}; } else if (myself_ && myself_ == slots_nodes_[slot]) { // We use central controller to manage the topology of the cluster. // Server can't change the topology directly, so we record the migrated slots // to move the requests of the migrated slots to the destination node. if (migrated_slots_.count(slot)) { // I'm not serving the migrated slot - return Status(Status::RedisExecErr, "MOVED " + std::to_string(slot) + " " + migrated_slots_[slot]); + return {Status::RedisExecErr, fmt::format("MOVED {} {}", slot, migrated_slots_[slot])}; } // To keep data consistency, slot will be forbidden write while sending the last incremental data. // During this phase, the requests of the migrating slot has to be rejected. if (attributes->is_write() && IsWriteForbiddenSlot(slot)) { - return Status(Status::RedisExecErr, "Can't write to slot being migrated which is in write forbidden phase"); + return {Status::RedisExecErr, "Can't write to slot being migrated which is in write forbidden phase"}; } return Status::OK(); // I'm serving this slot } else if (myself_ && myself_->importing_slot_ == slot && conn->IsImporting()) { @@ -677,7 +676,7 @@ Status Cluster::CanExecByMySelf(const Redis::CommandAttributes *attributes, cons nodes_.find(myself_->master_id_) != nodes_.end() && nodes_[myself_->master_id_] == slots_nodes_[slot]) { return Status::OK(); // My mater is serving this slot } else { - std::string ip_port = slots_nodes_[slot]->host_ + ":" + std::to_string(slots_nodes_[slot]->port_); - return Status(Status::RedisExecErr, "MOVED " + std::to_string(slot) + " " + ip_port); + return {Status::RedisExecErr, + fmt::format("MOVED {} {}:{}", slot, slots_nodes_[slot]->host_, slots_nodes_[slot]->port_)}; } } diff --git a/src/cluster/replication.cc b/src/cluster/replication.cc index 6bb5d6ffafa..0de4427d502 100644 --- a/src/cluster/replication.cc +++ b/src/cluster/replication.cc @@ -34,6 +34,7 @@ #include "event_util.h" #include "fd_util.h" +#include "fmt/format.h" #include "rocksdb_crc32c.h" #include "server/redis_reply.h" #include "server/server.h" @@ -797,13 +798,13 @@ Status ReplicationThread::fetchFile(int sock_fd, evbuffer *evbuf, const std::str UniqueEvbufReadln line(evbuf, EVBUFFER_EOL_CRLF_STRICT); if (!line) { if (evbuffer_read(evbuf, sock_fd, -1) <= 0) { - return Status(Status::NotOK, std::string("read size: ") + strerror(errno)); + return {Status::NotOK, fmt::format("read size: {}", strerror(errno))}; } continue; } if (line[0] == '-') { std::string msg(line.get()); - return Status(Status::NotOK, msg); + return {Status::NotOK, msg}; } file_size = line.length > 0 ? std::strtoull(line.get(), nullptr, 10) : 0; break; @@ -812,7 +813,7 @@ Status ReplicationThread::fetchFile(int sock_fd, evbuffer *evbuf, const std::str // Write to tmp file auto tmp_file = Engine::Storage::ReplDataManager::NewTmpFile(storage_, dir, file); if (!tmp_file) { - return Status(Status::NotOK, "unable to create tmp file"); + return {Status::NotOK, "unable to create tmp file"}; } size_t remain = file_size; @@ -823,22 +824,20 @@ Status ReplicationThread::fetchFile(int sock_fd, evbuffer *evbuf, const std::str auto data_len = evbuffer_remove(evbuf, data, remain > 16 * 1024 ? 16 * 1024 : remain); if (data_len == 0) continue; if (data_len < 0) { - return Status(Status::NotOK, "read sst file data error"); + return {Status::NotOK, "read sst file data error"}; } tmp_file->Append(rocksdb::Slice(data, data_len)); tmp_crc = rocksdb::crc32c::Extend(tmp_crc, data, data_len); remain -= data_len; } else { if (evbuffer_read(evbuf, sock_fd, -1) <= 0) { - return Status(Status::NotOK, std::string("read sst file: ") + strerror(errno)); + return {Status::NotOK, fmt::format("read sst file: {}", strerror(errno))}; } } } // Verify file crc checksum if crc is not 0 if (crc && crc != tmp_crc) { - char err_buf[64]; - snprintf(err_buf, sizeof(err_buf), "CRC mismatched, %u was expected but got %u", crc, tmp_crc); - return Status(Status::NotOK, err_buf); + return {Status::NotOK, fmt::format("CRC mismatched, {} was expected but got {}", crc, tmp_crc)}; } // File is OK, rename to formal name auto s = Engine::Storage::ReplDataManager::SwapTmpFile(storage_, dir, file); diff --git a/src/cluster/slot_import.cc b/src/cluster/slot_import.cc index 0353342233c..76e2914c822 100644 --- a/src/cluster/slot_import.cc +++ b/src/cluster/slot_import.cc @@ -153,5 +153,5 @@ void SlotImport::GetImportInfo(std::string *info) { break; } - *info = "importing_slot: " + std::to_string(import_slot_) + "\r\n" + "import_state: " + import_stat + "\r\n"; + *info = fmt::format("importing_slot: {}\r\nimport_state: {}\r\n", import_slot_, import_stat); } diff --git a/src/cluster/slot_migrate.cc b/src/cluster/slot_migrate.cc index b880cea3e58..8f7b892453a 100644 --- a/src/cluster/slot_migrate.cc +++ b/src/cluster/slot_migrate.cc @@ -24,6 +24,7 @@ #include #include "event_util.h" +#include "fmt/format.h" #include "storage/batch_extractor.h" static std::map type_to_cmd = { @@ -481,7 +482,7 @@ bool SlotMigrate::CheckResponseWithCounts(int sock_fd, int total) { while (true) { // Read response data from socket buffer to the event buffer if (evbuffer_read(evbuf.get(), sock_fd, -1) <= 0) { - LOG(ERROR) << "[migrate] Failed to read response, Err: " + std::string(strerror(errno)); + LOG(ERROR) << "[migrate] Failed to read response, Err: " << strerror(errno); return false; } @@ -499,8 +500,7 @@ bool SlotMigrate::CheckResponseWithCounts(int sock_fd, int total) { } if (line[0] == '-') { - LOG(ERROR) << "[migrate] Got invalid response: " + std::string(line.get()) - << ", line length: " << line.length; + LOG(ERROR) << "[migrate] Got invalid response: " << line.get() << ", line length: " << line.length; stat_ = Error; } else if (line[0] == '$') { auto parse_result = ParseInt(std::string(line.get() + 1, line.length - 1), 10); @@ -985,6 +985,6 @@ void SlotMigrate::GetMigrateInfo(std::string *info) { break; } - *info = "migrating_slot: " + std::to_string(slot) + "\r\n" + "destination_node: " + dst_node_ + "\r\n" + - "migrating_state: " + task_state + "\r\n"; + *info = + fmt::format("migrating_slot: {}\r\ndestination_node: {}\r\nmigrating_state: {}\r\n", slot, dst_node_, task_state); } diff --git a/src/common/util.cc b/src/common/util.cc index 66af04c74d8..2679b12f352 100644 --- a/src/common/util.cc +++ b/src/common/util.cc @@ -18,6 +18,7 @@ * */ +#include "fmt/core.h" #define __STDC_FORMAT_MACROS #include @@ -67,17 +68,14 @@ namespace Util { Status SockConnect(const std::string &host, uint32_t port, int *fd) { - int rv; - char portstr[6]; /* strlen("65535") + 1; */ addrinfo hints, *servinfo, *p; - snprintf(portstr, sizeof(portstr), "%u", port); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; - if ((rv = getaddrinfo(host.c_str(), portstr, &hints, &servinfo)) != 0) { - return Status(Status::NotOK, gai_strerror(rv)); + if (int rv = getaddrinfo(host.c_str(), std::to_string(port).c_str(), &hints, &servinfo); rv != 0) { + return {Status::NotOK, gai_strerror(rv)}; } auto exit = MakeScopeExit([servinfo] { freeaddrinfo(servinfo); }); @@ -108,14 +106,12 @@ const std::string Float2String(double d) { return d > 0 ? "inf" : "-inf"; } - char buf[128]; - snprintf(buf, sizeof(buf), "%.17g", d); - return buf; + return fmt::format("{:.17g}", d); } Status SockSetTcpNoDelay(int fd, int val) { if (setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val)) == -1) { - return Status(Status::NotOK, strerror(errno)); + return Status::FromErrno(); } return Status::OK(); } @@ -123,7 +119,7 @@ Status SockSetTcpNoDelay(int fd, int val) { Status SockSetTcpKeepalive(int fd, int interval) { int val = 1; if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) == -1) { - return Status(Status::NotOK, strerror(errno)); + return Status::FromErrno(); } #ifdef __linux__ @@ -134,7 +130,7 @@ Status SockSetTcpKeepalive(int fd, int interval) { // Send first probe after interval. val = interval; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) { - return Status(Status::NotOK, std::string("setsockopt TCP_KEEPIDLE: ") + strerror(errno)); + return {Status::NotOK, fmt::format("setsockopt TCP_KEEPIDLE: {}", strerror(errno))}; } // Send next probes after the specified interval. Note that we set the @@ -143,14 +139,14 @@ Status SockSetTcpKeepalive(int fd, int interval) { val = interval / 3; if (val == 0) val = 1; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) { - return Status(Status::NotOK, std::string("setsockopt TCP_KEEPINTVL: ") + strerror(errno)); + return {Status::NotOK, fmt::format("setsockopt TCP_KEEPINTVL: {}", strerror(errno))}; } // Consider the socket in error state after three we send three ACK // probes without getting a reply. val = 3; if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) { - return Status(Status::NotOK, std::string("setsockopt TCP_KEEPCNT: ") + strerror(errno)); + return {Status::NotOK, fmt::format("setsockopt TCP_KEEPCNT: {}", strerror(errno))}; } #else ((void)interval); // Avoid unused var warning for non Linux systems. @@ -540,28 +536,23 @@ std::string StringToHex(const std::string &input) { return output; } +constexpr unsigned long long expTo1024(unsigned n) { return 1ULL << (n * 10); } + void BytesToHuman(char *buf, size_t size, uint64_t n) { - double d; - - if (n < 1024) { - snprintf(buf, size, "%" PRIu64 "B", n); - } else if (n < (1024 * 1024)) { - d = static_cast(n) / (1024); - snprintf(buf, size, "%.2fK", d); - } else if (n < (1024LL * 1024 * 1024)) { - d = static_cast(n) / (1024 * 1024); - snprintf(buf, size, "%.2fM", d); - } else if (n < (1024LL * 1024 * 1024 * 1024)) { - d = static_cast(n) / (1024LL * 1024 * 1024); - snprintf(buf, size, "%.2fG", d); - } else if (n < (1024LL * 1024 * 1024 * 1024 * 1024)) { - d = static_cast(n) / (1024LL * 1024 * 1024 * 1024); - snprintf(buf, size, "%.2fT", d); - } else if (n < (1024LL * 1024 * 1024 * 1024 * 1024 * 1024)) { - d = static_cast(n) / (1024LL * 1024 * 1024 * 1024 * 1024); - snprintf(buf, size, "%.2fP", d); + if (n < expTo1024(1)) { + fmt::format_to_n(buf, size, "{}B", n); + } else if (n < expTo1024(2)) { + fmt::format_to_n(buf, size, "{:.2f}K", static_cast(n) / expTo1024(1)); + } else if (n < expTo1024(3)) { + fmt::format_to_n(buf, size, "{:.2f}M", static_cast(n) / expTo1024(2)); + } else if (n < expTo1024(4)) { + fmt::format_to_n(buf, size, "{:.2f}G", static_cast(n) / expTo1024(3)); + } else if (n < expTo1024(5)) { + fmt::format_to_n(buf, size, "{:.2f}T", static_cast(n) / expTo1024(4)); + } else if (n < expTo1024(6)) { + fmt::format_to_n(buf, size, "{:.2f}P", static_cast(n) / expTo1024(5)); } else { - snprintf(buf, size, "%" PRIu64 "B", n); + fmt::format_to_n(buf, size, "{}B", n); } } diff --git a/src/config/config.cc b/src/config/config.cc index 62e8cce00a5..aa169b28793 100644 --- a/src/config/config.cc +++ b/src/config/config.cc @@ -29,13 +29,16 @@ #include #include #include +#include #include #include +#include #include #include #include "config_type.h" #include "config_util.h" +#include "fmt/format.h" #include "parse_util.h" #include "server/server.h" #include "server/tls_util.h" @@ -673,7 +676,7 @@ Status Config::Load(const CLIOptions &opts) { } else { path_ = opts.conf_file; file.open(path_); - if (!file.is_open()) return Status(Status::NotOK, strerror(errno)); + if (!file.is_open()) return Status::FromErrno(); in = &file; } @@ -682,7 +685,7 @@ Status Config::Load(const CLIOptions &opts) { while (!in->eof()) { std::getline(*in, line); if (auto s = parseConfigFromString(line, line_num); !s) { - return Status(Status::NotOK, "at line: #L" + std::to_string(line_num) + ", err: " + s.Msg()); + return {Status::NotOK, fmt::format("at line: #L{}, err: {}", line_num, s.Msg())}; } line_num++; } @@ -694,7 +697,7 @@ Status Config::Load(const CLIOptions &opts) { for (const auto &opt : opts.cli_options) { if (Status s = parseConfigFromPair(opt, -1); !s) { - return Status(Status::NotOK, "CLI config option error: " + s.Msg()); + return {Status::NotOK, "CLI config option error: " + s.Msg()}; } } @@ -704,8 +707,8 @@ Status Config::Load(const CLIOptions &opts) { if (iter.second->line_number != 0 && iter.second->validate) { auto s = iter.second->validate(iter.first, iter.second->ToString()); if (!s.IsOK()) { - return Status(Status::NotOK, "at line: #L" + std::to_string(iter.second->line_number) + ", " + iter.first + - " is invalid: " + s.Msg()); + return {Status::NotOK, + fmt::format("at line: #L{}, {} is invalid: {}", iter.second->line_number, iter.first, s.Msg())}; } } } @@ -714,7 +717,7 @@ Status Config::Load(const CLIOptions &opts) { if (iter.second->callback) { auto s = iter.second->callback(nullptr, iter.first, iter.second->ToString()); if (!s.IsOK()) { - return Status(Status::NotOK, s.Msg() + " in key '" + iter.first + "'"); + return {Status::NotOK, fmt::format("{} in key '{}'", s.Msg(), iter.first)}; } } } @@ -759,7 +762,7 @@ Status Config::Set(Server *svr, std::string key, const std::string &value) { Status Config::Rewrite() { if (path_.empty()) { - return Status(Status::NotOK, "the server is running without a config file"); + return {Status::NotOK, "the server is running without a config file"}; } std::vector lines; std::map new_config; @@ -803,21 +806,21 @@ Status Config::Rewrite() { } file.close(); - std::ostringstream string_stream; + std::string out_buf; for (const auto &line : lines) { - string_stream << line << "\n"; + fmt::format_to(std::back_inserter(out_buf), "{}\n", line); } for (const auto &remain : new_config) { if (remain.second.empty()) continue; - string_stream << remain.first << " " << remain.second << "\n"; + fmt::format_to(std::back_inserter(out_buf), "{} {}\n", remain.first, remain.second); } std::string tmp_path = path_ + ".tmp"; remove(tmp_path.data()); std::ofstream output_file(tmp_path, std::ios::out); - output_file.write(string_stream.str().c_str(), string_stream.str().size()); + output_file << out_buf; output_file.close(); if (rename(tmp_path.data(), path_.data()) < 0) { - return Status(Status::NotOK, std::string("rename file encounter error: ") + strerror(errno)); + return {Status::NotOK, fmt::format("rename file encounter error: {}", strerror(errno))}; } return Status::OK(); } @@ -909,16 +912,16 @@ Status Config::DelNamespace(const std::string &ns) { return s; } } - return Status(Status::NotOK, "the namespace was not found"); + return {Status::NotOK, "the namespace was not found"}; } Status Config::isNamespaceLegal(const std::string &ns) { if (ns.size() > UINT8_MAX) { - return Status(Status::NotOK, std::string("size exceed limit ") + std::to_string(UINT8_MAX)); + return {Status::NotOK, fmt::format("size exceed limit {}", UINT8_MAX)}; } char last_char = ns.back(); if (last_char == std::numeric_limits::max()) { - return Status(Status::NotOK, std::string("namespace contain illegal letter")); + return {Status::NotOK, "namespace contain illegal letter"}; } return Status::OK(); } diff --git a/src/server/redis_connection.cc b/src/server/redis_connection.cc index 1c4b02f0f96..1cec131751c 100644 --- a/src/server/redis_connection.cc +++ b/src/server/redis_connection.cc @@ -21,6 +21,8 @@ #include #include #include + +#include "fmt/format.h" #ifdef ENABLE_OPENSSL #include #endif @@ -53,12 +55,9 @@ Connection::~Connection() { } std::string Connection::ToString() { - std::ostringstream stream; - stream << "id=" << id_ << " addr=" << addr_ << " fd=" << bufferevent_getfd(bev_) << " name=" << name_ - << " age=" << GetAge() << " idle=" << GetIdleTime() << " flags=" << GetFlags() << " namespace=" << ns_ - << " qbuf=" << evbuffer_get_length(Input()) << " obuf=" << evbuffer_get_length(Output()) - << " cmd=" << last_cmd_ << "\n"; - return stream.str(); + return fmt::format("id={} addr={} fd={} name={} age={} idle={} flags={} namespace={} qbuf={} obuf={} cmd={}\n", id_, + addr_, bufferevent_getfd(bev_), name_, GetAge(), GetIdleTime(), GetFlags(), ns_, + evbuffer_get_length(Input()), evbuffer_get_length(Output()), last_cmd_); } void Connection::Close() { diff --git a/src/server/server.cc b/src/server/server.cc index 89762260034..3944530e83f 100644 --- a/src/server/server.cc +++ b/src/server/server.cc @@ -31,6 +31,7 @@ #include #include "config.h" +#include "fmt/format.h" #include "redis_connection.h" #include "redis_request.h" #include "storage/compaction_checker.h" @@ -1056,23 +1057,21 @@ void Server::GetInfo(const std::string &ns, const std::string §ion, std::str } std::string Server::GetRocksDBStatsJson() { - char buf[256]; std::string output; output.reserve(8 * 1024); output.append("{"); auto stats = storage_->GetDB()->GetDBOptions().statistics; for (const auto &iter : rocksdb::TickersNameMap) { - snprintf(buf, sizeof(buf), "\"%s\":%" PRIu64 ",", iter.second.c_str(), stats->getTickerCount(iter.first)); - output.append(buf); + output.append(fmt::format(R"("{}":{},)", iter.second.c_str(), stats->getTickerCount(iter.first))); } for (const auto &iter : rocksdb::HistogramsNameMap) { rocksdb::HistogramData hist_data; stats->histogramData(iter.first, &hist_data); /* P50 P95 P99 P100 COUNT SUM */ - snprintf(buf, sizeof(buf), "\"%s\":[%f,%f,%f,%f,%" PRIu64 ",%" PRIu64 "],", iter.second.c_str(), hist_data.median, - hist_data.percentile95, hist_data.percentile99, hist_data.max, hist_data.count, hist_data.sum); - output.append(buf); + output.append(fmt::format(R"("{}":[{},{},{},{},{},{}])", iter.second.c_str(), hist_data.median, + hist_data.percentile95, hist_data.percentile99, hist_data.max, hist_data.count, + hist_data.sum)); } output.pop_back(); output.append("}"); @@ -1295,14 +1294,14 @@ void Server::SlowlogPushEntryIfNeeded(const std::vector *args, uint size_t argc = args->size() > kSlowLogMaxArgc ? kSlowLogMaxArgc : args->size(); for (size_t i = 0; i < argc; i++) { if (argc != args->size() && i == argc - 1) { - entry->args.emplace_back("... (" + std::to_string(args->size() - argc + 1) + " more arguments)"); + entry->args.emplace_back(fmt::format("... ({} more arguments)", args->size() - argc + 1)); break; } if (args->data()[i].length() <= kSlowLogMaxString) { entry->args.emplace_back(args->data()[i]); } else { - entry->args.emplace_back(args->data()[i].substr(0, kSlowLogMaxString) + "... (" + - std::to_string(args->data()[i].length() - kSlowLogMaxString) + " more bytes)"); + entry->args.emplace_back(fmt::format("{}... ({} more bytes)", args->data()[i].substr(0, kSlowLogMaxString), + args->data()[i].length() - kSlowLogMaxString)); } } entry->duration = duration; diff --git a/src/server/worker.cc b/src/server/worker.cc index f19ec2ae778..50caf3ad706 100644 --- a/src/server/worker.cc +++ b/src/server/worker.cc @@ -23,6 +23,8 @@ #include #include +#include + #ifdef ENABLE_OPENSSL #include #include @@ -196,7 +198,6 @@ void Worker::newUnixSocketConnection(evconnlistener *listener, evutil_socket_t f } Status Worker::listenTCP(const std::string &host, int port, int backlog) { - char _port[6]; int af, rv, fd, sock_opt = 1; if (strchr(host.data(), ':')) { @@ -204,14 +205,13 @@ Status Worker::listenTCP(const std::string &host, int port, int backlog) { } else { af = AF_INET; } - snprintf(_port, sizeof(_port), "%d", port); struct addrinfo hints, *srv_info, *p; memset(&hints, 0, sizeof(hints)); hints.ai_family = af; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; - if ((rv = getaddrinfo(host.data(), _port, &hints, &srv_info)) != 0) { + if ((rv = getaddrinfo(host.data(), std::to_string(port).c_str(), &hints, &srv_info)) != 0) { return Status(Status::NotOK, gai_strerror(rv)); } diff --git a/src/stats/stats.cc b/src/stats/stats.cc index 66704677718..b3736c4377a 100644 --- a/src/stats/stats.cc +++ b/src/stats/stats.cc @@ -22,6 +22,7 @@ #include +#include "fmt/format.h" #include "util.h" Stats::Stats() { @@ -59,9 +60,8 @@ int64_t Stats::GetMemoryRSS() { #include "fd_util.h" int64_t Stats::GetMemoryRSS() { - char buf[4096], filename[256]; - snprintf(filename, sizeof(filename), "/proc/%d/stat", getpid()); - auto fd = UniqueFD(open(filename, O_RDONLY)); + char buf[4096]; + auto fd = UniqueFD(open(fmt::format("/proc/{}/stat", getpid()).c_str(), O_RDONLY)); if (!fd) return 0; if (read(*fd, buf, sizeof(buf)) <= 0) { return 0; diff --git a/src/storage/scripting.cc b/src/storage/scripting.cc index 258aa043f8f..fe05e259e71 100644 --- a/src/storage/scripting.cc +++ b/src/storage/scripting.cc @@ -57,6 +57,7 @@ #include #include "commands/redis_cmd.h" +#include "fmt/format.h" #include "rand.h" #include "server/redis_connection.h" #include "server/server.h" @@ -350,15 +351,12 @@ int redisGenericCommand(lua_State *lua, int raise_error) { return raise_error ? raiseError(lua) : 1; } for (j = 0; j < argc; j++) { - char dbuf[64]; if (lua_type(lua, j + 1) == LUA_TNUMBER) { lua_Number num = lua_tonumber(lua, j + 1); - snprintf(dbuf, sizeof(dbuf), "%.17g", static_cast(num)); - args.emplace_back(dbuf); + args.emplace_back(fmt::format("{:.17g}", static_cast(num))); } else { - const char *obj_s; - size_t obj_len; - obj_s = lua_tolstring(lua, j + 1, &obj_len); + size_t obj_len = 0; + const char *obj_s = lua_tolstring(lua, j + 1, &obj_len); if (obj_s == nullptr) break; /* no a string */ args.emplace_back(obj_s, obj_len); } diff --git a/src/types/redis_stream_base.h b/src/types/redis_stream_base.h index bc0207e3df0..725d201a822 100644 --- a/src/types/redis_stream_base.h +++ b/src/types/redis_stream_base.h @@ -27,6 +27,7 @@ #include #include +#include "fmt/format.h" #include "status.h" namespace Redis { @@ -66,7 +67,7 @@ struct StreamEntryID { bool operator==(const StreamEntryID &rhs) const { return ms == rhs.ms && seq == rhs.seq; } - std::string ToString() const { return std::to_string(ms) + "-" + std::to_string(seq); } + std::string ToString() const { return fmt::format("{}-{}", ms, seq); } static StreamEntryID Minimum() { return StreamEntryID{0, 0}; } static StreamEntryID Maximum() { return StreamEntryID{UINT64_MAX, UINT64_MAX}; }