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 : public Store
32 {
33 private:
35  soci::session m_session;
36 
37 public:
38  enum {
39  // This determines the on-database format of the data
41  };
42 
43  explicit StoreSqdb(
45  : m_journal(journal)
46  {
47  }
48 
50  {
51  }
52 
53  void
54  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  //
68  load(load_callback const& cb) override
69  {
70  std::size_t n(0);
71  std::string s;
72  int valence;
73  soci::statement st =
74  (m_session.prepare << "SELECT "
75  " address, "
76  " valence "
77  "FROM PeerFinder_BootstrapCache;",
78  soci::into(s),
79  soci::into(valence));
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
104  save(std::vector<Entry> const& v) override
105  {
106  soci::transaction tr(m_session);
107  m_session << "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 << "INSERT INTO PeerFinder_BootstrapCache ( "
123  " address, "
124  " valence "
125  ") VALUES ( "
126  " :s, :valence "
127  ");",
128  soci::use(s), soci::use(valence);
129  }
130 
131  tr.commit();
132  }
133 
134  // Convert any existing entries from an older schema to the
135  // current one, if appropriate.
136  void
138  {
139  soci::transaction tr(m_session);
140  // get version
141  int version(0);
142  {
143  boost::optional<int> vO;
144  m_session << "SELECT "
145  " version "
146  "FROM SchemaVersion WHERE "
147  " name = 'PeerFinder';",
148  soci::into(vO);
149 
150  version = vO.value_or(0);
151 
152  JLOG(m_journal.info())
153  << "Opened version " << version << " database";
154  }
155 
156  {
157  if (version < currentSchemaVersion)
158  {
159  JLOG(m_journal.info())
160  << "Updating database to version " << currentSchemaVersion;
161  }
162  else if (version > currentSchemaVersion)
163  {
164  Throw<std::runtime_error>(
165  "The PeerFinder database version is higher than expected");
166  }
167  }
168 
169  if (version < 4)
170  {
171  //
172  // Remove the "uptime" column from the bootstrap table
173  //
174 
175  m_session << "CREATE TABLE IF NOT EXISTS "
176  "PeerFinder_BootstrapCache_Next ( "
177  " id INTEGER PRIMARY KEY AUTOINCREMENT, "
178  " address TEXT UNIQUE NOT NULL, "
179  " valence INTEGER"
180  ");";
181 
182  m_session << "CREATE INDEX IF NOT EXISTS "
183  " PeerFinder_BootstrapCache_Next_Index ON "
184  " PeerFinder_BootstrapCache_Next "
185  " ( address ); ";
186 
187  std::size_t count;
188  m_session << "SELECT COUNT(*) FROM PeerFinder_BootstrapCache;",
189  soci::into(count);
190 
192 
193  {
194  list.reserve(count);
195  std::string s;
196  int valence;
197  soci::statement st =
198  (m_session.prepare << "SELECT "
199  " address, "
200  " valence "
201  "FROM PeerFinder_BootstrapCache;",
202  soci::into(s),
203  soci::into(valence));
204 
205  st.execute();
206  while (st.fetch())
207  {
208  Store::Entry entry;
210  if (!is_unspecified(entry.endpoint))
211  {
212  entry.valence = valence;
213  list.push_back(entry);
214  }
215  else
216  {
217  JLOG(m_journal.error()) << "Bad address string '" << s
218  << "' in Bootcache table";
219  }
220  }
221  }
222 
223  if (!list.empty())
224  {
226  std::vector<int> valence;
227  s.reserve(list.size());
228  valence.reserve(list.size());
229 
230  for (auto iter(list.cbegin()); iter != list.cend(); ++iter)
231  {
232  s.emplace_back(to_string(iter->endpoint));
233  valence.emplace_back(iter->valence);
234  }
235 
236  m_session << "INSERT INTO PeerFinder_BootstrapCache_Next ( "
237  " address, "
238  " valence "
239  ") VALUES ( "
240  " :s, :valence"
241  ");",
242  soci::use(s), soci::use(valence);
243  }
244 
245  m_session << "DROP TABLE IF EXISTS PeerFinder_BootstrapCache;";
246 
247  m_session
248  << "DROP INDEX IF EXISTS PeerFinder_BootstrapCache_Index;";
249 
250  m_session << "ALTER TABLE PeerFinder_BootstrapCache_Next "
251  " RENAME TO PeerFinder_BootstrapCache;";
252 
253  m_session << "CREATE INDEX IF NOT EXISTS "
254  " PeerFinder_BootstrapCache_Index ON "
255  "PeerFinder_BootstrapCache "
256  " ( "
257  " address "
258  " ); ";
259  }
260 
261  if (version < 3)
262  {
263  //
264  // Remove legacy endpoints from the schema
265  //
266 
267  m_session << "DROP TABLE IF EXISTS LegacyEndpoints;";
268 
269  m_session << "DROP TABLE IF EXISTS PeerFinderLegacyEndpoints;";
270 
271  m_session << "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints;";
272 
273  m_session
274  << "DROP TABLE IF EXISTS PeerFinder_LegacyEndpoints_Index;";
275  }
276 
277  {
278  int const v(currentSchemaVersion);
279  m_session << "INSERT OR REPLACE INTO SchemaVersion ("
280  " name "
281  " ,version "
282  ") VALUES ( "
283  " 'PeerFinder', :version "
284  ");",
285  soci::use(v);
286  }
287 
288  tr.commit();
289  }
290 
291 private:
292  void
294  {
295  soci::transaction tr(m_session);
296  m_session << "PRAGMA encoding=\"UTF-8\";";
297 
298  m_session << "CREATE TABLE IF NOT EXISTS SchemaVersion ( "
299  " name TEXT PRIMARY KEY, "
300  " version INTEGER"
301  ");";
302 
303  m_session << "CREATE TABLE IF NOT EXISTS PeerFinder_BootstrapCache ( "
304  " id INTEGER PRIMARY KEY AUTOINCREMENT, "
305  " address TEXT UNIQUE NOT NULL, "
306  " valence INTEGER"
307  ");";
308 
309  m_session << "CREATE INDEX IF NOT EXISTS "
310  " PeerFinder_BootstrapCache_Index ON "
311  "PeerFinder_BootstrapCache "
312  " ( "
313  " address "
314  " ); ";
315 
316  tr.commit();
317  }
318 };
319 
320 } // namespace PeerFinder
321 } // namespace ripple
322 
323 #endif
ripple::SociConfig
SociConfig is used when a client wants to delay opening a soci::session after parsing the config para...
Definition: SociDB.h:76
ripple::PeerFinder::StoreSqdb::StoreSqdb
StoreSqdb(beast::Journal journal=beast::Journal{beast::Journal::getNullSink()})
Definition: StoreSqdb.h:43
std::string
STL class.
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:34
std::vector
STL class.
std::vector::size
T size(T... args)
ripple::PeerFinder::StoreSqdb::init
void init()
Definition: StoreSqdb.h:293
std::function
ripple::to_string
std::string to_string(ListDisposition disposition)
Definition: ValidatorList.cpp:42
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:104
beast::Journal::getNullSink
static Sink & getNullSink()
Returns a Sink which does nothing.
Definition: beast_Journal.cpp:72
std::vector::push_back
T push_back(T... args)
ripple::PeerFinder::StoreSqdb::m_session
soci::session m_session
Definition: StoreSqdb.h:35
ripple::PeerFinder::StoreSqdb::~StoreSqdb
~StoreSqdb()
Definition: StoreSqdb.h:49
ripple::PeerFinder::Store::Entry::valence
int valence
Definition: Store.h:45
beast::Journal::error
Stream error() const
Definition: Journal.h:333
beast::Journal::info
Stream info() const
Definition: Journal.h:321
beast::Journal
A generic endpoint for log messages.
Definition: Journal.h:58
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:46
ripple::SociConfig::open
void open(soci::session &s) const
Definition: SociDB.cpp:94
std::vector::empty
T empty(T... args)
ripple::PeerFinder::StoreSqdb::currentSchemaVersion
@ currentSchemaVersion
Definition: StoreSqdb.h:40
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:68
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:40
ripple::PeerFinder::Store::Entry::endpoint
beast::IP::Endpoint endpoint
Definition: Store.h:44
ripple::PeerFinder::StoreSqdb::update
void update()
Definition: StoreSqdb.h:137