Anope IRC Services  Version 2.0
db_sql_live.cpp
Go to the documentation of this file.
1 #include "module.h"
2 #include "modules/sql.h"
3 
4 using namespace SQL;
5 
6 class DBMySQL : public Module, public Pipe
7 {
8  private:
11  time_t lastwarn;
12  bool ro;
13  bool init;
14  std::set<Serializable *> updated_items;
15 
16  bool CheckSQL()
17  {
18  if (SQL)
19  {
20  if (Anope::ReadOnly && this->ro)
21  {
22  Anope::ReadOnly = this->ro = false;
23  Log() << "Found SQL again, going out of readonly mode...";
24  }
25 
26  return true;
27  }
28  else
29  {
30  if (Anope::CurTime - Config->GetBlock("options")->Get<time_t>("updatetimeout", "5m") > lastwarn)
31  {
32  Log() << "Unable to locate SQL reference, going to readonly...";
33  Anope::ReadOnly = this->ro = true;
34  this->lastwarn = Anope::CurTime;
35  }
36 
37  return false;
38  }
39  }
40 
41  bool CheckInit()
42  {
43  return init && SQL;
44  }
45 
46  void RunQuery(const Query &query)
47  {
48  /* Can this be threaded? */
49  this->RunQueryResult(query);
50  }
51 
52  Result RunQueryResult(const Query &query)
53  {
54  if (this->CheckSQL())
55  {
56  Result res = SQL->RunQuery(query);
57  if (!res.GetError().empty())
58  Log(LOG_DEBUG) << "SQL-live got error " << res.GetError() << " for " + res.finished_query;
59  else
60  Log(LOG_DEBUG) << "SQL-live got " << res.Rows() << " rows for " << res.finished_query;
61  return res;
62  }
63  throw SQL::Exception("No SQL!");
64  }
65 
66  public:
67  DBMySQL(const Anope::string &modname, const Anope::string &creator) : Module(modname, creator, DATABASE | VENDOR), SQL("", "")
68  {
69  this->lastwarn = 0;
70  this->ro = false;
71  this->init = false;
72 
73 
75  throw ModuleException("If db_sql_live is loaded it must be the first database module loaded.");
76  }
77 
79  {
80  if (!this->CheckInit())
81  return;
82 
83  for (std::set<Serializable *>::iterator it = this->updated_items.begin(), it_end = this->updated_items.end(); it != it_end; ++it)
84  {
85  Serializable *obj = *it;
86 
87  if (obj && this->SQL)
88  {
89  Data data;
90  obj->Serialize(data);
91 
92  if (obj->IsCached(data))
93  continue;
94 
95  obj->UpdateCache(data);
96 
97  Serialize::Type *s_type = obj->GetSerializableType();
98  if (!s_type)
99  continue;
100 
101  std::vector<Query> create = this->SQL->CreateTable(this->prefix + s_type->GetName(), data);
102  for (unsigned i = 0; i < create.size(); ++i)
103  this->RunQueryResult(create[i]);
104 
105  Result res = this->RunQueryResult(this->SQL->BuildInsert(this->prefix + s_type->GetName(), obj->id, data));
106  if (res.GetID() && obj->id != res.GetID())
107  {
108  /* In this case obj is new, so place it into the object map */
109  obj->id = res.GetID();
110  s_type->objects[obj->id] = obj;
111  }
112  }
113  }
114 
115  this->updated_items.clear();
116  }
117 
119  {
120  init = true;
121  return EVENT_STOP;
122  }
123 
125  {
126  init = false;
127  }
128 
130  {
131  init = false;
132  }
133 
135  {
136  Configuration::Block *block = conf->GetModule(this);
137  this->SQL = ServiceReference<Provider>("SQL::Provider", block->Get<const Anope::string>("engine"));
138  this->prefix = block->Get<const Anope::string>("prefix", "anope_db_");
139  }
140 
142  {
143  if (!this->CheckInit())
144  return;
145  obj->UpdateTS();
146  this->updated_items.insert(obj);
147  this->Notify();
148  }
149 
151  {
152  if (!this->CheckInit())
153  return;
154  Serialize::Type *s_type = obj->GetSerializableType();
155  if (s_type)
156  {
157  if (obj->id > 0)
158  this->RunQuery("DELETE FROM `" + this->prefix + s_type->GetName() + "` WHERE `id` = " + stringify(obj->id));
159  s_type->objects.erase(obj->id);
160  }
161  this->updated_items.erase(obj);
162  }
163 
165  {
166  if (!this->CheckInit() || obj->GetTimestamp() == Anope::CurTime)
167  return;
168 
169  Query query("SELECT * FROM `" + this->prefix + obj->GetName() + "` WHERE (`timestamp` > " + this->SQL->FromUnixtime(obj->GetTimestamp()) + " OR `timestamp` IS NULL)");
170 
171  obj->UpdateTimestamp();
172 
173  Result res = this->RunQueryResult(query);
174 
175  bool clear_null = false;
176  for (int i = 0; i < res.Rows(); ++i)
177  {
178  const std::map<Anope::string, Anope::string> &row = res.Row(i);
179 
180  unsigned int id;
181  try
182  {
183  id = convertTo<unsigned int>(res.Get(i, "id"));
184  }
185  catch (const ConvertException &)
186  {
187  Log(LOG_DEBUG) << "Unable to convert id from " << obj->GetName();
188  continue;
189  }
190 
191  if (res.Get(i, "timestamp").empty())
192  {
193  clear_null = true;
194  std::map<uint64_t, Serializable *>::iterator it = obj->objects.find(id);
195  if (it != obj->objects.end())
196  delete it->second; // This also removes this object from the map
197  }
198  else
199  {
200  Data data;
201 
202  for (std::map<Anope::string, Anope::string>::const_iterator it = row.begin(), it_end = row.end(); it != it_end; ++it)
203  data[it->first] << it->second;
204 
205  Serializable *s = NULL;
206  std::map<uint64_t, Serializable *>::iterator it = obj->objects.find(id);
207  if (it != obj->objects.end())
208  s = it->second;
209 
210  Serializable *new_s = obj->Unserialize(s, data);
211  if (new_s)
212  {
213  // If s == new_s then s->id == new_s->id
214  if (s != new_s)
215  {
216  new_s->id = id;
217  obj->objects[id] = new_s;
218 
219  /* The Unserialize operation is destructive so rebuild the data for UpdateCache.
220  * Also the old data may contain columns that we don't use, so we reserialize the
221  * object to know for sure our cache is consistent
222  */
223 
224  Data data2;
225  new_s->Serialize(data2);
226  new_s->UpdateCache(data2); /* We know this is the most up to date copy */
227  }
228  }
229  else
230  {
231  delete s;
232  }
233  }
234  }
235 
236  if (clear_null)
237  {
238  query = "DELETE FROM `" + this->prefix + obj->GetName() + "` WHERE `timestamp` IS NULL";
239  this->RunQuery(query);
240  }
241  }
242 
244  {
245  if (!this->CheckInit() || obj->IsTSCached())
246  return;
247  obj->UpdateTS();
248  this->updated_items.insert(obj);
249  this->Notify();
250  }
251 };
252 
254 
CoreExport bool ReadOnly
Definition: main.cpp:28
Anope::string prefix
Definition: db_sql_live.cpp:9
bool CheckSQL()
Definition: db_sql_live.cpp:16
void OnSerializeCheck(Serialize::Type *obj) anope_override
bool init
Definition: db_sql_live.cpp:13
const std::map< Anope::string, Anope::string > & Row(size_t index) const
Definition: sql.h:157
void OnShutdown() anope_override
bool CheckInit()
Definition: db_sql_live.cpp:41
void UpdateCache(Serialize::Data &)
Definition: serialize.cpp:97
const Anope::string & GetError() const
Definition: sql.h:153
void OnReload(Configuration::Conf *conf) anope_override
Anope::string finished_query
Definition: sql.h:144
void OnSerializableConstruct(Serializable *obj) anope_override
CoreExport time_t CurTime
Definition: main.cpp:41
uint64_t id
Definition: serialize.h:83
Definition: sockets.h:454
EventReturn OnLoadDatabase() anope_override
Result RunQueryResult(const Query &query)
Definition: db_sql_live.cpp:52
Definition: sql.h:96
Definition: Config.cs:26
void OnNotify() anope_override
Definition: db_sql_live.cpp:78
ServiceReference< Provider > SQL
Definition: db_sql_live.cpp:10
virtual void Serialize(Serialize::Data &data) const =0
#define anope_override
Definition: services.h:56
Definition: sql.h:11
bool empty() const
Definition: anope.h:126
void OnSerializableDestruct(Serializable *obj) anope_override
const unsigned int GetID() const
Definition: sql.h:151
EventReturn
Definition: modules.h:129
#define MODULE_INIT(x)
Definition: modules.h:45
Definition: sql.h:8
static Module * FindFirstOf(ModType type)
time_t lastwarn
Definition: db_sql_live.cpp:11
Anope::string stringify(const T &x)
Definition: anope.h:710
void OnRestart() anope_override
std::set< Serializable * > updated_items
Definition: db_sql_live.cpp:14
bool IsCached(Serialize::Data &)
Definition: serialize.cpp:92
Definition: logger.h:53
T Get(const Anope::string &tag)
Definition: config.h:44
DBMySQL(const Anope::string &modname, const Anope::string &creator)
Definition: db_sql_live.cpp:67
void RunQuery(const Query &query)
Definition: db_sql_live.cpp:46
int Rows() const
Definition: sql.h:155
Serialize::Type * GetSerializableType() const
Definition: serialize.h:101
Type(const Anope::string &n, unserialize_func f, Module *owner=NULL)
void OnSerializableUpdate(Serializable *obj) anope_override
const Anope::string Get(size_t index, const Anope::string &col) const
Definition: sql.h:169