Skip to content

Commit 050665e

Browse files
committed
Change RedisConnection::Query::value_type from String to std::variant<const char*,String>
Especially our history messages contain lots of hardcoded C string literals "like this one". At runtime, they get translated to pointers to constant global memory, const char*. String malloc(3)s and copies these data every time. In contrast, std::variant<const char*,String> just stores the address if any. (Actually, const char* is wrapped by std::string_view to not compute its length every time.)
1 parent 3ab6eba commit 050665e

File tree

3 files changed

+67
-12
lines changed

3 files changed

+67
-12
lines changed

lib/icingadb/icingadb-objects.cpp

+15-7
Original file line numberDiff line numberDiff line change
@@ -402,7 +402,15 @@ void IcingaDB::UpdateAllConfigObjects()
402402
upqObjectType.Enqueue([&]() {
403403
for (auto& hMSet : source.second) {
404404
for (decltype(hMSet.size()) i = 0, stop = hMSet.size() - 1u; i < stop; i += 2u) {
405-
dest.emplace(std::move(hMSet[i]), std::move(hMSet[i + 1u]));
405+
auto variantToString = [](RedisConnection::QueryArg v) -> String {
406+
if (auto str (std::get_if<String>(&v.GetData())); str) {
407+
return std::move(*str);
408+
}
409+
410+
return std::get<std::string_view>(v.GetData());
411+
};
412+
413+
dest.emplace(variantToString(std::move(hMSet[i])), variantToString(std::move(hMSet[i + 1u])));
406414
}
407415

408416
hMSet.clear();
@@ -710,12 +718,12 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
710718
auto id (HashValue(new Array({m_EnvironmentId, actionUrl})));
711719

712720
if (runtimeUpdate || m_DumpedGlobals.ActionUrl.IsNew(id)) {
713-
actionUrls.emplace_back(std::move(id));
721+
actionUrls.emplace_back(id);
714722
Dictionary::Ptr data = new Dictionary({{"environment_id", m_EnvironmentId}, {"action_url", actionUrl}});
715723
actionUrls.emplace_back(JsonEncode(data));
716724

717725
if (runtimeUpdate) {
718-
AddObjectDataToRuntimeUpdates(runtimeUpdates, actionUrls.at(actionUrls.size() - 2u), m_PrefixConfigObject + "action:url", data);
726+
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + "action:url", data);
719727
}
720728
}
721729
}
@@ -725,12 +733,12 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
725733
auto id (HashValue(new Array({m_EnvironmentId, notesUrl})));
726734

727735
if (runtimeUpdate || m_DumpedGlobals.NotesUrl.IsNew(id)) {
728-
notesUrls.emplace_back(std::move(id));
736+
notesUrls.emplace_back(id);
729737
Dictionary::Ptr data = new Dictionary({{"environment_id", m_EnvironmentId}, {"notes_url", notesUrl}});
730738
notesUrls.emplace_back(JsonEncode(data));
731739

732740
if (runtimeUpdate) {
733-
AddObjectDataToRuntimeUpdates(runtimeUpdates, notesUrls.at(notesUrls.size() - 2u), m_PrefixConfigObject + "notes:url", data);
741+
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + "notes:url", data);
734742
}
735743
}
736744
}
@@ -740,12 +748,12 @@ void IcingaDB::InsertObjectDependencies(const ConfigObject::Ptr& object, const S
740748
auto id (HashValue(new Array({m_EnvironmentId, iconImage})));
741749

742750
if (runtimeUpdate || m_DumpedGlobals.IconImage.IsNew(id)) {
743-
iconImages.emplace_back(std::move(id));
751+
iconImages.emplace_back(id);
744752
Dictionary::Ptr data = new Dictionary({{"environment_id", m_EnvironmentId}, {"icon_image", iconImage}});
745753
iconImages.emplace_back(JsonEncode(data));
746754

747755
if (runtimeUpdate) {
748-
AddObjectDataToRuntimeUpdates(runtimeUpdates, iconImages.at(iconImages.size() - 2u), m_PrefixConfigObject + "icon:image", data);
756+
AddObjectDataToRuntimeUpdates(runtimeUpdates, id, m_PrefixConfigObject + "icon:image", data);
749757
}
750758
}
751759
}

lib/icingadb/redisconnection.cpp

+14-3
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ namespace asio = boost::asio;
3030

3131
boost::regex RedisConnection::m_ErrAuth ("\\AERR AUTH ");
3232

33+
RedisConnection::QueryArg::operator std::string_view() const
34+
{
35+
if (auto str (std::get_if<String>(&m_Data)); str) {
36+
return *str;
37+
}
38+
39+
return std::get<std::string_view>(m_Data);
40+
}
41+
3342
RedisConnection::RedisConnection(const String& host, int port, const String& path, const String& username, const String& password, int db,
3443
bool useTls, bool insecure, const String& certPath, const String& keyPath, const String& caPath, const String& crlPath,
3544
const String& tlsProtocolmin, const String& cipherList, double connectTimeout, DebugInfo di, const RedisConnection::Ptr& parent)
@@ -99,10 +108,12 @@ void LogQuery(RedisConnection::Query& query, Log& msg)
99108
break;
100109
}
101110

102-
if (arg.GetLength() > 64) {
103-
msg << " '" << arg.SubStr(0, 61) << "...'";
111+
std::string_view sv (arg);
112+
113+
if (sv.length() > 64) {
114+
msg << " '" << sv.substr(0, 61) << "...'";
104115
} else {
105-
msg << " '" << arg << '\'';
116+
msg << " '" << sv << '\'';
106117
}
107118
}
108119
}

lib/icingadb/redisconnection.hpp

+38-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@
3838
#include <queue>
3939
#include <set>
4040
#include <stdexcept>
41+
#include <string_view>
4142
#include <utility>
43+
#include <variant>
4244
#include <vector>
4345

4446
namespace icinga
@@ -53,7 +55,39 @@ namespace icinga
5355
public:
5456
DECLARE_PTR_TYPEDEFS(RedisConnection);
5557

56-
typedef std::vector<String> Query;
58+
/**
59+
* A Redis query argument. Either owned String, borrowed std::string_view or hardcoded const char[].
60+
* Allows mixing these types in a single query transparently, not requiring any conversions.
61+
*
62+
* @ingroup icingadb
63+
*/
64+
class QueryArg
65+
{
66+
public:
67+
explicit QueryArg(std::string_view data) : m_Data(data)
68+
{
69+
}
70+
71+
QueryArg(String data): m_Data(std::move(data))
72+
{
73+
}
74+
75+
QueryArg(const char* data) : m_Data(std::string_view(data))
76+
{
77+
}
78+
79+
explicit operator std::string_view() const;
80+
81+
std::variant<std::string_view, String>& GetData()
82+
{
83+
return m_Data;
84+
}
85+
86+
private:
87+
std::variant<std::string_view, String> m_Data;
88+
};
89+
90+
typedef std::vector<QueryArg> Query;
5791
typedef std::vector<Query> Queries;
5892
typedef Value Reply;
5993
typedef std::vector<Reply> Replies;
@@ -667,7 +701,9 @@ void RedisConnection::WriteRESP(AsyncWriteStream& stream, const Query& query, bo
667701
msg << "*" << query.size() << "\r\n";
668702

669703
for (auto& arg : query) {
670-
msg << "$" << arg.GetLength() << "\r\n" << arg << "\r\n";
704+
std::string_view sv (arg);
705+
706+
msg << "$" << sv.length() << "\r\n" << sv << "\r\n";
671707
}
672708

673709
asio::async_write(stream, writeBuffer, yc);

0 commit comments

Comments
 (0)