sqlite_functions.c 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "sqlite_functions.h"
  3. const char *database_config[] = {
  4. "PRAGMA auto_vacuum=incremental; PRAGMA synchronous=1 ; PRAGMA journal_mode=WAL; PRAGMA temp_store=MEMORY;",
  5. "PRAGMA journal_size_limit=16777216;",
  6. "CREATE TABLE IF NOT EXISTS host(host_id blob PRIMARY KEY, hostname text, "
  7. "registry_hostname text, update_every int, os text, timezone text, tags text);",
  8. "CREATE TABLE IF NOT EXISTS chart(chart_id blob PRIMARY KEY, host_id blob, type text, id text, name text, "
  9. "family text, context text, title text, unit text, plugin text, module text, priority int, update_every int, "
  10. "chart_type int, memory_mode int, history_entries);",
  11. "CREATE TABLE IF NOT EXISTS dimension(dim_id blob PRIMARY KEY, chart_id blob, id text, name text, "
  12. "multiplier int, divisor int , algorithm int, options text);",
  13. "CREATE TABLE IF NOT EXISTS chart_active(chart_id blob PRIMARY KEY, date_created int);",
  14. "CREATE TABLE IF NOT EXISTS dimension_active(dim_id blob primary key, date_created int);",
  15. "CREATE TABLE IF NOT EXISTS metadata_migration(filename text, file_size, date_created int);",
  16. "CREATE INDEX IF NOT EXISTS ind_d1 on dimension (chart_id, id, name);",
  17. "CREATE INDEX IF NOT EXISTS ind_c1 on chart (host_id, id, type, name);",
  18. "CREATE TABLE IF NOT EXISTS chart_label(chart_id blob, source_type int, label_key text, "
  19. "label_value text, date_created int, PRIMARY KEY (chart_id, label_key));",
  20. "delete from chart_active;",
  21. "delete from dimension_active;",
  22. "delete from chart where chart_id not in (select chart_id from dimension);",
  23. "delete from host where host_id not in (select host_id from chart);",
  24. "delete from chart_label where chart_id not in (select chart_id from chart);",
  25. NULL
  26. };
  27. sqlite3 *db_meta = NULL;
  28. static uv_mutex_t sqlite_transaction_lock;
  29. static int execute_insert(sqlite3_stmt *res)
  30. {
  31. int rc;
  32. while ((rc = sqlite3_step(res)) != SQLITE_DONE && unlikely(netdata_exit)) {
  33. if (likely(rc == SQLITE_BUSY || rc == SQLITE_LOCKED))
  34. usleep(SQLITE_INSERT_DELAY * USEC_PER_MS);
  35. else {
  36. error_report("SQLite error %d", rc);
  37. break;
  38. }
  39. }
  40. return rc;
  41. }
  42. /*
  43. * Store a chart or dimension UUID in chart_active or dimension_active
  44. * The statement that will be prepared determines that
  45. */
  46. static int store_active_uuid_object(sqlite3_stmt **res, char *statement, uuid_t *uuid)
  47. {
  48. int rc;
  49. // Check if we should need to prepare the statement
  50. if (!*res) {
  51. rc = sqlite3_prepare_v2(db_meta, statement, -1, res, 0);
  52. if (unlikely(rc != SQLITE_OK)) {
  53. error_report("Failed to prepare statement to store active object, rc = %d", rc);
  54. return rc;
  55. }
  56. }
  57. rc = sqlite3_bind_blob(*res, 1, uuid, sizeof(*uuid), SQLITE_STATIC);
  58. if (unlikely(rc != SQLITE_OK))
  59. error_report("Failed to bind input parameter to store active object, rc = %d", rc);
  60. else
  61. rc = execute_insert(*res);
  62. return rc;
  63. }
  64. /*
  65. * Marks a chart with UUID as active
  66. * Input: UUID
  67. */
  68. void store_active_chart(uuid_t *chart_uuid)
  69. {
  70. sqlite3_stmt *res = NULL;
  71. int rc;
  72. if (unlikely(!db_meta)) {
  73. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  74. error_report("Database has not been initialized");
  75. return;
  76. }
  77. if (unlikely(!chart_uuid))
  78. return;
  79. rc = store_active_uuid_object(&res, SQL_STORE_ACTIVE_CHART, chart_uuid);
  80. if (rc != SQLITE_DONE)
  81. error_report("Failed to store active chart, rc = %d", rc);
  82. rc = sqlite3_finalize(res);
  83. if (unlikely(rc != SQLITE_OK))
  84. error_report("Failed to finalize statement in store active chart, rc = %d", rc);
  85. return;
  86. }
  87. /*
  88. * Marks a dimension with UUID as active
  89. * Input: UUID
  90. */
  91. void store_active_dimension(uuid_t *dimension_uuid)
  92. {
  93. sqlite3_stmt *res = NULL;
  94. int rc;
  95. if (unlikely(!db_meta)) {
  96. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  97. error_report("Database has not been initialized");
  98. return;
  99. }
  100. if (unlikely(!dimension_uuid))
  101. return;
  102. rc = store_active_uuid_object(&res, SQL_STORE_ACTIVE_DIMENSION, dimension_uuid);
  103. if (rc != SQLITE_DONE)
  104. error_report("Failed to store active dimension, rc = %d", rc);
  105. rc = sqlite3_finalize(res);
  106. if (unlikely(rc != SQLITE_OK))
  107. error_report("Failed to finalize statement in store active dimension, rc = %d", rc);
  108. return;
  109. }
  110. /*
  111. * Initialize the SQLite database
  112. * Return 0 on success
  113. */
  114. int sql_init_database(void)
  115. {
  116. char *err_msg = NULL;
  117. char sqlite_database[FILENAME_MAX + 1];
  118. int rc;
  119. fatal_assert(0 == uv_mutex_init(&sqlite_transaction_lock));
  120. snprintfz(sqlite_database, FILENAME_MAX, "%s/netdata-meta.db", netdata_configured_cache_dir);
  121. rc = sqlite3_open(sqlite_database, &db_meta);
  122. if (rc != SQLITE_OK) {
  123. error_report("Failed to initialize database at %s, due to \"%s\"", sqlite_database, sqlite3_errstr(rc));
  124. sqlite3_close(db_meta);
  125. db_meta = NULL;
  126. return 1;
  127. }
  128. info("SQLite database %s initialization", sqlite_database);
  129. for (int i = 0; database_config[i]; i++) {
  130. debug(D_METADATALOG, "Executing %s", database_config[i]);
  131. rc = sqlite3_exec(db_meta, database_config[i], 0, 0, &err_msg);
  132. if (rc != SQLITE_OK) {
  133. error_report("SQLite error during database setup, rc = %d (%s)", rc, err_msg);
  134. error_report("SQLite failed statement %s", database_config[i]);
  135. sqlite3_free(err_msg);
  136. return 1;
  137. }
  138. }
  139. info("SQLite database initialization completed");
  140. return 0;
  141. }
  142. /*
  143. * Close the sqlite database
  144. */
  145. void sql_close_database(void)
  146. {
  147. int rc;
  148. if (unlikely(!db_meta))
  149. return;
  150. info("Closing SQLite database");
  151. rc = sqlite3_close(db_meta);
  152. if (unlikely(rc != SQLITE_OK))
  153. error_report("Error %d while closing the SQLite database", rc);
  154. return;
  155. }
  156. #define FIND_UUID_TYPE "select 1 from host where host_id = @uuid union select 2 from chart where chart_id = @uuid union select 3 from dimension where dim_id = @uuid;"
  157. int find_uuid_type(uuid_t *uuid)
  158. {
  159. static __thread sqlite3_stmt *res = NULL;
  160. int rc;
  161. int uuid_type = 3;
  162. if (unlikely(!res)) {
  163. rc = sqlite3_prepare_v2(db_meta, FIND_UUID_TYPE, -1, &res, 0);
  164. if (rc != SQLITE_OK) {
  165. error_report("Failed to bind prepare statement to find UUID type in the database");
  166. return 0;
  167. }
  168. }
  169. rc = sqlite3_bind_blob(res, 1, uuid, sizeof(*uuid), SQLITE_STATIC);
  170. if (unlikely(rc != SQLITE_OK))
  171. goto bind_fail;
  172. rc = sqlite3_step(res);
  173. if (likely(rc == SQLITE_ROW))
  174. uuid_type = sqlite3_column_int(res, 0);
  175. rc = sqlite3_reset(res);
  176. if (unlikely(rc != SQLITE_OK))
  177. error_report("Failed to reset statement during find uuid type, rc = %d", rc);
  178. return uuid_type;
  179. bind_fail:
  180. return 0;
  181. }
  182. uuid_t *find_dimension_uuid(RRDSET *st, RRDDIM *rd)
  183. {
  184. static __thread sqlite3_stmt *res = NULL;
  185. uuid_t *uuid = NULL;
  186. int rc;
  187. if (unlikely(!db_meta) && default_rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE)
  188. return NULL;
  189. if (unlikely(!res)) {
  190. rc = sqlite3_prepare_v2(db_meta, SQL_FIND_DIMENSION_UUID, -1, &res, 0);
  191. if (rc != SQLITE_OK) {
  192. error_report("Failed to bind prepare statement to lookup dimension UUID in the database");
  193. return NULL;
  194. }
  195. }
  196. rc = sqlite3_bind_blob(res, 1, st->chart_uuid, sizeof(*st->chart_uuid), SQLITE_STATIC);
  197. if (unlikely(rc != SQLITE_OK))
  198. goto bind_fail;
  199. rc = sqlite3_bind_text(res, 2, rd->id, -1, SQLITE_STATIC);
  200. if (unlikely(rc != SQLITE_OK))
  201. goto bind_fail;
  202. rc = sqlite3_bind_text(res, 3, rd->name, -1, SQLITE_STATIC);
  203. if (unlikely(rc != SQLITE_OK))
  204. goto bind_fail;
  205. rc = sqlite3_step(res);
  206. if (likely(rc == SQLITE_ROW)) {
  207. uuid = mallocz(sizeof(uuid_t));
  208. uuid_copy(*uuid, sqlite3_column_blob(res, 0));
  209. }
  210. rc = sqlite3_reset(res);
  211. if (unlikely(rc != SQLITE_OK))
  212. error_report("Failed to reset statement find dimension uuid, rc = %d", rc);
  213. #ifdef NETDATA_INTERNAL_CHECKS
  214. char uuid_str[GUID_LEN + 1];
  215. if (likely(uuid)) {
  216. uuid_unparse_lower(*uuid, uuid_str);
  217. debug(D_METADATALOG, "Found UUID %s for dimension %s", uuid_str, rd->name);
  218. }
  219. else
  220. debug(D_METADATALOG, "UUID not found for dimension %s", rd->name);
  221. #endif
  222. return uuid;
  223. bind_fail:
  224. error_report("Failed to bind input parameter to perform dimension UUID database lookup, rc = %d", rc);
  225. return NULL;
  226. }
  227. uuid_t *create_dimension_uuid(RRDSET *st, RRDDIM *rd)
  228. {
  229. uuid_t *uuid = NULL;
  230. int rc;
  231. uuid = mallocz(sizeof(uuid_t));
  232. uuid_generate(*uuid);
  233. #ifdef NETDATA_INTERNAL_CHECKS
  234. char uuid_str[GUID_LEN + 1];
  235. uuid_unparse_lower(*uuid, uuid_str);
  236. debug(D_METADATALOG,"Generating uuid [%s] for dimension %s under chart %s", uuid_str, rd->name, st->id);
  237. #endif
  238. rc = sql_store_dimension(uuid, st->chart_uuid, rd->id, rd->name, rd->multiplier, rd->divisor, rd->algorithm);
  239. if (unlikely(rc))
  240. error_report("Failed to store dimension metadata in the database");
  241. return uuid;
  242. }
  243. #define DELETE_DIMENSION_UUID "delete from dimension where dim_id = @uuid;"
  244. void delete_dimension_uuid(uuid_t *dimension_uuid)
  245. {
  246. static __thread sqlite3_stmt *res = NULL;
  247. int rc;
  248. #ifdef NETDATA_INTERNAL_CHECKS
  249. char uuid_str[GUID_LEN + 1];
  250. uuid_unparse_lower(*dimension_uuid, uuid_str);
  251. debug(D_METADATALOG,"Deleting dimension uuid %s", uuid_str);
  252. #endif
  253. if (unlikely(!res)) {
  254. rc = sqlite3_prepare_v2(db_meta, DELETE_DIMENSION_UUID, -1, &res, 0);
  255. if (rc != SQLITE_OK) {
  256. error_report("Failed to prepare statement to delete a dimension uuid");
  257. return;
  258. }
  259. }
  260. rc = sqlite3_bind_blob(res, 1, dimension_uuid, sizeof(*dimension_uuid), SQLITE_STATIC);
  261. if (unlikely(rc != SQLITE_OK))
  262. goto bind_fail;
  263. rc = sqlite3_step(res);
  264. if (unlikely(rc != SQLITE_DONE))
  265. error_report("Failed to delete dimension uuid, rc = %d", rc);
  266. bind_fail:
  267. rc = sqlite3_reset(res);
  268. if (unlikely(rc != SQLITE_OK))
  269. error_report("Failed to reset statement when deleting dimension UUID, rc = %d", rc);
  270. return;
  271. }
  272. /*
  273. * Do a database lookup to find the UUID of a chart
  274. *
  275. */
  276. uuid_t *find_chart_uuid(RRDHOST *host, const char *type, const char *id, const char *name)
  277. {
  278. static __thread sqlite3_stmt *res = NULL;
  279. uuid_t *uuid = NULL;
  280. int rc;
  281. if (unlikely(!db_meta) && default_rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE)
  282. return NULL;
  283. if (unlikely(!res)) {
  284. rc = sqlite3_prepare_v2(db_meta, SQL_FIND_CHART_UUID, -1, &res, 0);
  285. if (rc != SQLITE_OK) {
  286. error_report("Failed to prepare statement to lookup chart UUID in the database");
  287. return NULL;
  288. }
  289. }
  290. rc = sqlite3_bind_blob(res, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
  291. if (unlikely(rc != SQLITE_OK))
  292. goto bind_fail;
  293. rc = sqlite3_bind_text(res, 2, type, -1, SQLITE_STATIC);
  294. if (unlikely(rc != SQLITE_OK))
  295. goto bind_fail;
  296. rc = sqlite3_bind_text(res, 3, id, -1, SQLITE_STATIC);
  297. if (unlikely(rc != SQLITE_OK))
  298. goto bind_fail;
  299. rc = sqlite3_bind_text(res, 4, name ? name : id, -1, SQLITE_STATIC);
  300. if (unlikely(rc != SQLITE_OK))
  301. goto bind_fail;
  302. rc = sqlite3_step(res);
  303. if (likely(rc == SQLITE_ROW)) {
  304. uuid = mallocz(sizeof(uuid_t));
  305. uuid_copy(*uuid, sqlite3_column_blob(res, 0));
  306. }
  307. rc = sqlite3_reset(res);
  308. if (unlikely(rc != SQLITE_OK))
  309. error_report("Failed to reset statement when searching for a chart UUID, rc = %d", rc);
  310. #ifdef NETDATA_INTERNAL_CHECKS
  311. char uuid_str[GUID_LEN + 1];
  312. if (likely(uuid)) {
  313. uuid_unparse_lower(*uuid, uuid_str);
  314. debug(D_METADATALOG, "Found UUID %s for chart %s.%s", uuid_str, type, name ? name : id);
  315. }
  316. else
  317. debug(D_METADATALOG, "UUID not found for chart %s.%s", type, name ? name : id);
  318. #endif
  319. return uuid;
  320. bind_fail:
  321. error_report("Failed to bind input parameter to perform chart UUID database lookup, rc = %d", rc);
  322. rc = sqlite3_reset(res);
  323. if (unlikely(rc != SQLITE_OK))
  324. error_report("Failed to reset statement when searching for a chart UUID, rc = %d", rc);
  325. return NULL;
  326. }
  327. int update_chart_metadata(uuid_t *chart_uuid, RRDSET *st, const char *id, const char *name)
  328. {
  329. int rc;
  330. if (unlikely(!db_meta) && default_rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE)
  331. return 0;
  332. rc = sql_store_chart(
  333. chart_uuid, &st->rrdhost->host_uuid, st->type, id, name, st->family, st->context, st->title, st->units, st->plugin_name,
  334. st->module_name, st->priority, st->update_every, st->chart_type, st->rrd_memory_mode, st->entries);
  335. return rc;
  336. }
  337. uuid_t *create_chart_uuid(RRDSET *st, const char *id, const char *name)
  338. {
  339. uuid_t *uuid = NULL;
  340. int rc;
  341. uuid = mallocz(sizeof(uuid_t));
  342. uuid_generate(*uuid);
  343. #ifdef NETDATA_INTERNAL_CHECKS
  344. char uuid_str[GUID_LEN + 1];
  345. uuid_unparse_lower(*uuid, uuid_str);
  346. debug(D_METADATALOG,"Generating uuid [%s] for chart %s under host %s", uuid_str, st->id, st->rrdhost->hostname);
  347. #endif
  348. rc = update_chart_metadata(uuid, st, id, name);
  349. if (unlikely(rc))
  350. error_report("Failed to store chart metadata in the database");
  351. return uuid;
  352. }
  353. // Functions to create host, chart, dimension in the database
  354. int sql_store_host(
  355. uuid_t *host_uuid, const char *hostname, const char *registry_hostname, int update_every, const char *os,
  356. const char *tzone, const char *tags)
  357. {
  358. static __thread sqlite3_stmt *res = NULL;
  359. int rc;
  360. if (unlikely(!db_meta)) {
  361. if (default_rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE)
  362. return 0;
  363. error_report("Database has not been initialized");
  364. return 1;
  365. }
  366. if (unlikely((!res))) {
  367. rc = sqlite3_prepare_v2(db_meta, SQL_STORE_HOST, -1, &res, 0);
  368. if (unlikely(rc != SQLITE_OK)) {
  369. error_report("Failed to prepare statement to store host, rc = %d", rc);
  370. return 1;
  371. }
  372. }
  373. rc = sqlite3_bind_blob(res, 1, host_uuid, sizeof(*host_uuid), SQLITE_STATIC);
  374. if (unlikely(rc != SQLITE_OK))
  375. goto bind_fail;
  376. rc = sqlite3_bind_text(res, 2, hostname, -1, SQLITE_STATIC);
  377. if (unlikely(rc != SQLITE_OK))
  378. goto bind_fail;
  379. rc = sqlite3_bind_text(res, 3, registry_hostname, -1, SQLITE_STATIC);
  380. if (unlikely(rc != SQLITE_OK))
  381. goto bind_fail;
  382. rc = sqlite3_bind_int(res, 4, update_every);
  383. if (unlikely(rc != SQLITE_OK))
  384. goto bind_fail;
  385. rc = sqlite3_bind_text(res, 5, os, -1, SQLITE_STATIC);
  386. if (unlikely(rc != SQLITE_OK))
  387. goto bind_fail;
  388. rc = sqlite3_bind_text(res, 6, tzone, -1, SQLITE_STATIC);
  389. if (unlikely(rc != SQLITE_OK))
  390. goto bind_fail;
  391. rc = sqlite3_bind_text(res, 7, tags, -1, SQLITE_STATIC);
  392. if (unlikely(rc != SQLITE_OK))
  393. goto bind_fail;
  394. int store_rc = sqlite3_step(res);
  395. if (unlikely(store_rc != SQLITE_DONE))
  396. error_report("Failed to store host %s, rc = %d", hostname, rc);
  397. rc = sqlite3_reset(res);
  398. if (unlikely(rc != SQLITE_OK))
  399. error_report("Failed to reset statement to store host %s, rc = %d", hostname, rc);
  400. return !(store_rc == SQLITE_DONE);
  401. bind_fail:
  402. error_report("Failed to bind parameter to store host %s, rc = %d", hostname, rc);
  403. rc = sqlite3_reset(res);
  404. if (unlikely(rc != SQLITE_OK))
  405. error_report("Failed to reset statement to store host %s, rc = %d", hostname, rc);
  406. return 1;
  407. }
  408. /*
  409. * Store a chart in the database
  410. */
  411. int sql_store_chart(
  412. uuid_t *chart_uuid, uuid_t *host_uuid, const char *type, const char *id, const char *name, const char *family,
  413. const char *context, const char *title, const char *units, const char *plugin, const char *module, long priority,
  414. int update_every, int chart_type, int memory_mode, long history_entries)
  415. {
  416. static __thread sqlite3_stmt *res;
  417. int rc, param = 0;
  418. if (unlikely(!db_meta)) {
  419. if (default_rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE)
  420. return 0;
  421. error_report("Database has not been initialized");
  422. return 1;
  423. }
  424. if (unlikely(!res)) {
  425. rc = sqlite3_prepare_v2(db_meta, SQL_STORE_CHART, -1, &res, 0);
  426. if (unlikely(rc != SQLITE_OK)) {
  427. error_report("Failed to prepare statement to store chart, rc = %d", rc);
  428. return 1;
  429. }
  430. }
  431. param++;
  432. rc = sqlite3_bind_blob(res, 1, chart_uuid, sizeof(*chart_uuid), SQLITE_STATIC);
  433. if (unlikely(rc != SQLITE_OK))
  434. goto bind_fail;
  435. param++;
  436. rc = sqlite3_bind_blob(res, 2, host_uuid, sizeof(*host_uuid), SQLITE_STATIC);
  437. if (unlikely(rc != SQLITE_OK))
  438. goto bind_fail;
  439. param++;
  440. rc = sqlite3_bind_text(res, 3, type, -1, SQLITE_STATIC);
  441. if (unlikely(rc != SQLITE_OK))
  442. goto bind_fail;
  443. param++;
  444. rc = sqlite3_bind_text(res, 4, id, -1, SQLITE_STATIC);
  445. if (unlikely(rc != SQLITE_OK))
  446. goto bind_fail;
  447. param++;
  448. if (name && *name)
  449. rc = sqlite3_bind_text(res, 5, name, -1, SQLITE_STATIC);
  450. else
  451. rc = sqlite3_bind_null(res, 5);
  452. if (unlikely(rc != SQLITE_OK))
  453. goto bind_fail;
  454. param++;
  455. rc = sqlite3_bind_text(res, 6, family, -1, SQLITE_STATIC);
  456. if (unlikely(rc != SQLITE_OK))
  457. goto bind_fail;
  458. param++;
  459. rc = sqlite3_bind_text(res, 7, context, -1, SQLITE_STATIC);
  460. if (unlikely(rc != SQLITE_OK))
  461. goto bind_fail;
  462. param++;
  463. rc = sqlite3_bind_text(res, 8, title, -1, SQLITE_STATIC);
  464. if (unlikely(rc != SQLITE_OK))
  465. goto bind_fail;
  466. param++;
  467. rc = sqlite3_bind_text(res, 9, units, -1, SQLITE_STATIC);
  468. if (unlikely(rc != SQLITE_OK))
  469. goto bind_fail;
  470. param++;
  471. rc = sqlite3_bind_text(res, 10, plugin, -1, SQLITE_STATIC);
  472. if (unlikely(rc != SQLITE_OK))
  473. goto bind_fail;
  474. param++;
  475. rc = sqlite3_bind_text(res, 11, module, -1, SQLITE_STATIC);
  476. if (unlikely(rc != SQLITE_OK))
  477. goto bind_fail;
  478. param++;
  479. rc = sqlite3_bind_int(res, 12, priority);
  480. if (unlikely(rc != SQLITE_OK))
  481. goto bind_fail;
  482. param++;
  483. rc = sqlite3_bind_int(res, 13, update_every);
  484. if (unlikely(rc != SQLITE_OK))
  485. goto bind_fail;
  486. param++;
  487. rc = sqlite3_bind_int(res, 14, chart_type);
  488. if (unlikely(rc != SQLITE_OK))
  489. goto bind_fail;
  490. param++;
  491. rc = sqlite3_bind_int(res, 15, memory_mode);
  492. if (unlikely(rc != SQLITE_OK))
  493. goto bind_fail;
  494. param++;
  495. rc = sqlite3_bind_int(res, 16, history_entries);
  496. if (unlikely(rc != SQLITE_OK))
  497. goto bind_fail;
  498. rc = execute_insert(res);
  499. if (unlikely(rc != SQLITE_DONE))
  500. error_report("Failed to store chart, rc = %d", rc);
  501. rc = sqlite3_reset(res);
  502. if (unlikely(rc != SQLITE_OK))
  503. error_report("Failed to reset statement in chart store function, rc = %d", rc);
  504. return 0;
  505. bind_fail:
  506. error_report("Failed to bind parameter %d to store chart, rc = %d", param, rc);
  507. rc = sqlite3_reset(res);
  508. if (unlikely(rc != SQLITE_OK))
  509. error_report("Failed to reset statement in chart store function, rc = %d", rc);
  510. return 1;
  511. }
  512. /*
  513. * Store a dimension
  514. */
  515. int sql_store_dimension(
  516. uuid_t *dim_uuid, uuid_t *chart_uuid, const char *id, const char *name, collected_number multiplier,
  517. collected_number divisor, int algorithm)
  518. {
  519. static __thread sqlite3_stmt *res = NULL;
  520. int rc;
  521. if (unlikely(!db_meta)) {
  522. if (default_rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE)
  523. return 0;
  524. error_report("Database has not been initialized");
  525. return 1;
  526. }
  527. if (unlikely(!res)) {
  528. rc = sqlite3_prepare_v2(db_meta, SQL_STORE_DIMENSION, -1, &res, 0);
  529. if (unlikely(rc != SQLITE_OK)) {
  530. error_report("Failed to prepare statement to store dimension, rc = %d", rc);
  531. return 1;
  532. }
  533. }
  534. rc = sqlite3_bind_blob(res, 1, dim_uuid, sizeof(*dim_uuid), SQLITE_STATIC);
  535. if (unlikely(rc != SQLITE_OK))
  536. goto bind_fail;
  537. rc = sqlite3_bind_blob(res, 2, chart_uuid, sizeof(*chart_uuid), SQLITE_STATIC);
  538. if (unlikely(rc != SQLITE_OK))
  539. goto bind_fail;
  540. rc = sqlite3_bind_text(res, 3, id, -1, SQLITE_STATIC);
  541. if (unlikely(rc != SQLITE_OK))
  542. goto bind_fail;
  543. rc = sqlite3_bind_text(res, 4, name, -1, SQLITE_STATIC);
  544. if (unlikely(rc != SQLITE_OK))
  545. goto bind_fail;
  546. rc = sqlite3_bind_int(res, 5, multiplier);
  547. if (unlikely(rc != SQLITE_OK))
  548. goto bind_fail;
  549. rc = sqlite3_bind_int(res, 6, divisor);
  550. if (unlikely(rc != SQLITE_OK))
  551. goto bind_fail;
  552. rc = sqlite3_bind_int(res, 7, algorithm);
  553. if (unlikely(rc != SQLITE_OK))
  554. goto bind_fail;
  555. rc = execute_insert(res);
  556. if (unlikely(rc != SQLITE_DONE))
  557. error_report("Failed to store dimension, rc = %d", rc);
  558. rc = sqlite3_reset(res);
  559. if (unlikely(rc != SQLITE_OK))
  560. error_report("Failed to reset statement in store dimension, rc = %d", rc);
  561. return 0;
  562. bind_fail:
  563. error_report("Failed to bind parameter to store dimension, rc = %d", rc);
  564. rc = sqlite3_reset(res);
  565. if (unlikely(rc != SQLITE_OK))
  566. error_report("Failed to reset statement in store dimension, rc = %d", rc);
  567. return 1;
  568. }
  569. //
  570. // Support for archived charts
  571. //
  572. #define SELECT_DIMENSION "select d.id, d.name from dimension d where d.chart_id = @chart_uuid;"
  573. void sql_rrdim2json(sqlite3_stmt *res_dim, uuid_t *chart_uuid, BUFFER *wb, size_t *dimensions_count)
  574. {
  575. int rc;
  576. rc = sqlite3_bind_blob(res_dim, 1, chart_uuid, sizeof(*chart_uuid), SQLITE_STATIC);
  577. if (rc != SQLITE_OK)
  578. return;
  579. int dimensions = 0;
  580. buffer_sprintf(wb, "\t\t\t\"dimensions\": {\n");
  581. while (sqlite3_step(res_dim) == SQLITE_ROW) {
  582. if (dimensions)
  583. buffer_strcat(wb, ",\n\t\t\t\t\"");
  584. else
  585. buffer_strcat(wb, "\t\t\t\t\"");
  586. buffer_strcat_jsonescape(wb, (const char *) sqlite3_column_text(res_dim, 0));
  587. buffer_strcat(wb, "\": { \"name\": \"");
  588. buffer_strcat_jsonescape(wb, (const char *) sqlite3_column_text(res_dim, 1));
  589. buffer_strcat(wb, "\" }");
  590. dimensions++;
  591. }
  592. *dimensions_count += dimensions;
  593. buffer_sprintf(wb, "\n\t\t\t}");
  594. }
  595. #define SELECT_CHART "select chart_id, id, name, type, family, context, title, priority, plugin, " \
  596. "module, unit, chart_type, update_every from chart " \
  597. "where host_id = @host_uuid and chart_id not in (select chart_id from chart_active) order by chart_id asc;"
  598. void sql_rrdset2json(RRDHOST *host, BUFFER *wb)
  599. {
  600. // time_t first_entry_t = 0; //= rrdset_first_entry_t(st);
  601. // time_t last_entry_t = 0; //rrdset_last_entry_t(st);
  602. static char *custom_dashboard_info_js_filename = NULL;
  603. int rc;
  604. sqlite3_stmt *res_chart = NULL;
  605. sqlite3_stmt *res_dim = NULL;
  606. time_t now = now_realtime_sec();
  607. rc = sqlite3_prepare_v2(db_meta, SELECT_CHART, -1, &res_chart, 0);
  608. if (unlikely(rc != SQLITE_OK)) {
  609. error_report("Failed to prepare statement to fetch host archived charts");
  610. return;
  611. }
  612. rc = sqlite3_bind_blob(res_chart, 1, &host->host_uuid, sizeof(host->host_uuid), SQLITE_STATIC);
  613. if (unlikely(rc != SQLITE_OK)) {
  614. error_report("Failed to bind host parameter to fetch archived charts");
  615. return;
  616. }
  617. rc = sqlite3_prepare_v2(db_meta, SELECT_DIMENSION, -1, &res_dim, 0);
  618. if (unlikely(rc != SQLITE_OK)) {
  619. error_report("Failed to prepare statement to fetch chart archived dimensions");
  620. goto failed;
  621. };
  622. if(unlikely(!custom_dashboard_info_js_filename))
  623. custom_dashboard_info_js_filename = config_get(CONFIG_SECTION_WEB, "custom dashboard_info.js", "");
  624. buffer_sprintf(wb, "{\n"
  625. "\t\"hostname\": \"%s\""
  626. ",\n\t\"version\": \"%s\""
  627. ",\n\t\"release_channel\": \"%s\""
  628. ",\n\t\"os\": \"%s\""
  629. ",\n\t\"timezone\": \"%s\""
  630. ",\n\t\"update_every\": %d"
  631. ",\n\t\"history\": %ld"
  632. ",\n\t\"memory_mode\": \"%s\""
  633. ",\n\t\"custom_info\": \"%s\""
  634. ",\n\t\"charts\": {"
  635. , host->hostname
  636. , host->program_version
  637. , get_release_channel()
  638. , host->os
  639. , host->timezone
  640. , host->rrd_update_every
  641. , host->rrd_history_entries
  642. , rrd_memory_mode_name(host->rrd_memory_mode)
  643. , custom_dashboard_info_js_filename
  644. );
  645. size_t c = 0;
  646. size_t dimensions = 0;
  647. while (sqlite3_step(res_chart) == SQLITE_ROW) {
  648. char id[512];
  649. sprintf(id, "%s.%s", sqlite3_column_text(res_chart, 3), sqlite3_column_text(res_chart, 1));
  650. RRDSET *st = rrdset_find(host, id);
  651. if (st && !rrdset_flag_check(st, RRDSET_FLAG_ARCHIVED))
  652. continue;
  653. if (c)
  654. buffer_strcat(wb, ",\n\t\t\"");
  655. else
  656. buffer_strcat(wb, "\n\t\t\"");
  657. c++;
  658. buffer_strcat(wb, id);
  659. buffer_strcat(wb, "\": ");
  660. buffer_sprintf(
  661. wb,
  662. "\t\t{\n"
  663. "\t\t\t\"id\": \"%s\",\n"
  664. "\t\t\t\"name\": \"%s\",\n"
  665. "\t\t\t\"type\": \"%s\",\n"
  666. "\t\t\t\"family\": \"%s\",\n"
  667. "\t\t\t\"context\": \"%s\",\n"
  668. "\t\t\t\"title\": \"%s (%s)\",\n"
  669. "\t\t\t\"priority\": %ld,\n"
  670. "\t\t\t\"plugin\": \"%s\",\n"
  671. "\t\t\t\"module\": \"%s\",\n"
  672. "\t\t\t\"enabled\": %s,\n"
  673. "\t\t\t\"units\": \"%s\",\n"
  674. "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n"
  675. "\t\t\t\"chart_type\": \"%s\",\n",
  676. id //sqlite3_column_text(res_chart, 1)
  677. ,
  678. id // sqlite3_column_text(res_chart, 2)
  679. ,
  680. sqlite3_column_text(res_chart, 3), sqlite3_column_text(res_chart, 4), sqlite3_column_text(res_chart, 5),
  681. sqlite3_column_text(res_chart, 6), id //sqlite3_column_text(res_chart, 2)
  682. ,
  683. (long ) sqlite3_column_int(res_chart, 7),
  684. (const char *) sqlite3_column_text(res_chart, 8) ? (const char *) sqlite3_column_text(res_chart, 8) : (char *) "",
  685. (const char *) sqlite3_column_text(res_chart, 9) ? (const char *) sqlite3_column_text(res_chart, 9) : (char *) "", (char *) "false",
  686. (const char *) sqlite3_column_text(res_chart, 10), id //sqlite3_column_text(res_chart, 2)
  687. ,
  688. rrdset_type_name(sqlite3_column_int(res_chart, 11)));
  689. sql_rrdim2json(res_dim, (uuid_t *) sqlite3_column_blob(res_chart, 0), wb, &dimensions);
  690. rc = sqlite3_reset(res_dim);
  691. if (unlikely(rc != SQLITE_OK))
  692. error_report("Failed to reset the prepared statement when reading archived chart dimensions");
  693. buffer_strcat(wb, "\n\t\t}");
  694. }
  695. buffer_sprintf(wb
  696. , "\n\t}"
  697. ",\n\t\"charts_count\": %zu"
  698. ",\n\t\"dimensions_count\": %zu"
  699. ",\n\t\"alarms_count\": %zu"
  700. ",\n\t\"rrd_memory_bytes\": %zu"
  701. ",\n\t\"hosts_count\": %zu"
  702. ",\n\t\"hosts\": ["
  703. , c
  704. , dimensions
  705. , (size_t) 0
  706. , (size_t) 0
  707. , rrd_hosts_available
  708. );
  709. if(unlikely(rrd_hosts_available > 1)) {
  710. rrd_rdlock();
  711. size_t found = 0;
  712. RRDHOST *h;
  713. rrdhost_foreach_read(h) {
  714. if(!rrdhost_should_be_removed(h, host, now) && !rrdhost_flag_check(h, RRDHOST_FLAG_ARCHIVED)) {
  715. buffer_sprintf(wb
  716. , "%s\n\t\t{"
  717. "\n\t\t\t\"hostname\": \"%s\""
  718. "\n\t\t}"
  719. , (found > 0) ? "," : ""
  720. , h->hostname
  721. );
  722. found++;
  723. }
  724. }
  725. rrd_unlock();
  726. }
  727. else {
  728. buffer_sprintf(wb
  729. , "\n\t\t{"
  730. "\n\t\t\t\"hostname\": \"%s\""
  731. "\n\t\t}"
  732. , host->hostname
  733. );
  734. }
  735. buffer_sprintf(wb, "\n\t]\n}\n");
  736. rc = sqlite3_finalize(res_dim);
  737. if (unlikely(rc != SQLITE_OK))
  738. error_report("Failed to finalize the prepared statement when reading archived chart dimensions");
  739. failed:
  740. rc = sqlite3_finalize(res_chart);
  741. if (unlikely(rc != SQLITE_OK))
  742. error_report("Failed to finalize the prepared statement when reading archived charts");
  743. return;
  744. }
  745. #define SELECT_HOST "select host_id, registry_hostname, update_every, os, timezone, tags from host where hostname = @hostname;"
  746. RRDHOST *sql_create_host_by_uuid(char *hostname)
  747. {
  748. int rc;
  749. RRDHOST *host = NULL;
  750. sqlite3_stmt *res = NULL;
  751. rc = sqlite3_prepare_v2(db_meta, SELECT_HOST, -1, &res, 0);
  752. if (unlikely(rc != SQLITE_OK)) {
  753. error_report("Failed to prepare statement to fetch host");
  754. return NULL;
  755. }
  756. rc = sqlite3_bind_text(res, 1, hostname, -1, SQLITE_STATIC);
  757. if (unlikely(rc != SQLITE_OK)) {
  758. error_report("Failed to bind hostname parameter to fetch host information");
  759. return NULL;
  760. }
  761. rc = sqlite3_step(res);
  762. if (unlikely(rc != SQLITE_ROW)) {
  763. error_report("Failed to find hostname %s", hostname);
  764. goto failed;
  765. }
  766. char uuid_str[GUID_LEN + 1];
  767. uuid_unparse_lower(*((uuid_t *) sqlite3_column_blob(res, 0)), uuid_str);
  768. host = callocz(1, sizeof(RRDHOST));
  769. set_host_properties(host, sqlite3_column_int(res, 2), RRD_MEMORY_MODE_DBENGINE, hostname,
  770. (char *) sqlite3_column_text(res, 1), (const char *) uuid_str,
  771. (char *) sqlite3_column_text(res, 3), (char *) sqlite3_column_text(res, 5),
  772. (char *) sqlite3_column_text(res, 4), NULL, NULL);
  773. uuid_copy(host->host_uuid, *((uuid_t *) sqlite3_column_blob(res, 0)));
  774. host->system_info = NULL;
  775. failed:
  776. rc = sqlite3_finalize(res);
  777. if (unlikely(rc != SQLITE_OK))
  778. error_report("Failed to finalize the prepared statement when reading host information");
  779. return host;
  780. }
  781. void db_execute(char *cmd)
  782. {
  783. int rc;
  784. char *err_msg;
  785. rc = sqlite3_exec(db_meta, cmd, 0, 0, &err_msg);
  786. if (rc != SQLITE_OK) {
  787. error_report("Failed to execute '%s', rc = %d (%s)", cmd, rc, err_msg);
  788. sqlite3_free(err_msg);
  789. }
  790. return;
  791. }
  792. void db_lock(void)
  793. {
  794. uv_mutex_lock(&sqlite_transaction_lock);
  795. return;
  796. }
  797. void db_unlock(void)
  798. {
  799. uv_mutex_unlock(&sqlite_transaction_lock);
  800. return;
  801. }
  802. #define SELECT_MIGRATED_FILE "select 1 from metadata_migration where filename = @path;"
  803. int file_is_migrated(char *path)
  804. {
  805. sqlite3_stmt *res = NULL;
  806. int rc;
  807. rc = sqlite3_prepare_v2(db_meta, SELECT_MIGRATED_FILE, -1, &res, 0);
  808. if (unlikely(rc != SQLITE_OK)) {
  809. error_report("Failed to prepare statement to fetch host");
  810. return 0;
  811. }
  812. rc = sqlite3_bind_text(res, 1, path, -1, SQLITE_STATIC);
  813. if (unlikely(rc != SQLITE_OK)) {
  814. error_report("Failed to bind filename parameter to check migration");
  815. return 0;
  816. }
  817. rc = sqlite3_step(res);
  818. if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
  819. error_report("Failed to finalize the prepared statement when checking if metadata file is migrated");
  820. return (rc == SQLITE_ROW);
  821. }
  822. #define STORE_MIGRATED_FILE "insert or replace into metadata_migration (filename, file_size, date_created) " \
  823. "values (@file, @size, strftime('%s'));"
  824. void add_migrated_file(char *path, uint64_t file_size)
  825. {
  826. sqlite3_stmt *res = NULL;
  827. int rc;
  828. rc = sqlite3_prepare_v2(db_meta, STORE_MIGRATED_FILE, -1, &res, 0);
  829. if (unlikely(rc != SQLITE_OK)) {
  830. error_report("Failed to prepare statement to fetch host");
  831. return;
  832. }
  833. rc = sqlite3_bind_text(res, 1, path, -1, SQLITE_STATIC);
  834. if (unlikely(rc != SQLITE_OK)) {
  835. error_report("Failed to bind filename parameter to store migration information");
  836. return;
  837. }
  838. rc = sqlite3_bind_int64(res, 2, file_size);
  839. if (unlikely(rc != SQLITE_OK)) {
  840. error_report("Failed to bind size parameter to store migration information");
  841. return;
  842. }
  843. rc = execute_insert(res);
  844. if (unlikely(rc != SQLITE_DONE))
  845. error_report("Failed to store migrated file, rc = %d", rc);
  846. if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
  847. error_report("Failed to finalize the prepared statement when checking if metadata file is migrated");
  848. return;
  849. }
  850. #define SQL_INS_CHART_LABEL "insert or replace into chart_label " \
  851. "(chart_id, source_type, label_key, label_value, date_created) " \
  852. "values (@chart, @source, @label, @value, strftime('%s'));"
  853. void sql_store_chart_label(uuid_t *chart_uuid, int source_type, char *label, char *value)
  854. {
  855. sqlite3_stmt *res = NULL;
  856. int rc;
  857. if (unlikely(!db_meta)) {
  858. if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
  859. error_report("Database has not been initialized");
  860. return;
  861. }
  862. rc = sqlite3_prepare_v2(db_meta, SQL_INS_CHART_LABEL, -1, &res, 0);
  863. if (unlikely(rc != SQLITE_OK)) {
  864. error_report("Failed to prepare statement store chart labels");
  865. return;
  866. }
  867. rc = sqlite3_bind_blob(res, 1, chart_uuid, sizeof(*chart_uuid), SQLITE_STATIC);
  868. if (unlikely(rc != SQLITE_OK)) {
  869. error_report("Failed to bind chart_id parameter to store label information");
  870. goto failed;
  871. }
  872. rc = sqlite3_bind_int(res, 2, source_type);
  873. if (unlikely(rc != SQLITE_OK)) {
  874. error_report("Failed to bind type parameter to store label information");
  875. goto failed;
  876. }
  877. rc = sqlite3_bind_text(res, 3, label, -1, SQLITE_STATIC);
  878. if (unlikely(rc != SQLITE_OK)) {
  879. error_report("Failed to bind label parameter to store label information");
  880. goto failed;
  881. }
  882. rc = sqlite3_bind_text(res, 4, value, -1, SQLITE_STATIC);
  883. if (unlikely(rc != SQLITE_OK)) {
  884. error_report("Failed to bind value parameter to store label information");
  885. goto failed;
  886. }
  887. rc = execute_insert(res);
  888. if (unlikely(rc != SQLITE_DONE))
  889. error_report("Failed to store chart label entry, rc = %d", rc);
  890. failed:
  891. if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
  892. error_report("Failed to finalize the prepared statement when storing chart label information");
  893. return;
  894. }