sqlite_ubench.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdint.h>
  17. #include <string.h>
  18. #include <sstream>
  19. #include <iostream>
  20. #include <sqlite3.h>
  21. #include "sqlite_ubench.h"
  22. using namespace std;
  23. SQLite_uBenchmark::SQLite_uBenchmark(const string& filename,
  24. uint32_t num_iterations,
  25. bool sync, bool verbose)
  26. :uBenchmark(num_iterations, filename, sync, verbose),
  27. db_(NULL) {
  28. }
  29. void SQLite_uBenchmark::connect() {
  30. int result = sqlite3_open(dbname_.c_str(), &db_);
  31. if (result != SQLITE_OK) {
  32. failure("Failed to open DB file");
  33. }
  34. result = sqlite3_exec(db_, "DELETE FROM lease4", NULL, NULL, NULL);
  35. if (result != SQLITE_OK) {
  36. failure("Failed to delete old entries");
  37. }
  38. if (sync_) {
  39. sqlite3_exec(db_, "PRAGMA synchronous = ON", NULL, NULL, NULL);
  40. } else {
  41. sqlite3_exec(db_, "PRAGMA synchronous = OFF", NULL, NULL, NULL);
  42. }
  43. // see http://www.sqlite.org/pragma.html#pragma_journal_mode
  44. // for detailed explanation. Available modes: DELETE, TRUNCATE,
  45. // PERSIST, MEMORY, WAL, OFF
  46. sqlite3_exec(db_, "PRAGMA journal_mode = OFF", NULL, NULL, NULL);
  47. }
  48. void SQLite_uBenchmark::disconnect() {
  49. if (db_) {
  50. sqlite3_close(db_);
  51. db_ = NULL;
  52. } else {
  53. throw "Can't close SQLite connection: it was never open.";
  54. }
  55. }
  56. void SQLite_uBenchmark::createLease4Test() {
  57. if (!db_) {
  58. throw "SQLite connection is closed.";
  59. }
  60. uint32_t addr = BASE_ADDR4; // Let's start with 1.0.0.0 address
  61. const uint8_t hwaddr_len = 20; // Not a real field
  62. char hwaddr[hwaddr_len];
  63. const uint8_t client_id_len = 128;
  64. char client_id[client_id_len];
  65. uint32_t valid_lft = 1000; // We can use the same value for all leases
  66. uint32_t recycle_time = 0; // Not supported in any foresable future,
  67. // so keep this as 0
  68. char cltt[48]; // Timestamp
  69. uint32_t pool_id = 0; // Let's use pools 0-99
  70. bool fixed = false;
  71. string hostname("foo"); // Will generate it dynamically
  72. bool fqdn_fwd = true; // Let's pretend to do AAAA update
  73. bool fqdn_rev = true; // Let's pretend to do PTR update
  74. cout << "CREATE: ";
  75. for (uint8_t i = 0; i < hwaddr_len; i++) {
  76. hwaddr[i] = 65 + i;
  77. }
  78. hwaddr[19] = 0; // workaround
  79. for (uint8_t i = 0; i < client_id_len; i++) {
  80. client_id[i] = 33 + i;
  81. }
  82. client_id[6] = 'X'; // there's apostrophe here. It would confuse
  83. // query formatting, let's get rid of it
  84. client_id[127] = 0; // workaround
  85. sqlite3_stmt *stmt = NULL;
  86. if (compiled_stmt_) {
  87. char query[] = "INSERT INTO lease4(addr,hwaddr,client_id,"
  88. "valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
  89. "fqdn_fwd,fqdn_rev) VALUES(?001,?002,?003,?004,?005,?006,?007,?008,?009,?010,?011);";
  90. int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
  91. if (result != SQLITE_OK) {
  92. failure("Failed to compile statement");
  93. }
  94. }
  95. for (uint32_t i = 0; i < num_; i++) {
  96. sprintf(cltt, "2012-07-11 15:43:%02d", i % 60);
  97. addr++;
  98. char* errorMsg = NULL;
  99. if (!compiled_stmt_) {
  100. // the first address is 1.0.0.0.
  101. char query[2000];
  102. /// @todo: Encode HWADDR and CLIENT-ID properly
  103. sprintf(query, "INSERT INTO lease4(addr,hwaddr,client_id,"
  104. "valid_lft,recycle_time,cltt,pool_id,fixed,hostname,"
  105. "fqdn_fwd,fqdn_rev) VALUES(%u,'%s','%s',%d,%d,'%s',%d,'%s','%s','%s','%s');",
  106. addr, hwaddr, client_id, valid_lft, recycle_time,
  107. cltt, pool_id, (fixed?"true":"false"),
  108. hostname.c_str(), (fqdn_fwd?"true":"false"), (fqdn_rev?"true":"false"));
  109. int result = sqlite3_exec(db_, query, NULL, 0, &errorMsg);
  110. if (result != SQLITE_OK) {
  111. stringstream tmp;
  112. tmp << "INSERT error:" << errorMsg;
  113. failure(tmp.str().c_str());
  114. }
  115. } else {
  116. // compiled statement
  117. int result = sqlite3_bind_int(stmt, 1, addr);
  118. if (result != SQLITE_OK) {
  119. failure("sqlite3_bind_int() for column 1");
  120. }
  121. result = sqlite3_bind_blob(stmt, 2, hwaddr, hwaddr_len, NULL);
  122. if (result != SQLITE_OK) {
  123. failure("sqlite3_bind_blob() for column 2");
  124. }
  125. result = sqlite3_bind_blob(stmt, 3, client_id, client_id_len, NULL);
  126. if (result != SQLITE_OK) {
  127. failure("sqlite3_bind_blob() for column 3");
  128. }
  129. if (sqlite3_bind_int(stmt, 4, valid_lft) != SQLITE_OK) {
  130. failure("sqlite3_bind_int() for column 4");
  131. }
  132. if (sqlite3_bind_int(stmt, 5, recycle_time) != SQLITE_OK) {
  133. failure("sqlite3_bind_int() for column 5");
  134. }
  135. if (sqlite3_bind_text(stmt, 6, cltt, strlen(cltt), NULL) != SQLITE_OK) {
  136. failure("sqlite3_bind_int() for column 6");
  137. }
  138. if (sqlite3_bind_int(stmt, 7, pool_id) != SQLITE_OK) {
  139. failure("sqlite3_bind_int() for column 7");
  140. }
  141. if (sqlite3_bind_int(stmt, 7, pool_id) != SQLITE_OK) {
  142. failure("sqlite3_bind_int() for column 7");
  143. }
  144. if (sqlite3_bind_int(stmt, 8, fixed) != SQLITE_OK) {
  145. failure("sqlite3_bind_int() for column 8");
  146. }
  147. if (sqlite3_bind_text(stmt, 9, hostname.c_str(), hostname.length(), NULL) != SQLITE_OK) {
  148. failure("sqlite3_bind_int() for column 9");
  149. }
  150. if (sqlite3_bind_int(stmt, 10, fqdn_fwd) != SQLITE_OK) {
  151. failure("sqlite3_bind_int() for column 10");
  152. }
  153. if (sqlite3_bind_int(stmt, 11, fqdn_rev) != SQLITE_OK) {
  154. failure("sqlite3_bind_int() for column 11");
  155. }
  156. result = sqlite3_step(stmt);
  157. if (result != SQLITE_DONE) {
  158. failure("Failed to execute INSERT clause");
  159. }
  160. // let's reset the compiled statement, so it can be used in the
  161. // next iteration
  162. result = sqlite3_reset(stmt);
  163. if (result != SQLITE_OK) {
  164. failure("Failed to execute sqlite3_reset()");
  165. }
  166. }
  167. if (verbose_) {
  168. cout << ".";
  169. }
  170. }
  171. if (compiled_stmt_) {
  172. int result = sqlite3_finalize(stmt);
  173. if (result != SQLITE_OK) {
  174. failure("sqlite3_finalize() failed");
  175. }
  176. }
  177. cout << endl;
  178. }
  179. static int search_callback(void *counter, int argc, char** argv,
  180. char** azColName){
  181. int* cnt = static_cast<int*>(counter);
  182. (*cnt)++;
  183. char buf[512];
  184. // retrieved lease can be accessed here
  185. for(int i = 0; i < argc; i++){
  186. // pretend we do something with returned lease
  187. if (argv[i]) {
  188. strncpy(buf, azColName[i], 512);
  189. strncpy(buf, argv[i], 512);
  190. }
  191. // Uncomment this to print out all contents
  192. // cout << azColName[i] << "=" << (argv[i] ? argv[i] : "NULL") << endl;
  193. }
  194. return (0);
  195. }
  196. void SQLite_uBenchmark::searchLease4Test() {
  197. if (!db_) {
  198. throw "SQLite connection is closed.";
  199. }
  200. cout << "RETRIEVE: ";
  201. sqlite3_stmt *stmt = NULL;
  202. if (compiled_stmt_) {
  203. const char query[] = "SELECT lease_id,addr,hwaddr,client_id,valid_lft,"
  204. "cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
  205. "FROM lease4 where addr=?1";
  206. int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
  207. if (result != SQLITE_OK) {
  208. failure("Failed to compile statement");
  209. }
  210. }
  211. for (uint32_t i = 0; i < num_; i++) {
  212. uint32_t addr = BASE_ADDR4 + random() % int(num_ / hitratio_);
  213. int cnt = 0;
  214. if (!compiled_stmt_) {
  215. char* errorMsg = NULL;
  216. char query[512];
  217. sprintf(query, "SELECT lease_id,addr,hwaddr,client_id,valid_lft,"
  218. "cltt,pool_id,fixed,hostname,fqdn_fwd,fqdn_rev "
  219. "FROM lease4 where addr=%d", addr);
  220. int result = sqlite3_exec(db_, query, search_callback, &cnt, &errorMsg);
  221. if (result != SQLITE_OK) {
  222. stringstream tmp;
  223. tmp << "SELECT failed: " << errorMsg;
  224. failure(tmp.str().c_str());
  225. }
  226. } else {
  227. // compiled statement
  228. int result = sqlite3_bind_int(stmt, 1, addr);
  229. if (result != SQLITE_OK) {
  230. failure("sqlite3_bind_int() for column 1");
  231. }
  232. result = sqlite3_step(stmt);
  233. switch (result) {
  234. case SQLITE_ROW:
  235. {
  236. uint32_t lease_addr = sqlite3_column_int(stmt, 1);
  237. const void * lease_hwaddr = sqlite3_column_blob(stmt, 2);
  238. uint32_t lease_hwaddr_len = sqlite3_column_bytes(stmt, 2);
  239. const void * lease_clientid = sqlite3_column_blob(stmt, 3);
  240. uint32_t lease_clientid_len = sqlite3_column_bytes(stmt, 3);
  241. uint32_t lease_valid_lft = sqlite3_column_int(stmt, 4);
  242. // cltt
  243. const unsigned char *lease_cltt = sqlite3_column_text(stmt, 5);
  244. uint32_t lease_pool_id = sqlite3_column_int(stmt, 6);
  245. uint32_t lease_fixed = sqlite3_column_int(stmt, 7);
  246. const unsigned char *lease_hostname = sqlite3_column_text(stmt, 8);
  247. uint32_t lease_fqdn_fwd = sqlite3_column_int(stmt, 9);
  248. uint32_t lease_fqdn_rev = sqlite3_column_int(stmt, 10);
  249. if (lease_addr || lease_hwaddr || lease_hwaddr_len || lease_clientid ||
  250. lease_clientid_len || lease_valid_lft || lease_cltt || lease_pool_id ||
  251. lease_fixed || lease_hostname || lease_fqdn_fwd || lease_fqdn_rev) {
  252. // we don't need this information, we just want to obtain it to measure
  253. // the overhead. That strange if is only to quell compiler/cppcheck
  254. // warning about unused variables.
  255. cnt = 1;
  256. }
  257. cnt = 1; // there is at least one row
  258. break;
  259. }
  260. case SQLITE_DONE:
  261. cnt = 0; // there are no rows at all (i.e. no such lease)
  262. break;
  263. default:
  264. failure("Failed to execute SELECT clause");
  265. }
  266. // let's reset the compiled statement, so it can be used in the
  267. // next iteration
  268. result = sqlite3_reset(stmt);
  269. if (result != SQLITE_OK) {
  270. failure("Failed to execute sqlite3_reset()");
  271. }
  272. }
  273. if (verbose_) {
  274. cout << (cnt?".":"X");
  275. }
  276. }
  277. if (compiled_stmt_) {
  278. int result = sqlite3_finalize(stmt);
  279. if (result != SQLITE_OK) {
  280. failure("sqlite3_finalize() failed");
  281. }
  282. }
  283. cout << endl;
  284. }
  285. void SQLite_uBenchmark::updateLease4Test() {
  286. if (!db_) {
  287. throw "SQLite connection is closed.";
  288. }
  289. cout << "UPDATE: ";
  290. sqlite3_stmt *stmt = NULL;
  291. if (compiled_stmt_) {
  292. const char query[] = "UPDATE lease4 SET valid_lft=1002, cltt='now' WHERE addr=?1";
  293. int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
  294. if (result != SQLITE_OK) {
  295. failure("Failed to compile statement");
  296. }
  297. }
  298. for (uint32_t i = 0; i < num_; i++) {
  299. uint32_t addr = BASE_ADDR4 + random() % num_;
  300. if (!compiled_stmt_) {
  301. char* errorMsg = NULL;
  302. char query[512];
  303. sprintf(query, "UPDATE lease4 SET valid_lft=1002, cltt='now' WHERE addr=%d",
  304. addr);
  305. int result = sqlite3_exec(db_, query, NULL /* no callback here*/, 0, &errorMsg);
  306. if (result != SQLITE_OK) {
  307. stringstream tmp;
  308. tmp << "UPDATE error:" << errorMsg;
  309. failure(tmp.str().c_str());
  310. }
  311. } else {
  312. int result = sqlite3_bind_int(stmt, 1, addr);
  313. if (result != SQLITE_OK) {
  314. failure("sqlite3_bind_int() for column 1");
  315. }
  316. result = sqlite3_step(stmt);
  317. if (result != SQLITE_OK && result != SQLITE_DONE) {
  318. failure("Failed to execute sqlite3_step() for UPDATE");
  319. }
  320. // let's reset the compiled statement, so it can be used in the
  321. // next iteration
  322. result = sqlite3_reset(stmt);
  323. if (result != SQLITE_OK) {
  324. failure("Failed to execute sqlite3_reset()");
  325. }
  326. }
  327. if (verbose_) {
  328. cout << ".";
  329. }
  330. }
  331. if (compiled_stmt_) {
  332. int result = sqlite3_finalize(stmt);
  333. if (result != SQLITE_OK) {
  334. failure("sqlite3_finalize() failed");
  335. }
  336. }
  337. cout << endl;
  338. }
  339. void SQLite_uBenchmark::deleteLease4Test() {
  340. if (!db_) {
  341. throw "SQLite connection is closed.";
  342. }
  343. cout << "DELETE: ";
  344. sqlite3_stmt *stmt = NULL;
  345. if (compiled_stmt_) {
  346. const char query[] = "DELETE FROM lease4 WHERE addr=?1";
  347. int result = sqlite3_prepare_v2(db_, query, strlen(query), &stmt, NULL);
  348. if (result != SQLITE_OK) {
  349. failure("Failed to compile statement");
  350. }
  351. }
  352. for (uint32_t i = 0; i < num_; i++) {
  353. uint32_t addr = BASE_ADDR4 + i;
  354. if (!compiled_stmt_) {
  355. char* errorMsg = NULL;
  356. char query[2000];
  357. sprintf(query, "DELETE FROM lease4 WHERE addr=%d", addr);
  358. int result = sqlite3_exec(db_, query, NULL /* no callback here*/, 0, &errorMsg);
  359. if (result != SQLITE_OK) {
  360. stringstream tmp;
  361. tmp << "DELETE error:" << errorMsg;
  362. failure(tmp.str().c_str());
  363. }
  364. } else {
  365. // compiled statement
  366. int result = sqlite3_bind_int(stmt, 1, addr);
  367. if (result != SQLITE_OK) {
  368. failure("sqlite3_bind_int() for column 1");
  369. }
  370. result = sqlite3_step(stmt);
  371. if (result != SQLITE_OK && result != SQLITE_DONE) {
  372. failure("Failed to execute sqlite3_step() for UPDATE");
  373. }
  374. // let's reset the compiled statement, so it can be used in the
  375. // next iteration
  376. result = sqlite3_reset(stmt);
  377. if (result != SQLITE_OK) {
  378. failure("Failed to execute sqlite3_reset()");
  379. }
  380. }
  381. if (verbose_) {
  382. cout << ".";
  383. }
  384. }
  385. if (compiled_stmt_) {
  386. int result = sqlite3_finalize(stmt);
  387. if (result != SQLITE_OK) {
  388. failure("sqlite3_finalize() failed");
  389. }
  390. }
  391. cout << endl;
  392. }
  393. void SQLite_uBenchmark::printInfo() {
  394. cout << "SQLite version is " << sqlite3_libversion()
  395. << "sourceid version is " << sqlite3_sourceid() << endl;
  396. }
  397. int main(int argc, char* const argv[]) {
  398. const char* filename = "sqlite.db";
  399. uint32_t num = 100;
  400. bool sync = true;
  401. bool verbose = true;
  402. SQLite_uBenchmark bench(filename, num, sync, verbose);
  403. bench.parseCmdline(argc, argv);
  404. int result = bench.run();
  405. return (result);
  406. }