rippled
StoreSqdb.h
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #ifndef RIPPLE_PEERFINDER_STORESQDB_H_INCLUDED
21 #define RIPPLE_PEERFINDER_STORESQDB_H_INCLUDED
22 
23 #include <ripple/basics/contract.h>
24 #include <ripple/core/SociDB.h>
25 #include <boost/optional.hpp>
26 
27 namespace ripple {
28 namespace PeerFinder {
29 
31 class StoreSqdb
32  : public Store
33 {
34 private:
36  soci::session m_session;
37 public:
38  enum
39  {
40  // This determines the on-database format of the data
42  };
43 
44  explicit StoreSqdb (beast::Journal journal =
46  : m_journal (journal)
47  {
48  }
49 
51  {
52  }
53 
54  void open (SociConfig const& sociConfig)
55  {
56  sociConfig.open (m_session);
57 
58  JLOG(m_journal.info()) <<
59  "Opening database at '" << sociConfig.connectionString () << "'";
60 
61  init ();
62  update ();
63  }
64 
65  // Loads the bootstrap cache, calling the callback for each entry
66  //
67  std::size_t load (load_callback const& cb) override
68  {
69  std::size_t n (0);
70  std::string s;
71  int valence;
72  soci::statement st = (m_session.prepare <<
73  "SELECT "
74  " address, "
75  " valence "
76  "FROM PeerFinder_BootstrapCache;"
77  , soci::into (s)
78  , soci::into (valence)
79  );
80 
81  st.execute ();
82  while (st.fetch ())
83  {
84  beast::IP::Endpoint const endpoint (
86 
87  if (!is_unspecified (endpoint))
88  {
89  cb (endpoint, valence);
90  ++n;
91  }
92  else
93  {
94  JLOG(m_journal.error()) <<
95  "Bad address string '" << s << "' in Bootcache table";
96  }
97  }
98  return n;
99  }
100 
101  // Overwrites the stored bootstrap cache with the specified array.
102  //
103  void save (std::vector <Entry> const& v) override
104  {
105  soci::transaction tr (m_session);
106  m_session <<
107  "DELETE FROM PeerFinder_BootstrapCache;";
108 
109  if (!v.empty ())
110  {
112  std::vector<int> valence;
113  s.reserve (v.size ());
114  valence.reserve (v.size ());
115 
116  for (auto const& e : v)
117  {
118  s.emplace_back (to_string (e.endpoint));
119  valence.emplace_back (e.valence);
120  }
121 
122  m_session <<
123  "INSERT INTO PeerFinder_BootstrapCache ( "
124  " address, "
125  " valence "
126  ") VALUES ( "
127  " :s, :valence "
128  ");"
129  , soci::use (s)
130  , soci::use (valence);
131  }
132 
133  tr.commit ();
134  }
135 
136  // Convert any existing entries from an older schema to the
137  // current one, if appropriate.
138  void update ()
139  {
140  soci::transaction tr (m_session);
141  // get version
142  int version (0);
143  {
144  boost::optional<int> vO;
145  m_session <<
146  "SELECT "
147  " version "
148  "FROM SchemaVersion WHERE "
149  " name = 'PeerFinder';"
150  , soci::into (vO)
151  ;
152 
153  version = vO.value_or (0);
154 
155  JLOG(m_journal.info()) <<
156  "Opened version " << version << " database";
157  }
158 
159  {
160  if (version < currentSchemaVersion)
161  {
162  JLOG(m_journal.info()) <<
163  "Updating database to version " << currentSchemaVersion;
164  }
165  else if (version > currentSchemaVersion)
166  {
167  Throw<std::runtime_error> (
168  "The PeerFinder database version is higher than expected");
169  }
170  }
171 
172  if (version < 4)
173  {
174  //
175  // Remove the "uptime" column from the bootstrap table
176  //
177 
178  m_session <<
179  "CREATE TABLE IF NOT EXISTS PeerFinder_BootstrapCache_Next ( "
180  " id INTEGER PRIMARY KEY AUTOINCREMENT, "
181  " address TEXT UNIQUE NOT NULL, "
182  " valence INTEGER"
183  ");"
184  ;
185 
186  m_session <<
187  "CREATE INDEX IF NOT EXISTS "
188  " PeerFinder_BootstrapCache_Next_Index ON "
189  " PeerFinder_BootstrapCache_Next "
190  " ( address ); "
191  ;
192 
193  std::size_t count;
194  m_session <<
195  "SELECT COUNT(*) FROM PeerFinder_BootstrapCache;"
196  , soci::into (count)
197  ;
198 
200 
201  {
202  list.reserve (count);
203  std::string s;
204  int valence;
205  soci::statement st = (m_session.prepare <<
206  "SELECT "
207  " address, "
208  " valence "
209  "FROM PeerFinder_BootstrapCache;"
210  , soci::into (s)
211  , soci::into (valence)
212  );
213 
214  st.execute ();
215  while (st.fetch ())
216  {
217  Store::Entry entry;
219  if (!is_unspecified (entry.endpoint))
220  {
221  entry.valence = valence;
222  list.push_back (entry);
223  }
224  else
225  {
226  JLOG(m_journal.error()) <<
227  "Bad address string '" << s << "' in Bootcache table";
228  }
229  }
230  }
231 
232  if (!list.empty ())
233  {
235  std::vector<int> valence;
236  s.reserve (list.size ());
237  valence.reserve (list.size ());
238 
239  for (auto iter (list.cbegin ());
240  iter != list.cend (); ++iter)
241  {
242  s.emplace_back (to_string (iter->endpoint));
243  valence.emplace_back (iter->valence);
244  }
245 
246  m_session <<
247  "INSERT INTO PeerFinder_BootstrapCache_Next ( "
248  " address, "
249  " valence "
250  ") VALUES ( "
251  " :s, :valence"
252  ");"
253  , soci::use (s)
254  , soci::use (valence)
255  ;
256 
257  }
258 
259  m_session <<
260  "DROP TABLE IF EXISTS PeerFinder_BootstrapCache;";
261 
262  m_session <<
263  "DROP INDEX IF EXISTS PeerFinder_BootstrapCache_Index;";
264 
265  m_session <<
266  "ALTER TABLE PeerFinder_BootstrapCache_Next "
267  " RENAME TO PeerFinder_BootstrapCache;";
268 
269  m_session <<
270  "CREATE INDEX IF NOT EXISTS "
271  " PeerFinder_BootstrapCache_Index ON "
272  "PeerFinder_BootstrapCache "
273  " ( "
274  " address "
275  " ); "
276  ;
277  }
278 
279  if (version < 3)
280  {
281  //
282  // Remove legacy endpoints from the schema
283  //
284 
285  m_session <<
286  "DROP TABLE IF EXISTS LegacyEndpoints;";
287 
288  m_session <<
289  "DROP TABLE IF EXISTS PeerFinderLegacyEndpoints;";
290 
291  m_session <<
292  "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints;";
293 
294  m_session <<
295  "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints_Index;";
296  }
297 
298  {
299  int const v(currentSchemaVersion);
300  m_session <<
301  "INSERT OR REPLACE INTO SchemaVersion ("
302  " name "
303  " ,version "
304  ") VALUES ( "
305  " 'PeerFinder', :version "
306  ");"
307  , soci::use (v);
308  }
309 
310  tr.commit ();
311  }
312 
313 private:
314  void init ()
315  {
316  soci::transaction tr (m_session);
317  m_session << "PRAGMA encoding=\"UTF-8\";";
318 
319  m_session <<
320  "CREATE TABLE IF NOT EXISTS SchemaVersion ( "
321  " name TEXT PRIMARY KEY, "
322  " version INTEGER"
323  ");"
324  ;
325 
326  m_session <<
327  "CREATE TABLE IF NOT EXISTS PeerFinder_BootstrapCache ( "
328  " id INTEGER PRIMARY KEY AUTOINCREMENT, "
329  " address TEXT UNIQUE NOT NULL, "
330  " valence INTEGER"
331  ");"
332  ;
333 
334  m_session <<
335  "CREATE INDEX IF NOT EXISTS "
336  " PeerFinder_BootstrapCache_Index ON "
337  "PeerFinder_BootstrapCache "
338  " ( "
339  " address "
340  " ); "
341  ;
342 
343  tr.commit ();
344  }
345 };
346 
347 }
348 }
349 
350 #endif
ripple::SociConfig
SociConfig is used when a client wants to delay opening a soci::session after parsing the config para...
Definition: SociDB.h:75
std::string
STL class.
ripple::PeerFinder::StoreSqdb::StoreSqdb
StoreSqdb(beast::Journal journal=beast::Journal {beast::Journal::getNullSink()})
Definition: StoreSqdb.h:44
ripple::PeerFinder::StoreSqdb
Database persistence for PeerFinder using SQLite.
Definition: StoreSqdb.h:31
ripple::PeerFinder::StoreSqdb::open
void open(SociConfig const &sociConfig)
Definition: StoreSqdb.h:54
std::vector::reserve
T reserve(T... args)
ripple::PeerFinder::StoreSqdb::m_journal
beast::Journal m_journal
Definition: StoreSqdb.h:35
std::vector
STL class.
std::vector::size
T size(T... args)
ripple::PeerFinder::StoreSqdb::init
void init()
Definition: StoreSqdb.h:314
std::function
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:41
ripple::PeerFinder::Store
Abstract persistence for PeerFinder data.
Definition: Store.h:27
ripple::PeerFinder::StoreSqdb::save
void save(std::vector< Entry > const &v) override
Definition: StoreSqdb.h:103
beast::Journal::getNullSink
static Sink & getNullSink()
Returns a Sink which does nothing.
Definition: beast_Journal.cpp:67
std::vector::push_back
T push_back(T... args)
ripple::PeerFinder::StoreSqdb::m_session
soci::session m_session
Definition: StoreSqdb.h:36
ripple::PeerFinder::StoreSqdb::~StoreSqdb
~StoreSqdb()
Definition: StoreSqdb.h:50
ripple::PeerFinder::Store::Entry::valence
int valence
Definition: Store.h:42
beast::Journal::error
Stream error() const
Definition: Journal.h:307
beast::Journal::info
Stream info() const
Definition: Journal.h:297
ripple::PeerFinder::StoreSqdb::currentSchemaVersion
@ currentSchemaVersion
Definition: StoreSqdb.h:41
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:60
std::vector::emplace_back
T emplace_back(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
std::vector::cbegin
T cbegin(T... args)
beast::IP::Endpoint::from_string
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:47
ripple::SociConfig::open
void open(soci::session &s) const
Definition: SociDB.cpp:93
std::vector::empty
T empty(T... args)
std::size_t
beast::IP::Endpoint
A version-independent IP address and port combination.
Definition: IPEndpoint.h:39
ripple::PeerFinder::StoreSqdb::load
std::size_t load(load_callback const &cb) override
Definition: StoreSqdb.h:67
ripple::SociConfig::connectionString
std::string connectionString() const
Definition: SociDB.cpp:88
std::vector::cend
T cend(T... args)
ripple::PeerFinder::Store::Entry
Definition: Store.h:37
ripple::PeerFinder::Store::Entry::endpoint
beast::IP::Endpoint endpoint
Definition: Store.h:41
ripple::PeerFinder::StoreSqdb::update
void update()
Definition: StoreSqdb.h:138