xrpld
Loading...
Searching...
No Matches
PeerFinder.cpp
1#include <xrpld/app/rdb/PeerFinder.h>
2
3#include <xrpld/peerfinder/detail/Store.h>
4
5#include <xrpl/basics/Log.h>
6#include <xrpl/basics/contract.h>
7#include <xrpl/beast/net/IPEndpoint.h>
8#include <xrpl/beast/utility/Journal.h>
9#include <xrpl/config/BasicConfig.h>
10#include <xrpl/rdb/SociDB.h>
11
12#include <boost/optional/optional.hpp> // IWYU pragma: keep
13
14#include <soci/into.h>
15#include <soci/session.h>
16#include <soci/statement.h>
17#include <soci/transaction.h>
18#include <soci/use.h>
19
20#include <cstddef>
21#include <functional>
22#include <stdexcept>
23#include <vector>
24
25namespace xrpl {
26
27void
28initPeerFinderDB(soci::session& session, BasicConfig const& config, beast::Journal j)
29{
30 DBConfig const sociConfig(config, "peerfinder");
31 sociConfig.open(session);
32
33 JLOG(j.info()) << "Opening database at '" << sociConfig.connectionString() << "'";
34
35 soci::transaction tr(session);
36 session << "PRAGMA encoding=\"UTF-8\";";
37
38 session << "CREATE TABLE IF NOT EXISTS SchemaVersion ( "
39 " name TEXT PRIMARY KEY, "
40 " version INTEGER"
41 ");";
42
43 session << "CREATE TABLE IF NOT EXISTS PeerFinder_BootstrapCache ( "
44 " id INTEGER PRIMARY KEY AUTOINCREMENT, "
45 " address TEXT UNIQUE NOT NULL, "
46 " valence INTEGER"
47 ");";
48
49 session << "CREATE INDEX IF NOT EXISTS "
50 " PeerFinder_BootstrapCache_Index ON "
51 "PeerFinder_BootstrapCache "
52 " ( "
53 " address "
54 " ); ";
55
56 tr.commit();
57}
58
59void
60updatePeerFinderDB(soci::session& session, int currentSchemaVersion, beast::Journal j)
61{
62 soci::transaction tr(session);
63 // get version
64 int version(0);
65 {
66 // SOCI requires a boost::optional (not std::optional) parameter.
67 boost::optional<int> vO;
68 session << "SELECT "
69 " version "
70 "FROM SchemaVersion WHERE "
71 " name = 'PeerFinder';",
72 soci::into(vO);
73
74 version = vO.value_or(0);
75
76 JLOG(j.info()) << "Opened version " << version << " database";
77 }
78
79 {
80 if (version < currentSchemaVersion)
81 {
82 JLOG(j.info()) << "Updating database to version " << currentSchemaVersion;
83 }
84 else if (version > currentSchemaVersion)
85 {
86 Throw<std::runtime_error>("The PeerFinder database version is higher than expected");
87 }
88 }
89
90 if (version < 4)
91 {
92 //
93 // Remove the "uptime" column from the bootstrap table
94 //
95
96 session << "CREATE TABLE IF NOT EXISTS "
97 "PeerFinder_BootstrapCache_Next ( "
98 " id INTEGER PRIMARY KEY AUTOINCREMENT, "
99 " address TEXT UNIQUE NOT NULL, "
100 " valence INTEGER"
101 ");";
102
103 session << "CREATE INDEX IF NOT EXISTS "
104 " PeerFinder_BootstrapCache_Next_Index ON "
105 " PeerFinder_BootstrapCache_Next "
106 " ( address ); ";
107
108 std::size_t count = 0;
109 session << "SELECT COUNT(*) FROM PeerFinder_BootstrapCache;", soci::into(count);
110
112
113 {
114 list.reserve(count);
115 std::string s;
116 int valence = 0;
117 soci::statement st =
118 (session.prepare << "SELECT "
119 " address, "
120 " valence "
121 "FROM PeerFinder_BootstrapCache;",
122 soci::into(s),
123 soci::into(valence));
124
125 st.execute();
126 while (st.fetch())
127 {
129 entry.endpoint = beast::IP::Endpoint::fromString(s);
130 if (!isUnspecified(entry.endpoint))
131 {
132 entry.valence = valence;
133 list.push_back(entry);
134 }
135 else
136 {
137 JLOG(j.error()) << "Bad address string '" << s << "' in Bootcache table";
138 }
139 }
140 }
141
142 if (!list.empty())
143 {
145 std::vector<int> valence;
146 s.reserve(list.size());
147 valence.reserve(list.size());
148
149 for (auto iter(list.cbegin()); iter != list.cend(); ++iter)
150 {
151 s.emplace_back(to_string(iter->endpoint));
152 valence.emplace_back(iter->valence);
153 }
154
155 session << "INSERT INTO PeerFinder_BootstrapCache_Next ( "
156 " address, "
157 " valence "
158 ") VALUES ( "
159 " :s, :valence"
160 ");",
161 soci::use(s), soci::use(valence);
162 }
163
164 session << "DROP TABLE IF EXISTS PeerFinder_BootstrapCache;";
165
166 session << "DROP INDEX IF EXISTS PeerFinder_BootstrapCache_Index;";
167
168 session << "ALTER TABLE PeerFinder_BootstrapCache_Next "
169 " RENAME TO PeerFinder_BootstrapCache;";
170
171 session << "CREATE INDEX IF NOT EXISTS "
172 " PeerFinder_BootstrapCache_Index ON "
173 "PeerFinder_BootstrapCache "
174 " ( "
175 " address "
176 " ); ";
177 }
178
179 if (version < 3)
180 {
181 //
182 // Remove legacy endpoints from the schema
183 //
184
185 session << "DROP TABLE IF EXISTS LegacyEndpoints;";
186
187 session << "DROP TABLE IF EXISTS PeerFinderLegacyEndpoints;";
188
189 session << "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints;";
190
191 session << "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints_Index;";
192 }
193
194 {
195 int const v(currentSchemaVersion);
196 session << "INSERT OR REPLACE INTO SchemaVersion ("
197 " name "
198 " ,version "
199 ") VALUES ( "
200 " 'PeerFinder', :version "
201 ");",
202 soci::use(v);
203 }
204
205 tr.commit();
206}
207
208void
209readPeerFinderDB(soci::session& session, std::function<void(std::string const&, int)> const& func)
210{
211 std::string s;
212 int valence = 0;
213 soci::statement st =
214 (session.prepare << "SELECT "
215 " address, "
216 " valence "
217 "FROM PeerFinder_BootstrapCache;",
218 soci::into(s),
219 soci::into(valence));
220
221 st.execute();
222 while (st.fetch())
223 {
224 func(s, valence);
225 }
226}
227
228void
230{
231 soci::transaction tr(session);
232 session << "DELETE FROM PeerFinder_BootstrapCache;";
233
234 if (!v.empty())
235 {
237 std::vector<int> valence;
238 s.reserve(v.size());
239 valence.reserve(v.size());
240
241 for (auto const& e : v)
242 {
243 s.emplace_back(to_string(e.endpoint));
244 valence.emplace_back(e.valence);
245 }
246
247 session << "INSERT INTO PeerFinder_BootstrapCache ( "
248 " address, "
249 " valence "
250 ") VALUES ( "
251 " :s, :valence "
252 ");",
253 soci::use(s), soci::use(valence);
254 }
255
256 tr.commit();
257}
258
259} // namespace xrpl
T cbegin(T... args)
static Endpoint fromString(std::string const &s)
A generic endpoint for log messages.
Definition Journal.h:38
Stream error() const
Definition Journal.h:315
Stream info() const
Definition Journal.h:303
Holds unparsed configuration information.
DBConfig is used when a client wants to delay opening a soci::session after parsing the config parame...
Definition SociDB.h:40
void open(soci::session &s) const
Definition SociDB.cpp:86
std::string connectionString() const
Definition SociDB.cpp:80
T emplace_back(T... args)
T empty(T... args)
T cend(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
void readPeerFinderDB(soci::session &session, std::function< void(std::string const &, int)> const &func)
readPeerFinderDB Reads all entries from the peer finder database and invokes the given callback for e...
void updatePeerFinderDB(soci::session &session, int currentSchemaVersion, beast::Journal j)
updatePeerFinderDB Updates the peer finder database to a new version.
void initPeerFinderDB(soci::session &session, BasicConfig const &config, beast::Journal j)
initPeerFinderDB Opens a session with the peer finder database.
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:633
void savePeerFinderDB(soci::session &session, std::vector< PeerFinder::Store::Entry > const &v)
savePeerFinderDB Saves a new entry to the peer finder database.
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:49
T push_back(T... args)
T reserve(T... args)
T size(T... args)