kyototycoon-0.9.56/0000755000175000017500000000000011757471603013231 5ustar mikiomikiokyototycoon-0.9.56/ktremotedb.cc0000644000175000017500000000225111757471602015677 0ustar mikiomikio/************************************************************************************************* * Remote database * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "ktremotedb.h" #include "myconf.h" namespace kyototycoon { // common namespace // There is no implementation now. } // common namespace // END OF FILE kyototycoon-0.9.56/README0000644000175000017500000000173311577640524014115 0ustar mikiomikio================================================================ Kyoto Tycoon: a handy cache/storage server Copyright (C) 2009-2010 FAL Labs ================================================================ Please read the following documents with a WWW browser. How to install Kyoto Tycoon is explained in the specification. README - this file COPYING - license (GPLv3) ChangeLog - history of enhancement doc/index.html - index of documents Contents of the directory tree is below. ./ - sources of Kyoto Tycoon ./doc/ - manuals and specifications ./man/ - manuals for nroff ./example/ - sample code for tutorial ./lab/ - for test and experiment Kyoto Tycoon is released under the terms of the GNU General Public License version 3. See the file `COPYING' for details. Kyoto Tycoon was written by FAL Labs. You can contact the author by e-mail to `info@fallabs.com'. Thanks. == END OF FILE == kyototycoon-0.9.56/ktremotetest.cc0000644000175000017500000016262211757471602016302 0ustar mikiomikio/************************************************************************************************* * The test cases of the remote database * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include #include "cmdcommon.h" // global variables const char* g_progname; // program name uint32_t g_randseed; // random seed int64_t g_memusage; // memory usage // function prototypes int main(int argc, char** argv); static void usage(); static void dberrprint(kt::RemoteDB* db, int32_t line, const char* func); static void dbmetaprint(kt::RemoteDB* db, bool verbose); static int32_t runorder(int argc, char** argv); static int32_t runbulk(int argc, char** argv); static int32_t runwicked(int argc, char** argv); static int32_t runusual(int argc, char** argv); static int32_t procorder(int64_t rnum, int32_t thnum, bool rnd, int32_t mode, const char* host, int32_t port, double tout); static int32_t procbulk(int64_t rnum, int32_t thnum, bool bin, bool rnd, int32_t mode, int32_t bulk, const char* host, int32_t port, double tout, int32_t bopts); static int32_t procwicked(int64_t rnum, int32_t thnum, int32_t itnum, const char* host, int32_t port, double tout); static int32_t procusual(int64_t rnum, int32_t thnum, int32_t itnum, const char* host, int32_t port, double tout, int64_t kp, int64_t vs, int64_t xt, double iv); // main routine int main(int argc, char** argv) { g_progname = argv[0]; const char* ebuf = kc::getenv("KTRNDSEED"); g_randseed = ebuf ? (uint32_t)kc::atoi(ebuf) : (uint32_t)(kc::time() * 1000); mysrand(g_randseed); g_memusage = memusage(); kc::setstdiobin(); if (argc < 2) usage(); int32_t rv = 0; if (!std::strcmp(argv[1], "order")) { rv = runorder(argc, argv); } else if (!std::strcmp(argv[1], "bulk")) { rv = runbulk(argc, argv); } else if (!std::strcmp(argv[1], "wicked")) { rv = runwicked(argc, argv); } else if (!std::strcmp(argv[1], "usual")) { rv = runusual(argc, argv); } else { usage(); } if (rv != 0) { oprintf("FAILED: KTRNDSEED=%u PID=%ld", g_randseed, (long)kc::getpid()); for (int32_t i = 0; i < argc; i++) { oprintf(" %s", argv[i]); } oprintf("\n\n"); } return rv; } // print the usage and exit static void usage() { eprintf("%s: test cases of the remote database of Kyoto Tycoon\n", g_progname); eprintf("\n"); eprintf("usage:\n"); eprintf(" %s order [-th num] [-rnd] [-set|-get|-rem|-etc]" " [-host str] [-port num] [-tout num] rnum\n", g_progname); eprintf(" %s bulk [-th num] [-bin] [-rnd] [-set|-get|-rem|-etc] [-bulk num]" " [-host str] [-port num] [-tout num] [-bnr] rnum\n", g_progname); eprintf(" %s wicked [-th num] [-it num] [-host str] [-port num] [-tout num] rnum\n", g_progname); eprintf(" %s usual [-th num] [-host str] [-port num] [-tout num]" " [-kp num] [-vs num] [-xt num] [-iv num] rnum\n", g_progname); eprintf("\n"); std::exit(1); } // print the error message of a database static void dberrprint(kt::RemoteDB* db, int32_t line, const char* func) { const kt::RemoteDB::Error& err = db->error(); oprintf("%s: %d: %s: %s: %d: %s: %s\n", g_progname, line, func, db->expression().c_str(), err.code(), err.name(), err.message()); } // print members of a database static void dbmetaprint(kt::RemoteDB* db, bool verbose) { if (verbose) { std::map status; if (db->status(&status)) { std::map::iterator it = status.begin(); std::map::iterator itend = status.end(); while (it != itend) { oprintf("%s: %s\n", it->first.c_str(), it->second.c_str()); ++it; } } } else { oprintf("count: %lld\n", (long long)db->count()); oprintf("size: %lld\n", (long long)db->size()); } int64_t musage = memusage(); if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage)); } // parse arguments of order command static int32_t runorder(int argc, char** argv) { bool argbrk = false; const char* rstr = NULL; int32_t thnum = 1; bool rnd = false; int32_t mode = 0; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-rnd")) { rnd = true; } else if (!std::strcmp(argv[i], "-set")) { mode = 's'; } else if (!std::strcmp(argv[i], "-get")) { mode = 'g'; } else if (!std::strcmp(argv[i], "-rem")) { mode = 'r'; } else if (!std::strcmp(argv[i], "-etc")) { mode = 'e'; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else { usage(); } } else if (!rstr) { argbrk = false; rstr = argv[i]; } else { usage(); } } if (!rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1 || port < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = procorder(rnum, thnum, rnd, mode, host, port, tout); return rv; } // parse arguments of bulk command static int32_t runbulk(int argc, char** argv) { bool argbrk = false; const char* rstr = NULL; int32_t thnum = 1; bool bin = false; bool rnd = false; int32_t mode = 0; int32_t bulk = 1; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; int32_t bopts = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-bin")) { bin = true; } else if (!std::strcmp(argv[i], "-rnd")) { rnd = true; } else if (!std::strcmp(argv[i], "-set")) { mode = 's'; } else if (!std::strcmp(argv[i], "-get")) { mode = 'g'; } else if (!std::strcmp(argv[i], "-rem")) { mode = 'r'; } else if (!std::strcmp(argv[i], "-etc")) { mode = 'e'; } else if (!std::strcmp(argv[i], "-bulk")) { if (++i >= argc) usage(); bulk = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-bnr")) { bopts |= kt::RemoteDB::BONOREPLY; } else { usage(); } } else if (!rstr) { argbrk = false; rstr = argv[i]; } else { usage(); } } if (!rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1 || bulk < 1 || port < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = procbulk(rnum, thnum, bin, rnd, mode, bulk, host, port, tout, bopts); return rv; } // parse arguments of wicked command static int32_t runwicked(int argc, char** argv) { bool argbrk = false; const char* rstr = NULL; int32_t thnum = 1; int32_t itnum = 1; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-it")) { if (++i >= argc) usage(); itnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else { usage(); } } else if (!rstr) { argbrk = false; rstr = argv[i]; } else { usage(); } } if (!rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1 || port < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = procwicked(rnum, thnum, itnum, host, port, tout); return rv; } // parse arguments of usual command static int32_t runusual(int argc, char** argv) { bool argbrk = false; const char* rstr = NULL; int32_t thnum = 1; int32_t itnum = 1; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; int64_t kp = 0; int64_t vs = 0; int64_t xt = 0; double iv = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-it")) { if (++i >= argc) usage(); itnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-kp")) { if (++i >= argc) usage(); kp = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-vs")) { if (++i >= argc) usage(); vs = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-xt")) { if (++i >= argc) usage(); xt = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-iv")) { if (++i >= argc) usage(); iv = kc::atof(argv[i]); } else { usage(); } } else if (!rstr) { argbrk = false; rstr = argv[i]; } else { usage(); } } if (!rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1 || port < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; if (kp < 1) kp = rnum * thnum; int32_t rv = procusual(rnum, thnum, itnum, host, port, tout, kp, vs, xt, iv); return rv; } // perform order command static int32_t procorder(int64_t rnum, int32_t thnum, bool rnd, int32_t mode, const char* host, int32_t port, double tout) { oprintf("\n seed=%u rnum=%lld thnum=%d rnd=%d mode=%d host=%s port=%d" " tout=%f\n\n", g_randseed, (long long)rnum, thnum, rnd, mode, host, port, tout); bool err = false; oprintf("opening the database:\n"); double stime = kc::time(); kt::RemoteDB* dbs = new kt::RemoteDB[thnum]; for (int32_t i = 0; i < thnum; i++) { if (!dbs[i].open(host, port, tout)) { dberrprint(dbs + i, __LINE__, "DB::open"); err = true; } } if (mode != 'g' && mode != 'r' && !dbs[0].clear()) { dberrprint(dbs, __LINE__, "DB::clear"); err = true; } double etime = kc::time(); oprintf("time: %.3f\n", etime - stime); if (mode == 0 || mode == 's' || mode == 'e') { oprintf("setting records:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), rnd_(false), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool rnd, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; rnd_ = rnd; db_ = db; } bool error() { return err_; } private: void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; if (!db_->set(kbuf, ksiz, kbuf, ksiz, xt)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } int32_t id_; int64_t rnum_; int32_t thnum_; bool rnd_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, rnd, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, mode == 's'); oprintf("time: %.3f\n", etime - stime); } if (mode == 'e') { oprintf("adding records:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), rnd_(false), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool rnd, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; rnd_ = rnd; db_ = db; } bool error() { return err_; } private: void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; if (!db_->add(kbuf, ksiz, kbuf, ksiz, xt) && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::add"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } int32_t id_; int64_t rnum_; int32_t thnum_; bool rnd_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, rnd, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, false); oprintf("time: %.3f\n", etime - stime); } if (mode == 'e') { oprintf("appending records:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), rnd_(false), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool rnd, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; rnd_ = rnd; db_ = db; } bool error() { return err_; } private: void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; if (!db_->append(kbuf, ksiz, kbuf, ksiz, xt)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } int32_t id_; int64_t rnum_; int32_t thnum_; bool rnd_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, rnd, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, false); oprintf("time: %.3f\n", etime - stime); } if (mode == 0 || mode == 'g' || mode == 'e') { oprintf("geting records:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), rnd_(false), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool rnd, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; rnd_ = rnd; db_ = db; } bool error() { return err_; } private: void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); size_t vsiz; char* vbuf = db_->get(kbuf, ksiz, &vsiz); if (vbuf) { if (vsiz < ksiz || std::memcmp(vbuf, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } delete[] vbuf; } else if (!rnd_ || db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } int32_t id_; int64_t rnum_; int32_t thnum_; bool rnd_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, rnd, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, mode == 'g'); oprintf("time: %.3f\n", etime - stime); } if (mode == 'e') { oprintf("traversing the database by the outer cursor:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), rnd_(false), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool rnd, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; rnd_ = rnd; db_ = db; } bool error() { return err_; } private: void run() { kt::RemoteDB::Cursor* cur = db_->cursor(); if (!cur->jump() && cur->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::jump"); err_ = true; } int64_t cnt = 0; const char* kbuf; size_t ksiz; while ((kbuf = cur->get_key(&ksiz)) != NULL) { cnt++; if (rnd_) { switch (myrand(5)) { case 0: { char vbuf[RECBUFSIZ]; size_t vsiz = std::sprintf(vbuf, "%lld", (long long)cnt); if (!cur->set_value(vbuf, vsiz, myrand(600) + 1, myrand(2) == 0) && cur->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::set_value"); err_ = true; } break; } case 1: { if (!cur->remove() && cur->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::remove"); err_ = true; } break; } case 2: { size_t rsiz, vsiz; const char* vbuf; int64_t xt; char* rbuf = cur->get(&rsiz, &vbuf, &vsiz, &xt, myrand(2) == 0); if (rbuf ) { delete[] rbuf; } else if (cur->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::et"); err_ = true; } break; } } } else { size_t vsiz; char* vbuf = cur->get_value(&vsiz); if (vbuf) { delete[] vbuf; } else { dberrprint(db_, __LINE__, "Cursor::get_value"); err_ = true; } } delete[] kbuf; if (!cur->step() && cur->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::step"); err_ = true; } if (id_ < 1 && rnum_ > 250 && cnt % (rnum_ / 250) == 0) { oputchar('.'); if (cnt == rnum_ || cnt % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt); } } if (cur->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::get_key"); err_ = true; } if (!rnd_ && cnt != db_->count()) { dberrprint(db_, __LINE__, "Cursor::get_key"); err_ = true; } if (id_ < 1) oprintf(" (end)\n"); delete cur; } int32_t id_; int64_t rnum_; int32_t thnum_; bool rnd_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, rnd, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, false); oprintf("time: %.3f\n", etime - stime); } if (mode == 0 || mode == 'r' || mode == 'e') { oprintf("removing records:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), rnd_(false), mode_(0), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool rnd, int32_t mode, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; rnd_ = rnd; mode_ = mode; db_ = db; } bool error() { return err_; } private: void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); if (!db_->remove(kbuf, ksiz) && ((!rnd_ && mode_ != 'e') || db_->error() != kt::RemoteDB::Error::LOGIC)) { dberrprint(db_, __LINE__, "DB::remove"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } int32_t id_; int64_t rnum_; int32_t thnum_; bool rnd_; int32_t mode_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, rnd, mode, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, mode == 'r' || mode == 'e'); oprintf("time: %.3f\n", etime - stime); } oprintf("closing the database:\n"); stime = kc::time(); for (int32_t i = 0; i < thnum; i++) { if (!dbs[i].close()) { dberrprint(dbs + i, __LINE__, "DB::close"); err = true; } } etime = kc::time(); oprintf("time: %.3f\n", etime - stime); delete[] dbs; oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform bulk command static int32_t procbulk(int64_t rnum, int32_t thnum, bool bin, bool rnd, int32_t mode, int32_t bulk, const char* host, int32_t port, double tout, int32_t bopts) { oprintf("\n seed=%u rnum=%lld thnum=%d bin=%d rnd=%d mode=%d bulk=%d" " host=%s port=%d tout=%f bopts=%d\n\n", g_randseed, (long long)rnum, thnum, bin, rnd, mode, bulk, host, port, tout, bopts); bool err = false; oprintf("opening the database:\n"); double stime = kc::time(); kt::RemoteDB* dbs = new kt::RemoteDB[thnum]; for (int32_t i = 0; i < thnum; i++) { if (!dbs[i].open(host, port, tout)) { dberrprint(dbs + i, __LINE__, "DB::open"); err = true; } } if (mode != 'g' && mode != 'r' && !dbs[0].clear()) { dberrprint(dbs, __LINE__, "DB::clear"); err = true; } double etime = kc::time(); oprintf("time: %.3f\n", etime - stime); if (mode == 0 || mode == 's') { oprintf("setting records:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), bin_(false), rnd_(false), bulk_(0), bopts_(0), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool bin, bool rnd, int32_t bulk, int32_t bopts, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; bin_ = bin; rnd_ = rnd; bulk_ = bulk; bopts_ = bopts; db_ = db; } bool error() { return err_; } private: void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; std::map recs; std::vector bulkrecs; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); std::string key(kbuf, ksiz); int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; if (bin_) { kt::RemoteDB::BulkRecord rec = { 0, key, key, xt }; bulkrecs.push_back(rec); if (bulkrecs.size() >= (size_t)bulk_) { if (db_->set_bulk_binary(bulkrecs, bopts_) < 0) { dberrprint(db_, __LINE__, "DB::set_bulk_binary"); err_ = true; } bulkrecs.clear(); } } else { recs[key] = key; if (recs.size() >= (size_t)bulk_) { if (db_->set_bulk(recs, xt) != (int64_t)recs.size()) { dberrprint(db_, __LINE__, "DB::set_bulk"); err_ = true; } recs.clear(); } } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } if (bulkrecs.size() > 0) { if (db_->set_bulk_binary(bulkrecs, bopts_) < 0) { dberrprint(db_, __LINE__, "DB::set_bulk_binary"); err_ = true; } bulkrecs.clear(); } if (recs.size() > 0) { int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; if (db_->set_bulk(recs, xt) != (int64_t)recs.size()) { dberrprint(db_, __LINE__, "DB::set_bulk"); err_ = true; } recs.clear(); } } int32_t id_; int64_t rnum_; int32_t thnum_; bool bin_; bool rnd_; int32_t bulk_; int32_t bopts_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, bin, rnd, bulk, bopts, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, mode == 's'); oprintf("time: %.3f\n", etime - stime); } if (mode == 0 || mode == 'g') { oprintf("getting records:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), bin_(false), rnd_(false), bulk_(0), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool bin, bool rnd, int32_t bulk, int32_t bopts, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; bin_ = bin; rnd_ = rnd; bulk_ = bulk; bopts_ = bopts; db_ = db; } bool error() { return err_; } private: void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; std::vector keys; std::vector bulkrecs; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); std::string key(kbuf, ksiz); if (bin_) { kt::RemoteDB::BulkRecord rec = { 0, key, "", 0 }; bulkrecs.push_back(rec); if (bulkrecs.size() >= (size_t)bulk_) { if (db_->get_bulk_binary(&bulkrecs) < 0) { dberrprint(db_, __LINE__, "DB::get_bulk_binary"); err_ = true; } bulkrecs.clear(); } } else { keys.push_back(key); if (keys.size() >= (size_t)bulk_) { std::map recs; if (db_->get_bulk(keys, &recs) < 0) { dberrprint(db_, __LINE__, "DB::get_bulk"); err_ = true; } keys.clear(); } } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } if (bulkrecs.size() > 0) { if (db_->get_bulk_binary(&bulkrecs) < 0) { dberrprint(db_, __LINE__, "DB::get_bulk_binary"); err_ = true; } bulkrecs.clear(); } if (keys.size() > 0) { std::map recs; if (db_->get_bulk(keys, &recs) < 0) { dberrprint(db_, __LINE__, "DB::get_bulk"); err_ = true; } keys.clear(); } } int32_t id_; int64_t rnum_; int32_t thnum_; bool bin_; bool rnd_; int32_t bulk_; int32_t bopts_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, bin, rnd, bulk, bopts, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, mode == 'g'); oprintf("time: %.3f\n", etime - stime); } if (mode == 0 || mode == 'r') { oprintf("removing records:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), bin_(false), rnd_(false), bulk_(0), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool bin, bool rnd, int32_t bulk, int32_t bopts, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; bin_ = bin; rnd_ = rnd; bulk_ = bulk; bopts_ = bopts; db_ = db; } bool error() { return err_; } private: void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; std::vector keys; std::vector bulkrecs; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); std::string key(kbuf, ksiz); if (bin_) { kt::RemoteDB::BulkRecord rec = { 0, key, "", 0 }; bulkrecs.push_back(rec); if (bulkrecs.size() >= (size_t)bulk_) { if (db_->remove_bulk_binary(bulkrecs, bopts_) < 0) { dberrprint(db_, __LINE__, "DB::remove_bulk_binary"); err_ = true; } bulkrecs.clear(); } } else { keys.push_back(key); if (keys.size() >= (size_t)bulk_) { if (db_->remove_bulk(keys) < 0) { dberrprint(db_, __LINE__, "DB::remove_bulk"); err_ = true; } keys.clear(); } } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } if (bulkrecs.size() > 0) { if (db_->remove_bulk_binary(bulkrecs, bopts_) < 0) { dberrprint(db_, __LINE__, "DB::remove_bulk_binary"); err_ = true; } bulkrecs.clear(); } if (keys.size() > 0) { if (db_->remove_bulk(keys) < 0) { dberrprint(db_, __LINE__, "DB::remove_bulk"); err_ = true; } keys.clear(); } } int32_t id_; int64_t rnum_; int32_t thnum_; bool bin_; bool rnd_; int32_t bulk_; int32_t bopts_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, bin, rnd, bulk, bopts, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, mode == 'r'); oprintf("time: %.3f\n", etime - stime); } if (mode == 0 || mode == 'e') { oprintf("performing mixed operations:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), bin_(false), rnd_(false), bulk_(0), bopts_(0), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, bool bin, bool rnd, int32_t bulk, int32_t bopts, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; bin_ = bin; rnd_ = rnd; bulk_ = bulk; bopts_ = bopts; db_ = db; } bool error() { return err_; } private: void run() { std::map recs; std::vector keys; std::vector bulkrecs; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(rnum_) + 1 : i)); std::string key(kbuf, ksiz); int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; int32_t cmd; if (rnd_) { cmd = myrand(100); } else { cmd = i + id_; cmd = kc::hashmurmur(&cmd, sizeof(cmd)) % 100; } if (bin_) { kt::RemoteDB::BulkRecord rec = { 0, key, key, xt }; bulkrecs.push_back(rec); if (bulkrecs.size() >= (size_t)bulk_) { if (cmd < 50) { if (db_->get_bulk_binary(&bulkrecs) < 0) { dberrprint(db_, __LINE__, "DB::get_bulk_binary"); err_ = true; } } else if (cmd < 90) { if (db_->set_bulk_binary(bulkrecs, bopts_) < 0) { dberrprint(db_, __LINE__, "DB::set_bulk_binary"); err_ = true; } } else if (cmd < 98) { if (db_->remove_bulk_binary(bulkrecs, bopts_) < 0) { dberrprint(db_, __LINE__, "DB::remove_bulk_binary"); err_ = true; } } else { std::map params, result; params[key] = key; if (!db_->play_script_binary("echo", params, &result, bopts_) && db_->error() != kt::RemoteDB::Error::NOIMPL && db_->error() != kt::RemoteDB::Error::LOGIC && db_->error() != kt::RemoteDB::Error::INTERNAL) { dberrprint(db_, __LINE__, "DB::play_script_binary"); err_ = true; } } bulkrecs.clear(); } } else { recs[key] = key; keys.push_back(key); if (keys.size() >= (size_t)bulk_) { if (cmd < 50) { std::map recs; if (db_->get_bulk(keys, &recs) < 0) { dberrprint(db_, __LINE__, "DB::get_bulk"); err_ = true; } } else if (cmd < 90) { if (db_->set_bulk(recs, xt) != (int64_t)recs.size()) { dberrprint(db_, __LINE__, "DB::set_bulk"); err_ = true; } } else if (cmd < 98) { if (db_->remove_bulk(keys) < 0) { dberrprint(db_, __LINE__, "DB::remove_bulk"); err_ = true; } } else { std::map params, result; params[key] = key; if (!db_->play_script("echo", params, &result) && db_->error() != kt::RemoteDB::Error::NOIMPL && db_->error() != kt::RemoteDB::Error::LOGIC && db_->error() != kt::RemoteDB::Error::INTERNAL) { dberrprint(db_, __LINE__, "DB::play_script_binary"); err_ = true; } } recs.clear(); keys.clear(); } } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } if (bulkrecs.size() > 0) { if (db_->set_bulk_binary(bulkrecs, bopts_) < 0) { dberrprint(db_, __LINE__, "DB::set_bulk_binary"); err_ = true; } bulkrecs.clear(); } if (recs.size() > 0) { int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; if (db_->set_bulk(recs, xt) != (int64_t)recs.size()) { dberrprint(db_, __LINE__, "DB::set_bulk"); err_ = true; } recs.clear(); } } int32_t id_; int64_t rnum_; int32_t thnum_; bool bin_; bool rnd_; int32_t bulk_; int32_t bopts_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, bin, rnd, bulk, bopts, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, mode == 'e'); oprintf("time: %.3f\n", etime - stime); } oprintf("closing the database:\n"); stime = kc::time(); for (int32_t i = 0; i < thnum; i++) { if (!dbs[i].close()) { dberrprint(dbs + i, __LINE__, "DB::close"); err = true; } } etime = kc::time(); oprintf("time: %.3f\n", etime - stime); delete[] dbs; oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform wicked command static int32_t procwicked(int64_t rnum, int32_t thnum, int32_t itnum, const char* host, int32_t port, double tout) { oprintf("\n seed=%u rnum=%lld thnum=%d itnum=%d host=%s port=%d" " tout=%f\n\n", g_randseed, (long long)rnum, thnum, itnum, host, port, tout); bool err = false; for (int32_t itcnt = 1; itcnt <= itnum; itcnt++) { if (itnum > 1) oprintf("iteration %d:\n", itcnt); double stime = kc::time(); kt::RemoteDB* dbs = new kt::RemoteDB[thnum]; for (int32_t i = 0; i < thnum; i++) { if (!dbs[i].open(host, port, tout)) { dberrprint(dbs + i, __LINE__, "DB::open"); err = true; } } class ThreadWicked : public kc::Thread { public: void setparams(int32_t id, kt::RemoteDB* db, int64_t rnum, int32_t thnum, const char* lbuf) { id_ = id; db_ = db; rnum_ = rnum; thnum_ = thnum; lbuf_ = lbuf; err_ = false; } bool error() { return err_; } void run() { kt::RemoteDB::Cursor* cur = db_->cursor(); int64_t range = rnum_ * thnum_ / 2; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1)); if (myrand(1000) == 0) { ksiz = myrand(RECBUFSIZ) + 1; if (myrand(2) == 0) { for (size_t j = 0; j < ksiz; j++) { kbuf[j] = j; } } else { for (size_t j = 0; j < ksiz; j++) { kbuf[j] = myrand(256); } } } const char* vbuf = kbuf; size_t vsiz = ksiz; if (myrand(10) == 0) { vbuf = lbuf_; vsiz = myrand(RECBUFSIZL) / (myrand(5) + 1); } int64_t xt = myrand(600); if (myrand(100) == 0) db_->set_signal_sending(kbuf, myrand(10) == 0); do { switch (myrand(16)) { case 0: { if (!db_->set(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } break; } case 1: { if (!db_->add(kbuf, ksiz, vbuf, vsiz, xt) && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::add"); err_ = true; } break; } case 2: { if (!db_->replace(kbuf, ksiz, vbuf, vsiz, xt) && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::replace"); err_ = true; } break; } case 3: { if (!db_->append(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(db_, __LINE__, "DB::append"); err_ = true; } break; } case 4: { if (myrand(2) == 0) { int64_t num = myrand(rnum_); int64_t orig = myrand(10) == 0 ? kc::INT64MIN : myrand(rnum_); if (myrand(10) == 0) orig = orig == kc::INT64MIN ? kc::INT64MAX : -orig; if (db_->increment(kbuf, ksiz, num, orig, xt) == kc::INT64MIN && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::increment"); err_ = true; } } else { double num = myrand(rnum_ * 10) / (myrand(rnum_) + 1.0); double orig = myrand(10) == 0 ? -kc::inf() : myrand(rnum_); if (myrand(10) == 0) orig = -orig; if (kc::chknan(db_->increment_double(kbuf, ksiz, num, orig, xt)) && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::increment_double"); err_ = true; } } break; } case 5: { if (!db_->cas(kbuf, ksiz, kbuf, ksiz, vbuf, vsiz, xt) && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::cas"); err_ = true; } break; } case 6: { if (!db_->remove(kbuf, ksiz) && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::remove"); err_ = true; } break; } case 7: { if (myrand(2) == 0) { int32_t vsiz = db_->check(kbuf, ksiz); if (vsiz < 0 && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::check"); err_ = true; } } else { size_t rsiz; char* rbuf = db_->seize(kbuf, ksiz, &rsiz); if (rbuf) { delete[] rbuf; } else if (db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::seize"); err_ = true; } } break; } case 8: { if (myrand(10) == 0) { if (myrand(4) == 0) { if (!cur->jump_back(kbuf, ksiz) && db_->error() != kt::RemoteDB::Error::NOIMPL && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::jump_back"); err_ = true; } } else { if (!cur->jump(kbuf, ksiz) && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::jump"); err_ = true; } } } else { switch (myrand(3)) { case 0: { size_t vsiz = myrand(RECBUFSIZL) / (myrand(5) + 1); if (!cur->set_value(lbuf_, vsiz, xt, myrand(2) == 0) && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::set_value"); err_ = true; } break; } case 1: { if (!cur->remove() && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::remove"); err_ = true; } break; } } if (myrand(5) > 0 && !cur->step() && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "Cursor::step"); err_ = true; } } if (myrand(rnum_ / 50 + 1) == 0) { std::vector keys; std::string prefix(kbuf, ksiz > 0 ? ksiz - 1 : 0); if (db_->match_prefix(prefix, &keys, myrand(10)) == -1) { dberrprint(db_, __LINE__, "DB::match_prefix"); err_ = true; } } if (myrand(rnum_ / 50 + 1) == 0) { std::vector keys; std::string regex(kbuf, ksiz > 0 ? ksiz - 1 : 0); if (db_->match_regex(regex, &keys, myrand(10)) == -1 && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::match_regex"); err_ = true; } } if (myrand(rnum_ / 50 + 1) == 0) { std::vector keys; std::string origin(kbuf, ksiz > 0 ? ksiz - 1 : 0); if (db_->match_similar(origin, 3, myrand(2) == 0, &keys, myrand(10)) == -1) { dberrprint(db_, __LINE__, "DB::match_similar"); err_ = true; } } break; } case 9: { std::map recs; int32_t num = myrand(4); for (int32_t i = 0; i < num; i++) { ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1)); std::string key(kbuf, ksiz); recs[key] = std::string(vbuf, vsiz); } if (db_->set_bulk(recs, xt) != (int64_t)recs.size()) { dberrprint(db_, __LINE__, "DB::set_bulk"); err_ = true; } break; } case 10: { std::vector keys; int32_t num = myrand(4); for (int32_t i = 0; i < num; i++) { ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1)); keys.push_back(std::string(kbuf, ksiz)); } if (db_->remove_bulk(keys) < 0) { dberrprint(db_, __LINE__, "DB::remove_bulk"); err_ = true; } break; } case 11: { std::vector keys; int32_t num = myrand(4); for (int32_t i = 0; i < num; i++) { ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1)); keys.push_back(std::string(kbuf, ksiz)); } std::map recs; if (db_->get_bulk(keys, &recs) < 0) { dberrprint(db_, __LINE__, "DB::get_bulk"); err_ = true; } break; } default: { if (myrand(100) == 0) db_->set_signal_waiting(kbuf, 1.0 / (myrand(1000) + 1)); size_t rsiz; char* rbuf = db_->get(kbuf, ksiz, &rsiz); if (rbuf) { delete[] rbuf; } else if (db_->error() != kt::RemoteDB::Error::LOGIC && db_->error() != kt::RemoteDB::Error::TIMEOUT) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } break; } } } while (myrand(100) == 0); if (i == rnum_ / 2) { if (myrand(thnum_ * 4) == 0 && !db_->clear()) { dberrprint(db_, __LINE__, "DB::clear"); err_ = true; } else { if (!db_->synchronize(false)) { dberrprint(db_, __LINE__, "DB::synchronize"); err_ = true; } } } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } delete cur; } private: int32_t id_; kt::RemoteDB* db_; int64_t rnum_; int32_t thnum_; const char* lbuf_; bool err_; }; char lbuf[RECBUFSIZL]; std::memset(lbuf, '*', sizeof(lbuf)); ThreadWicked threads[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { threads[i].setparams(i, dbs + i, rnum, thnum, lbuf); threads[i].start(); } for (int32_t i = 0; i < thnum; i++) { threads[i].join(); if (threads[i].error()) err = true; } dbmetaprint(dbs, itcnt == itnum); for (int32_t i = 0; i < thnum; i++) { if (!dbs[i].close()) { dberrprint(dbs + i, __LINE__, "DB::close"); err = true; } } delete[] dbs; oprintf("time: %.3f\n", kc::time() - stime); } oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform usual command static int32_t procusual(int64_t rnum, int32_t thnum, int32_t itnum, const char* host, int32_t port, double tout, int64_t kp, int64_t vs, int64_t xt, double iv) { oprintf("\n seed=%u rnum=%lld thnum=%d itnum=%d host=%s port=%d" " tout=%f kp=%lld vs=%lld xt=%lld iv=%f\n\n", g_randseed, (long long)rnum, thnum, itnum, host, port, tout, kp, vs, xt, iv); bool err = false; oprintf("opening the database:\n"); double stime = kc::time(); kt::RemoteDB* dbs = new kt::RemoteDB[thnum]; for (int32_t i = 0; i < thnum; i++) { if (!dbs[i].open(host, port, tout)) { dberrprint(dbs + i, __LINE__, "DB::open"); err = true; } } double etime = kc::time(); oprintf("time: %.3f\n", etime - stime); oprintf("performing mixed operations:\n"); stime = kc::time(); class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), thnum_(0), db_(NULL), err_(false) {} void setparams(int32_t id, int64_t rnum, int32_t thnum, int64_t kp, int64_t vs, int64_t xt, double iv, kt::RemoteDB* db) { id_ = id; rnum_ = rnum; thnum_ = thnum; kp_ = kp; vs_ = vs; xt_ = xt; iv_ = iv; db_ = db; } bool error() { return err_; } private: void run() { size_t vsmax = vs_ > kc::INT8MAX ? vs_ : kc::INT8MAX; char* vbuf = new char[vsmax]; for (size_t i = 0; i < vsmax; i++) { vbuf[i] = 'A' + myrand('Z' - 'A'); } double slptime = 0; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)myrand(kp_)); std::memcpy(vbuf, kbuf, ksiz); int32_t cmd = myrand(100); if (cmd < 50) { size_t rsiz; char* rbuf = db_->get(kbuf, ksiz, &rsiz); if (rbuf) { delete[] rbuf; } else if (db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } } else if (cmd < 60) { if (!db_->remove(kbuf, ksiz) && db_->error() != kt::RemoteDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::remove"); err_ = true; } } else { size_t vsiz = vs_ > 0 ? vs_ : myrand(kc::INT8MAX); int64_t xt = xt_ == 0 ? kc::UINT32MAX : xt_ < 0 ? myrand(-xt_) + 1 : xt_; if (!db_->set(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } if (i % kc::INT8MAX == 0) { for (size_t i = 0; i < vsmax; i++) { vbuf[i] = 'A' + myrand('Z' - 'A'); } } if (iv_ > 0) { slptime += iv_; if (slptime >= 100) { Thread::sleep(slptime / 1000); slptime = 0; } } } delete[] vbuf; } int32_t id_; int64_t rnum_; int32_t thnum_; int64_t kp_; int64_t vs_; int64_t xt_; double iv_; kt::RemoteDB* db_; bool err_; }; Worker workers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, thnum, kp, vs, xt, iv, dbs + i); workers[i].start(); } for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; } etime = kc::time(); dbmetaprint(dbs, true); oprintf("time: %.3f\n", etime - stime); oprintf("closing the database:\n"); stime = kc::time(); for (int32_t i = 0; i < thnum; i++) { if (!dbs[i].close()) { dberrprint(dbs + i, __LINE__, "DB::close"); err = true; } } etime = kc::time(); oprintf("time: %.3f\n", etime - stime); delete[] dbs; oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // END OF FILE kyototycoon-0.9.56/kttimeddb.h0000644000175000017500000030464511757471602015364 0ustar mikiomikio/************************************************************************************************* * Timed database * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTTIMEDDB_H // duplication check #define _KTTIMEDDB_H #include #include #include #include namespace kyototycoon { // common namespace /** * Timed database. * @note This class is a concrete class of a wrapper for the polymorphic database to add * expiration features. This class can be inherited but overwriting methods is forbidden. * Before every database operation, it is necessary to call the TimedDB::open method in order to * open a database file and connect the database object to it. To avoid data missing or * corruption, it is important to close every database file by the TimedDB::close method when * the database is no longer in use. It is forbidden for multible database objects in a process * to open the same database at the same time. */ class TimedDB { public: class Cursor; class Visitor; class UpdateTrigger; /** The width of expiration time. */ static const int32_t XTWIDTH = 5; /** The maximum number of expiration time. */ static const int64_t XTMAX = (1LL << (XTWIDTH * 8)) - 1; private: class TimedVisitor; class TimedMetaTrigger; struct MergeLine; /* The magic data of the database type. */ static const uint8_t MAGICDATA = 0xbb; /* The score unit of expiratoin. */ static const int64_t XTSCUNIT = 256; /* The inverse frequency of reading expiration. */ static const int64_t XTREADFREQ = 8; /* The inverse frequency of iterating expiration. */ static const int64_t XTITERFREQ = 4; /* The unit step number of expiration. */ static const int64_t XTUNIT = 8; /* The size of the logging buffer. */ static const size_t LOGBUFSIZ = 1024; public: /** * Cursor to indicate a record. */ class Cursor { friend class TimedDB; public: /** * Constructor. * @param db the container database object. */ explicit Cursor(TimedDB* db) : db_(db), cur_(NULL), back_(false) { _assert_(db); cur_ = db_->db_.cursor(); } /** * Destructor. */ virtual ~Cursor() { _assert_(true); delete cur_; } /** * Jump the cursor to the first record for forward scan. * @return true on success, or false on failure. */ bool jump() { _assert_(true); if (!cur_->jump()) return false; back_ = false; return true; } /** * Jump the cursor to a record for forward scan. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @return true on success, or false on failure. */ bool jump(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); if (!cur_->jump(kbuf, ksiz)) return false; back_ = false; return true; } /** * Jump the cursor to a record for forward scan. * @note Equal to the original Cursor::jump method except that the parameter is std::string. */ bool jump(const std::string& key) { _assert_(true); return jump(key.c_str(), key.size()); } /** * Jump the cursor to the last record for backward scan. * @return true on success, or false on failure. * @note This method is dedicated to tree databases. Some database types, especially hash * databases, may provide a dummy implementation. */ bool jump_back() { _assert_(true); if (!cur_->jump_back()) return false; back_ = true; return true; } /** * Jump the cursor to a record for backward scan. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @return true on success, or false on failure. * @note This method is dedicated to tree databases. Some database types, especially hash * databases, will provide a dummy implementation. */ bool jump_back(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); if (!cur_->jump_back(kbuf, ksiz)) return false; back_ = true; return true; } /** * Jump the cursor to a record for backward scan. * @note Equal to the original Cursor::jump_back method except that the parameter is * std::string. */ bool jump_back(const std::string& key) { _assert_(true); return jump_back(key.c_str(), key.size()); } /** * Step the cursor to the next record. * @return true on success, or false on failure. */ bool step() { _assert_(true); if (!cur_->step()) return false; back_ = false; return true; } /** * Step the cursor to the previous record. * @return true on success, or false on failure. * @note This method is dedicated to tree databases. Some database types, especially hash * databases, may provide a dummy implementation. */ bool step_back() { _assert_(true); if (!cur_->step_back()) return false; back_ = true; return true; } /** * Accept a visitor to the current record. * @param visitor a visitor object. * @param writable true for writable operation, or false for read-only operation. * @param step true to move the cursor to the next record, or false for no move. * @return true on success, or false on failure. * @note the operation for each record is performed atomically and other threads accessing * the same record are blocked. */ bool accept(Visitor* visitor, bool writable = true, bool step = false) { _assert_(visitor); bool err = false; int64_t ct = std::time(NULL); while (true) { TimedVisitor myvisitor(db_, visitor, ct, true); if (!cur_->accept(&myvisitor, writable, step)) { err = true; break; } if (myvisitor.again()) { if (!step && !(back_ ? cur_->step_back() : cur_->step())) { err = true; break; } continue; } break; } if (db_->xcur_) { int64_t xtsc = writable ? XTSCUNIT : XTSCUNIT / XTREADFREQ; if (!db_->expire_records(xtsc)) err = true; } return !err; } /** * Set the value of the current record. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @param step true to move the cursor to the next record, or false for no move. * @return true on success, or false on failure. */ bool set_value(const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX, bool step = false) { _assert_(vbuf && vsiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl(const char* vbuf, size_t vsiz, int64_t xt) : vbuf_(vbuf), vsiz_(vsiz), xt_(xt), ok_(false) {} bool ok() const { return ok_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { ok_ = true; *sp = vsiz_; *xtp = xt_; return vbuf_; } const char* vbuf_; size_t vsiz_; int64_t xt_; bool ok_; }; VisitorImpl visitor(vbuf, vsiz, xt); if (!accept(&visitor, true, step)) return false; if (!visitor.ok()) return false; return true; } /** * Set the value of the current record. * @note Equal to the original Cursor::set_value method except that the parameter is * std::string. */ bool set_value_str(const std::string& value, int64_t xt = kc::INT64MAX, bool step = false) { _assert_(true); return set_value(value.c_str(), value.size(), xt, step); } /** * Remove the current record. * @return true on success, or false on failure. * @note If no record corresponds to the key, false is returned. The cursor is moved to the * next record implicitly. */ bool remove() { _assert_(true); class VisitorImpl : public Visitor { public: explicit VisitorImpl() : ok_(false) {} bool ok() const { return ok_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { ok_ = true; return REMOVE; } bool ok_; }; VisitorImpl visitor; if (!accept(&visitor, true, false)) return false; if (!visitor.ok()) return false; return true; } /** * Get the key of the current record. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param step true to move the cursor to the next record, or false for no move. * @return the pointer to the key region of the current record, or NULL on failure. * @note If the cursor is invalidated, NULL is returned. Because an additional zero * code is appended at the end of the region of the return value, the return value can be * treated as a C-style string. Because the region of the return value is allocated with the * the new[] operator, it should be released with the delete[] operator when it is no longer * in use. */ char* get_key(size_t* sp, bool step = false) { _assert_(sp); class VisitorImpl : public Visitor { public: explicit VisitorImpl() : kbuf_(NULL), ksiz_(0) {} char* pop(size_t* sp) { *sp = ksiz_; return kbuf_; } void clear() { delete[] kbuf_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { kbuf_ = new char[ksiz+1]; std::memcpy(kbuf_, kbuf, ksiz); kbuf_[ksiz] = '\0'; ksiz_ = ksiz; return NOP; } char* kbuf_; size_t ksiz_; }; VisitorImpl visitor; if (!accept(&visitor, false, step)) { visitor.clear(); *sp = 0; return NULL; } size_t ksiz; char* kbuf = visitor.pop(&ksiz); if (!kbuf) { *sp = 0; return NULL; } *sp = ksiz; return kbuf; } /** * Get the key of the current record. * @note Equal to the original Cursor::get_key method except that a parameter is a string to * contain the result and the return value is bool for success. */ bool get_key(std::string* key, bool step = false) { _assert_(key); size_t ksiz; char* kbuf = get_key(&ksiz, step); if (!kbuf) return false; key->clear(); key->append(kbuf, ksiz); delete[] kbuf; return true; } /** * Get the value of the current record. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param step true to move the cursor to the next record, or false for no move. * @return the pointer to the value region of the current record, or NULL on failure. * @note If the cursor is invalidated, NULL is returned. Because an additional zero * code is appended at the end of the region of the return value, the return value can be * treated as a C-style string. Because the region of the return value is allocated with the * the new[] operator, it should be released with the delete[] operator when it is no longer * in use. */ char* get_value(size_t* sp, bool step = false) { _assert_(sp); class VisitorImpl : public Visitor { public: explicit VisitorImpl() : vbuf_(NULL), vsiz_(0) {} char* pop(size_t* sp) { *sp = vsiz_; return vbuf_; } void clear() { delete[] vbuf_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { vbuf_ = new char[vsiz+1]; std::memcpy(vbuf_, vbuf, vsiz); vbuf_[vsiz] = '\0'; vsiz_ = vsiz; return NOP; } char* vbuf_; size_t vsiz_; }; VisitorImpl visitor; if (!accept(&visitor, false, step)) { visitor.clear(); *sp = 0; return NULL; } size_t vsiz; char* vbuf = visitor.pop(&vsiz); if (!vbuf) { *sp = 0; return NULL; } *sp = vsiz; return vbuf; } /** * Get the value of the current record. * @note Equal to the original Cursor::get_value method except that a parameter is a string * to contain the result and the return value is bool for success. */ bool get_value(std::string* value, bool step = false) { _assert_(value); size_t vsiz; char* vbuf = get_value(&vsiz, step); if (!vbuf) return false; value->clear(); value->append(vbuf, vsiz); delete[] vbuf; return true; } /** * Get a pair of the key and the value of the current record. * @param ksp the pointer to the variable into which the size of the region of the return * value is assigned. * @param vbp the pointer to the variable into which the pointer to the value region is * assigned. * @param vsp the pointer to the variable into which the size of the value region is * assigned. * @param xtp the pointer to the variable into which the absolute expiration time is * assigned. If it is NULL, it is ignored. * @param step true to move the cursor to the next record, or false for no move. * @return the pointer to the pair of the key region, or NULL on failure. * @note If the cursor is invalidated, NULL is returned. Because an additional zero code is * appended at the end of each region of the key and the value, each region can be treated * as a C-style string. The return value should be deleted explicitly by the caller with * the detele[] operator. */ char* get(size_t* ksp, const char** vbp, size_t* vsp, int64_t* xtp = NULL, bool step = false) { _assert_(ksp && vbp && vsp); class VisitorImpl : public Visitor { public: explicit VisitorImpl() : kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_(0), xt_(0) {} char* pop(size_t* ksp, const char** vbp, size_t* vsp, int64_t* xtp) { *ksp = ksiz_; *vbp = vbuf_; *vsp = vsiz_; if (xtp) *xtp = xt_; return kbuf_; } void clear() { delete[] kbuf_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { size_t rsiz = ksiz + 1 + vsiz + 1; kbuf_ = new char[rsiz]; std::memcpy(kbuf_, kbuf, ksiz); kbuf_[ksiz] = '\0'; ksiz_ = ksiz; vbuf_ = kbuf_ + ksiz + 1; std::memcpy(vbuf_, vbuf, vsiz); vbuf_[vsiz] = '\0'; vsiz_ = vsiz; xt_ = *xtp; return NOP; } char* kbuf_; size_t ksiz_; char* vbuf_; size_t vsiz_; int64_t xt_; }; VisitorImpl visitor; if (!accept(&visitor, false, step)) { visitor.clear(); *ksp = 0; *vbp = NULL; *vsp = 0; if (xtp) *xtp = 0; return NULL; } return visitor.pop(ksp, vbp, vsp, xtp); } /** * Get a pair of the key and the value of the current record. * @note Equal to the original Cursor::get method except that parameters are strings * to contain the result and the return value is bool for success. */ bool get(std::string* key, std::string* value, int64_t* xtp = NULL, bool step = false) { _assert_(key && value); class VisitorImpl : public Visitor { public: explicit VisitorImpl(std::string* key, std::string* value) : key_(key), value_(value), xt_(0), ok_(false) {} bool ok(int64_t* xtp) { if (xtp) *xtp = xt_; return ok_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { key_->clear(); key_->append(kbuf, ksiz); value_->clear(); value_->append(vbuf, vsiz); xt_ = *xtp; ok_ = true; return NOP; } std::string* key_; std::string* value_; int64_t xt_; bool ok_; }; VisitorImpl visitor(key, value); if (!accept(&visitor, false, step)) return false; return visitor.ok(xtp); } /** * Get a pair of the key and the value of the current record and remove it atomically. * @param ksp the pointer to the variable into which the size of the region of the return * value is assigned. * @param vbp the pointer to the variable into which the pointer to the value region is * assigned. * @param vsp the pointer to the variable into which the size of the value region is * assigned. * @param xtp the pointer to the variable into which the absolute expiration time is * assigned. If it is NULL, it is ignored. * @return the pointer to the pair of the key region, or NULL on failure. * @note If the cursor is invalidated, NULL is returned. Because an additional zero code is * appended at the end of each region of the key and the value, each region can be treated * as a C-style string. The return value should be deleted explicitly by the caller with * the detele[] operator. */ char* seize(size_t* ksp, const char** vbp, size_t* vsp, int64_t* xtp = NULL) { _assert_(ksp && vbp && vsp); class VisitorImpl : public Visitor { public: explicit VisitorImpl() : kbuf_(NULL), ksiz_(0), vbuf_(NULL), vsiz_(0), xt_(0) {} char* pop(size_t* ksp, const char** vbp, size_t* vsp, int64_t* xtp) { *ksp = ksiz_; *vbp = vbuf_; *vsp = vsiz_; if (xtp) *xtp = xt_; return kbuf_; } void clear() { delete[] kbuf_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { size_t rsiz = ksiz + 1 + vsiz + 1; kbuf_ = new char[rsiz]; std::memcpy(kbuf_, kbuf, ksiz); kbuf_[ksiz] = '\0'; ksiz_ = ksiz; vbuf_ = kbuf_ + ksiz + 1; std::memcpy(vbuf_, vbuf, vsiz); vbuf_[vsiz] = '\0'; vsiz_ = vsiz; xt_ = *xtp; return REMOVE; } char* kbuf_; size_t ksiz_; char* vbuf_; size_t vsiz_; int64_t xt_; }; VisitorImpl visitor; if (!accept(&visitor, true, false)) { visitor.clear(); *ksp = 0; *vbp = NULL; *vsp = 0; if (xtp) *xtp = 0; return NULL; } return visitor.pop(ksp, vbp, vsp, xtp); } /** * Get a pair of the key and the value of the current record and remove it atomically. * @note Equal to the original Cursor::seize method except that parameters are strings * to contain the result and the return value is bool for success. */ bool seize(std::string* key, std::string* value, int64_t* xtp = NULL) { _assert_(key && value); class VisitorImpl : public Visitor { public: explicit VisitorImpl(std::string* key, std::string* value) : key_(key), value_(value), xt_(0), ok_(false) {} bool ok(int64_t* xtp) { if (xtp) *xtp = xt_; return ok_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { key_->clear(); key_->append(kbuf, ksiz); value_->clear(); value_->append(vbuf, vsiz); xt_ = *xtp; ok_ = true; return REMOVE; } std::string* key_; std::string* value_; int64_t xt_; bool ok_; }; VisitorImpl visitor(key, value); if (!accept(&visitor, true, false)) return false; return visitor.ok(xtp); } /** * Get the database object. * @return the database object. */ TimedDB* db() { _assert_(true); return db_; } /** * Get the last happened error. * @return the last happened error. */ kc::BasicDB::Error error() { _assert_(true); return db()->error(); } private: /** Dummy constructor to forbid the use. */ Cursor(const Cursor&); /** Dummy Operator to forbid the use. */ Cursor& operator =(const Cursor&); /** The inner database. */ TimedDB* db_; /** The inner cursor. */ kc::BasicDB::Cursor* cur_; /** The backward flag. */ bool back_; }; /** * Interface to access a record. */ class Visitor { public: /** Special pointer for no operation. */ static const char* const NOP; /** Special pointer to remove the record. */ static const char* const REMOVE; /** * Destructor. */ virtual ~Visitor() { _assert_(true); } /** * Visit a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param xtp the pointer to the variable into which the expiration time from now in seconds * is assigned. The initial value is the absolute expiration time. * @return If it is the pointer to a region, the value is replaced by the content. If it * is Visitor::NOP, nothing is modified. If it is Visitor::REMOVE, the record is removed. */ virtual const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ && sp && xtp); return NOP; } /** * Visit a empty record space. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param xtp the pointer to the variable into which the expiration time from now in seconds * is assigned. * @return If it is the pointer to a region, the value is replaced by the content. If it * is Visitor::NOP or Visitor::REMOVE, nothing is modified. */ virtual const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && sp && xtp); return NOP; } /** * Preprocess the main operations. */ virtual void visit_before() { _assert_(true); } /** * Postprocess the main operations. */ virtual void visit_after() { _assert_(true); } }; /** * Interface to trigger update operations. */ class UpdateTrigger { public: /** * Destructor. */ virtual ~UpdateTrigger() { _assert_(true); } /** * Trigger an update operation. * @param mbuf the pointer to the message region. * @param msiz the size of the message region. */ virtual void trigger(const char* mbuf, size_t msiz) = 0; /** * Begin transaction. */ virtual void begin_transaction() = 0; /** * End transaction. * @param commit true to commit the transaction, or false to abort the transaction. */ virtual void end_transaction(bool commit) = 0; }; /** * Merge modes. */ enum MergeMode { MSET, ///< overwrite the existing value MADD, ///< keep the existing value MREPLACE, ///< modify the existing record only MAPPEND ///< append the new value }; /** * Default constructor. */ explicit TimedDB() : xlock_(), db_(), mtrigger_(this), utrigger_(NULL), omode_(0), opts_(0), capcnt_(0), capsiz_(0), xcur_(NULL), xsc_(0) { _assert_(true); db_.tune_meta_trigger(&mtrigger_); } /** * Destructor. */ virtual ~TimedDB() { _assert_(true); if (omode_ != 0) close(); } /** * Set the internal database object. * @param db the internal database object. Its possession is transferred inside and the * object is deleted automatically. * @return true on success, or false on failure. */ bool set_internal_db(kc::BasicDB* db) { _assert_(db); if (omode_ != 0) { set_error(kc::BasicDB::Error::INVALID, "already opened"); return false; } db_.set_internal_db(db); return true; } /** * Get the last happened error. * @return the last happened error. */ kc::BasicDB::Error error() const { _assert_(true); return db_.error(); } /** * Set the error information. * @param code an error code. * @param message a supplement message. */ void set_error(kc::BasicDB::Error::Code code, const char* message) { _assert_(message); db_.set_error(code, message); } /** * Open a database file. * @param path the path of a database file. The same as with kc::PolyDB. In addition, the * following tuning parameters are supported. "ktopts" sets options and the value can contain * "p" for the persistent option. "ktcapcnt" sets the capacity by record number. "ktcapsiz" * sets the capacity by database size. * @param mode the connection mode. The same as with kc::PolyDB. * @return true on success, or false on failure. */ bool open(const std::string& path = ":", uint32_t mode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE) { _assert_(true); if (omode_ != 0) { set_error(kc::BasicDB::Error::INVALID, "already opened"); return false; } kc::ScopedSpinLock lock(&xlock_); std::vector elems; kc::strsplit(path, '#', &elems); capcnt_ = -1; capsiz_ = -1; opts_ = 0; std::vector::iterator it = elems.begin(); std::vector::iterator itend = elems.end(); if (it != itend) ++it; while (it != itend) { std::vector fields; if (kc::strsplit(*it, '=', &fields) > 1) { const char* key = fields[0].c_str(); const char* value = fields[1].c_str(); if (!std::strcmp(key, "ktcapcnt") || !std::strcmp(key, "ktcapcount") || !std::strcmp(key, "ktcap_count")) { capcnt_ = kc::atoix(value); } else if (!std::strcmp(key, "ktcapsiz") || !std::strcmp(key, "ktcapsize") || !std::strcmp(key, "ktcap_size")) { capsiz_ = kc::atoix(value); } else if (!std::strcmp(key, "ktopts") || !std::strcmp(key, "ktoptions")) { if (std::strchr(value, 'p')) opts_ |= TPERSIST; } } ++it; } if (!db_.open(path, mode)) return false; kc::BasicDB* idb = db_.reveal_inner_db(); if (idb) { const std::type_info& info = typeid(*idb); if (info == typeid(kc::HashDB)) { kc::HashDB* hdb = (kc::HashDB*)idb; char* opq = hdb->opaque(); if (opq) { if (*(uint8_t*)opq == MAGICDATA) { opts_ = *(uint8_t*)(opq + 1); } else if ((mode & kc::BasicDB::OWRITER) && hdb->count() < 1) { *(uint8_t*)opq = MAGICDATA; *(uint8_t*)(opq + 1) = opts_; hdb->synchronize_opaque(); } } } else if (info == typeid(kc::TreeDB)) { kc::TreeDB* tdb = (kc::TreeDB*)idb; char* opq = tdb->opaque(); if (opq) { if (*(uint8_t*)opq == MAGICDATA) { opts_ = *(uint8_t*)(opq + 1); } else if ((mode & kc::BasicDB::OWRITER) && tdb->count() < 1) { *(uint8_t*)opq = MAGICDATA; *(uint8_t*)(opq + 1) = opts_; tdb->synchronize_opaque(); } } } else if (info == typeid(kc::DirDB)) { kc::DirDB* ddb = (kc::DirDB*)idb; char* opq = ddb->opaque(); if (opq) { if (*(uint8_t*)opq == MAGICDATA) { opts_ = *(uint8_t*)(opq + 1); } else if ((mode & kc::BasicDB::OWRITER) && ddb->count() < 1) { *(uint8_t*)opq = MAGICDATA; *(uint8_t*)(opq + 1) = opts_; ddb->synchronize_opaque(); } } } else if (info == typeid(kc::ForestDB)) { kc::ForestDB* fdb = (kc::ForestDB*)idb; char* opq = fdb->opaque(); if (opq) { if (*(uint8_t*)opq == MAGICDATA) { opts_ = *(uint8_t*)(opq + 1); } else if ((mode & kc::BasicDB::OWRITER) && fdb->count() < 1) { *(uint8_t*)opq = MAGICDATA; *(uint8_t*)(opq + 1) = opts_; fdb->synchronize_opaque(); } } } } omode_ = mode; if ((omode_ & kc::BasicDB::OWRITER) && !(opts_ & TPERSIST)) { xcur_ = db_.cursor(); if (db_.count() > 0) xcur_->jump(); } xsc_ = 0; return true; } /** * Close the database file. * @return true on success, or false on failure. */ bool close() { _assert_(true); if (omode_ == 0) { set_error(kc::BasicDB::Error::INVALID, "not opened"); return false; } kc::ScopedSpinLock lock(&xlock_); bool err = false; delete xcur_; xcur_ = NULL; if (!db_.close()) err = true; omode_ = 0; return !err; } /** * Accept a visitor to a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param visitor a visitor object. * @param writable true for writable operation, or false for read-only operation. * @return true on success, or false on failure. * @note the operation for each record is performed atomically and other threads accessing the * same record are blocked. */ bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && visitor); bool err = false; int64_t ct = std::time(NULL); TimedVisitor myvisitor(this, visitor, ct, false); if (!db_.accept(kbuf, ksiz, &myvisitor, writable)) err = true; if (xcur_) { int64_t xtsc = writable ? XTSCUNIT : XTSCUNIT / XTREADFREQ; if (!expire_records(xtsc)) err = true; } return !err; } /** * Accept a visitor to multiple records at once. * @param keys specifies a string vector of the keys. * @param visitor a visitor object. * @param writable true for writable operation, or false for read-only operation. * @return true on success, or false on failure. * @note The operations for specified records are performed atomically and other threads * accessing the same records are blocked. To avoid deadlock, any database operation must not * be performed in this function. */ bool accept_bulk(const std::vector& keys, Visitor* visitor, bool writable = true) { _assert_(visitor); bool err = false; int64_t ct = std::time(NULL); TimedVisitor myvisitor(this, visitor, ct, false); if (!db_.accept_bulk(keys, &myvisitor, writable)) err = true; if (xcur_) { int64_t xtsc = writable ? XTSCUNIT : XTSCUNIT / XTREADFREQ; if (!expire_records(xtsc)) err = true; } return !err; } /** * Iterate to accept a visitor for each record. * @param visitor a visitor object. * @param writable true for writable operation, or false for read-only operation. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. * @note The whole iteration is performed atomically and other threads are blocked. */ bool iterate(Visitor *visitor, bool writable = true, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(visitor); bool err = false; int64_t ct = std::time(NULL); TimedVisitor myvisitor(this, visitor, ct, true); if (!db_.iterate(&myvisitor, writable, checker)) err = true; if (xcur_) { int64_t count = db_.count(); int64_t xtsc = writable ? XTSCUNIT : XTSCUNIT / XTREADFREQ; if (count > 0) xtsc *= count / XTITERFREQ; if (!expire_records(xtsc)) err = true; } return !err; } /** * Scan each record in parallel. * @param visitor a visitor object. * @param thnum the number of worker threads. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. * @note This function is for reading records and not for updating ones. The return value of * the visitor is just ignored. To avoid deadlock, any explicit database operation must not * be performed in this function. */ bool scan_parallel(Visitor *visitor, size_t thnum, kc::BasicDB::ProgressChecker* checker = NULL) { bool err = false; int64_t ct = std::time(NULL); TimedVisitor myvisitor(this, visitor, ct, true); if (!db_.scan_parallel(&myvisitor, thnum, checker)) err = true; if (xcur_) { int64_t count = db_.count(); int64_t xtsc = XTSCUNIT / XTREADFREQ; if (count > 0) xtsc *= count / XTITERFREQ; if (!expire_records(xtsc)) err = true; } return !err; } /** * Synchronize updated contents with the file and the device. * @param hard true for physical synchronization with the device, or false for logical * synchronization with the file system. * @param proc a postprocessor object. If it is NULL, no postprocessing is performed. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. * @note The operation of the postprocessor is performed atomically and other threads accessing * the same record are blocked. To avoid deadlock, any explicit database operation must not * be performed in this function. */ bool synchronize(bool hard = false, kc::BasicDB::FileProcessor* proc = NULL, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(true); return db_.synchronize(hard, proc, checker); } /** * Occupy database by locking and do something meanwhile. * @param writable true to use writer lock, or false to use reader lock. * @param proc a processor object. If it is NULL, no processing is performed. * @return true on success, or false on failure. * @note The operation of the processor is performed atomically and other threads accessing * the same record are blocked. To avoid deadlock, any explicit database operation must not * be performed in this function. */ bool occupy(bool writable = true, kc::BasicDB::FileProcessor* proc = NULL) { _assert_(true); return db_.occupy(writable, proc); } /** * Create a copy of the database file. * @param dest the path of the destination file. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. */ bool copy(const std::string& dest, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(true); return db_.copy(dest, checker); } /** * Begin transaction. * @param hard true for physical synchronization with the device, or false for logical * synchronization with the file system. * @return true on success, or false on failure. */ bool begin_transaction(bool hard = false) { _assert_(true); return db_.begin_transaction(hard); } /** * Try to begin transaction. * @param hard true for physical synchronization with the device, or false for logical * synchronization with the file system. * @return true on success, or false on failure. */ bool begin_transaction_try(bool hard = false) { _assert_(true); return db_.begin_transaction_try(hard); } /** * End transaction. * @param commit true to commit the transaction, or false to abort the transaction. * @return true on success, or false on failure. */ bool end_transaction(bool commit = true) { _assert_(true); return db_.end_transaction(commit); } /** * Remove all records. * @return true on success, or false on failure. */ bool clear() { _assert_(true); return db_.clear(); } /** * Get the number of records. * @return the number of records, or -1 on failure. */ int64_t count() { _assert_(true); return db_.count(); } /** * Get the size of the database file. * @return the size of the database file in bytes, or -1 on failure. */ int64_t size() { _assert_(true); return db_.size(); } /** * Get the path of the database file. * @return the path of the database file, or an empty string on failure. */ std::string path() { _assert_(true); return db_.path(); } /** * Get the miscellaneous status information. * @param strmap a string map to contain the result. * @return true on success, or false on failure. */ bool status(std::map* strmap) { _assert_(strmap); if (!db_.status(strmap)) return false; (*strmap)["ktopts"] = kc::strprintf("%u", opts_); (*strmap)["ktcapcnt"] = kc::strprintf("%lld", (long long)capcnt_); (*strmap)["ktcapsiz"] = kc::strprintf("%lld", (long long)capsiz_); return true; } /** * Set the value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. * @note If no record corresponds to the key, a new record is created. If the corresponding * record exists, the value is overwritten. */ bool set(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl(const char* vbuf, size_t vsiz, int64_t xt) : vbuf_(vbuf), vsiz_(vsiz), xt_(xt) {} private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { *sp = vsiz_; *xtp = xt_; return vbuf_; } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { *sp = vsiz_; *xtp = xt_; return vbuf_; } const char* vbuf_; size_t vsiz_; int64_t xt_; }; VisitorImpl visitor(vbuf, vsiz, xt); if (!accept(kbuf, ksiz, &visitor, true)) return false; return true; } /** * Set the value of a record. * @note Equal to the original DB::set method except that the parameters are std::string. */ bool set(const std::string& key, const std::string& value, int64_t xt = kc::INT64MAX) { _assert_(true); return set(key.c_str(), key.size(), value.c_str(), value.size(), xt); } /** * Add a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. * @note If no record corresponds to the key, a new record is created. If the corresponding * record exists, the record is not modified and false is returned. */ bool add(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl(const char* vbuf, size_t vsiz, int64_t xt) : vbuf_(vbuf), vsiz_(vsiz), xt_(xt), ok_(false) {} bool ok() const { return ok_; } private: const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { ok_ = true; *sp = vsiz_; *xtp = xt_; return vbuf_; } const char* vbuf_; size_t vsiz_; int64_t xt_; bool ok_; }; VisitorImpl visitor(vbuf, vsiz, xt); if (!accept(kbuf, ksiz, &visitor, true)) return false; if (!visitor.ok()) { set_error(kc::BasicDB::Error::DUPREC, "record duplication"); return false; } return true; } /** * Set the value of a record. * @note Equal to the original DB::add method except that the parameters are std::string. */ bool add(const std::string& key, const std::string& value, int64_t xt = kc::INT64MAX) { _assert_(true); return add(key.c_str(), key.size(), value.c_str(), value.size(), xt); } /** * Replace the value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. * @note If no record corresponds to the key, no new record is created and false is returned. * If the corresponding record exists, the value is modified. */ bool replace(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl(const char* vbuf, size_t vsiz, int64_t xt) : vbuf_(vbuf), vsiz_(vsiz), xt_(xt), ok_(false) {} bool ok() const { return ok_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { ok_ = true; *sp = vsiz_; *xtp = xt_; return vbuf_; } const char* vbuf_; size_t vsiz_; int64_t xt_; bool ok_; }; VisitorImpl visitor(vbuf, vsiz, xt); if (!accept(kbuf, ksiz, &visitor, true)) return false; if (!visitor.ok()) { set_error(kc::BasicDB::Error::NOREC, "no record"); return false; } return true; } /** * Replace the value of a record. * @note Equal to the original DB::replace method except that the parameters are std::string. */ bool replace(const std::string& key, const std::string& value, int64_t xt = kc::INT64MAX) { _assert_(true); return replace(key.c_str(), key.size(), value.c_str(), value.size(), xt); } /** * Append the value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. * @note If no record corresponds to the key, a new record is created. If the corresponding * record exists, the given value is appended at the end of the existing value. */ bool append(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl(const char* vbuf, size_t vsiz, int64_t xt) : vbuf_(vbuf), vsiz_(vsiz), xt_(xt), nbuf_(NULL) {} ~VisitorImpl() { if (nbuf_) delete[] nbuf_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { size_t nsiz = vsiz + vsiz_; nbuf_ = new char[nsiz]; std::memcpy(nbuf_, vbuf, vsiz); std::memcpy(nbuf_ + vsiz, vbuf_, vsiz_); *sp = nsiz; *xtp = xt_; return nbuf_; } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { *sp = vsiz_; *xtp = xt_; return vbuf_; } const char* vbuf_; size_t vsiz_; int64_t xt_; char* nbuf_; }; VisitorImpl visitor(vbuf, vsiz, xt); if (!accept(kbuf, ksiz, &visitor, true)) return false; return true; } /** * Set the value of a record. * @note Equal to the original DB::append method except that the parameters are std::string. */ bool append(const std::string& key, const std::string& value, int64_t xt = kc::INT64MAX) { _assert_(true); return append(key.c_str(), key.size(), value.c_str(), value.size(), xt); } /** * Add a number to the numeric integer value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param num the additional number. * @param orig the origin number if no record corresponds to the key. If it is INT64MIN and * no record corresponds, this function fails. If it is INT64MAX, the value is set as the * additional number regardless of the current value. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return the result value, or kyotocabinet::INT64MIN on failure. * @note The value is serialized as an 8-byte binary integer in big-endian order, not a decimal * string. If existing value is not 8-byte, this function fails. */ int64_t increment(const char* kbuf, size_t ksiz, int64_t num, int64_t orig = 0, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl(int64_t num, int64_t orig, int64_t xt) : num_(num), orig_(orig), xt_(xt), big_(0) {} int64_t num() { return num_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { if (vsiz != sizeof(num_)) { num_ = kc::INT64MIN; return NOP; } int64_t onum; if (orig_ == kc::INT64MAX) { onum = 0; } else { std::memcpy(&onum, vbuf, vsiz); onum = kc::ntoh64(onum); if (num_ == 0) { num_ = onum; return NOP; } } num_ += onum; big_ = kc::hton64(num_); *sp = sizeof(big_); *xtp = xt_; return (const char*)&big_; } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { if (orig_ == kc::INT64MIN) { num_ = kc::INT64MIN; return NOP; } if (orig_ != kc::INT64MAX) num_ += orig_; big_ = kc::hton64(num_); *sp = sizeof(big_); *xtp = xt_; return (const char*)&big_; } int64_t num_; int64_t orig_; int64_t xt_; uint64_t big_; }; VisitorImpl visitor(num, orig, xt); if (!accept(kbuf, ksiz, &visitor, num != 0 || orig != kc::INT64MIN)) return kc::INT64MIN; num = visitor.num(); if (num == kc::INT64MIN) { set_error(kc::BasicDB::Error::LOGIC, "logical inconsistency"); return num; } return num; } /** * Add a number to the numeric integer value of a record. * @note Equal to the original DB::increment method except that the parameter is std::string. */ int64_t increment(const std::string& key, int64_t num, int64_t orig = 0, int64_t xt = kc::INT64MAX) { _assert_(true); return increment(key.c_str(), key.size(), num, orig, xt); } /** * Add a number to the numeric double value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param num the additional number. * @param orig the origin number if no record corresponds to the key. If it is negative * infinity and no record corresponds, this function fails. If it is positive infinity, the * value is set as the additional number regardless of the current value. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return the result value, or Not-a-number on failure. * @note The value is serialized as an 16-byte binary fixed-point number in big-endian order, * not a decimal string. If existing value is not 16-byte, this function fails. */ double increment_double(const char* kbuf, size_t ksiz, double num, double orig = 0, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl(double num, double orig, int64_t xt) : DECUNIT(1000000000000000LL), num_(num), orig_(orig), xt_(xt), buf_() {} double num() { return num_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { if (vsiz != sizeof(buf_)) { num_ = kc::nan(); return NOP; } int64_t linteg, lfract; if (kc::chkinf(orig_) && orig_ >= 0) { linteg = 0; lfract = 0; } else { std::memcpy(&linteg, vbuf, sizeof(linteg)); linteg = kc::ntoh64(linteg); std::memcpy(&lfract, vbuf + sizeof(linteg), sizeof(lfract)); lfract = kc::ntoh64(lfract); } if (lfract == kc::INT64MIN && linteg == kc::INT64MIN) { num_ = kc::nan(); return NOP; } else if (linteg == kc::INT64MAX) { num_ = HUGE_VAL; return NOP; } else if (linteg == kc::INT64MIN) { num_ = -HUGE_VAL; return NOP; } if (num_ == 0.0 && !(kc::chkinf(orig_) && orig_ >= 0)) { num_ = linteg + (double)lfract / DECUNIT; return NOP; } long double dinteg; long double dfract = std::modfl(num_, &dinteg); if (kc::chknan(dinteg)) { linteg = kc::INT64MIN; lfract = kc::INT64MIN; num_ = kc::nan(); } else if (kc::chkinf(dinteg)) { linteg = dinteg > 0 ? kc::INT64MAX : kc::INT64MIN; lfract = 0; num_ = dinteg; } else { linteg += (int64_t)dinteg; lfract += (int64_t)(dfract * DECUNIT); if (lfract >= DECUNIT) { linteg += 1; lfract -= DECUNIT; } num_ = linteg + (double)lfract / DECUNIT; } linteg = kc::hton64(linteg); std::memcpy(buf_, &linteg, sizeof(linteg)); lfract = kc::hton64(lfract); std::memcpy(buf_ + sizeof(linteg), &lfract, sizeof(lfract)); *sp = sizeof(buf_); *xtp = xt_; return buf_; } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { if (kc::chknan(orig_) || (kc::chkinf(orig_) && orig_ < 0)) { num_ = kc::nan(); return NOP; } if (!kc::chkinf(orig_)) num_ += orig_; long double dinteg; long double dfract = std::modfl(num_, &dinteg); int64_t linteg, lfract; if (kc::chknan(dinteg)) { linteg = kc::INT64MIN; lfract = kc::INT64MIN; } else if (kc::chkinf(dinteg)) { linteg = dinteg > 0 ? kc::INT64MAX : kc::INT64MIN; lfract = 0; } else { linteg = (int64_t)dinteg; lfract = (int64_t)(dfract * DECUNIT); } linteg = kc::hton64(linteg); std::memcpy(buf_, &linteg, sizeof(linteg)); lfract = kc::hton64(lfract); std::memcpy(buf_ + sizeof(linteg), &lfract, sizeof(lfract)); *sp = sizeof(buf_); *xtp = xt_; return buf_; } const int64_t DECUNIT; double num_; double orig_; int64_t xt_; char buf_[sizeof(int64_t)*2]; }; VisitorImpl visitor(num, orig, xt); if (!accept(kbuf, ksiz, &visitor, true)) return kc::nan(); num = visitor.num(); if (kc::chknan(num)) { set_error(kc::BasicDB::Error::LOGIC, "logical inconsistency"); return kc::nan(); } return num; } /** * Add a number to the numeric double value of a record. * @note Equal to the original DB::increment_double method except that the parameter is * std::string. */ double increment_double(const std::string& key, double num, double orig = 0, int64_t xt = kc::INT64MAX) { _assert_(true); return increment_double(key.c_str(), key.size(), num, orig, xt); } /** * Perform compare-and-swap. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param ovbuf the pointer to the old value region. NULL means that no record corresponds. * @param ovsiz the size of the old value region. * @param nvbuf the pointer to the new value region. NULL means that the record is removed. * @param nvsiz the size of new old value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. */ bool cas(const char* kbuf, size_t ksiz, const char* ovbuf, size_t ovsiz, const char* nvbuf, size_t nvsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl(const char* ovbuf, size_t ovsiz, const char* nvbuf, size_t nvsiz, int64_t xt) : ovbuf_(ovbuf), ovsiz_(ovsiz), nvbuf_(nvbuf), nvsiz_(nvsiz), xt_(xt), ok_(false) {} bool ok() const { return ok_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { if (!ovbuf_ || vsiz != ovsiz_ || std::memcmp(vbuf, ovbuf_, vsiz)) return NOP; ok_ = true; if (!nvbuf_) return REMOVE; *sp = nvsiz_; *xtp = xt_; return nvbuf_; } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { if (ovbuf_) return NOP; ok_ = true; if (!nvbuf_) return NOP; *sp = nvsiz_; *xtp = xt_; return nvbuf_; } const char* ovbuf_; size_t ovsiz_; const char* nvbuf_; size_t nvsiz_; int64_t xt_; bool ok_; }; VisitorImpl visitor(ovbuf, ovsiz, nvbuf, nvsiz, xt); if (!accept(kbuf, ksiz, &visitor, true)) return false; if (!visitor.ok()) { set_error(kc::BasicDB::Error::LOGIC, "status conflict"); return false; } return true; } /** * Perform compare-and-swap. * @note Equal to the original DB::cas method except that the parameters are std::string. */ bool cas(const std::string& key, const std::string& ovalue, const std::string& nvalue, int64_t xt = kc::INT64MAX) { _assert_(true); return cas(key.c_str(), key.size(), ovalue.c_str(), ovalue.size(), nvalue.c_str(), nvalue.size(), xt); } /** * Remove a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @return true on success, or false on failure. * @note If no record corresponds to the key, false is returned. */ bool remove(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl() : ok_(false) {} bool ok() const { return ok_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { ok_ = true; return REMOVE; } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { return REMOVE; } bool ok_; }; VisitorImpl visitor; if (!accept(kbuf, ksiz, &visitor, true)) return false; if (!visitor.ok()) { set_error(kc::BasicDB::Error::NOREC, "no record"); return false; } return true; } /** * Remove a record. * @note Equal to the original DB::remove method except that the parameter is std::string. */ bool remove(const std::string& key) { _assert_(true); return remove(key.c_str(), key.size()); } /** * Retrieve the value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param xtp the pointer to the variable into which the absolute expiration time is assigned. * If it is NULL, it is ignored. * @return the pointer to the value region of the corresponding record, or NULL on failure. * @note If no record corresponds to the key, NULL is returned. Because an additional zero * code is appended at the end of the region of the return value, the return value can be * treated as a C-style string. Because the region of the return value is allocated with the * the new[] operator, it should be released with the delete[] operator when it is no longer * in use. */ char* get(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp = NULL) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && sp); class VisitorImpl : public Visitor { public: explicit VisitorImpl() : vbuf_(NULL), vsiz_(0), xt_(0) {} char* pop(size_t* sp, int64_t* xtp) { *sp = vsiz_; if (xtp) *xtp = xt_; return vbuf_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { vbuf_ = new char[vsiz+1]; std::memcpy(vbuf_, vbuf, vsiz); vbuf_[vsiz] = '\0'; vsiz_ = vsiz; xt_ = *xtp; return NOP; } char* vbuf_; size_t vsiz_; int64_t xt_; }; VisitorImpl visitor; if (!accept(kbuf, ksiz, &visitor, false)) { *sp = 0; if (xtp) *xtp = 0; return NULL; } size_t vsiz; char* vbuf = visitor.pop(&vsiz, xtp); if (!vbuf) { set_error(kc::BasicDB::Error::NOREC, "no record"); *sp = 0; if (xtp) *xtp = 0; return NULL; } *sp = vsiz; return vbuf; } /** * Retrieve the value of a record. * @note Equal to the original DB::get method except that the first parameters is the key * string and the second parameter is a string to contain the result and the return value is * bool for success. */ bool get(const std::string& key, std::string* value, int64_t* xtp = NULL) { _assert_(value); class VisitorImpl : public Visitor { public: explicit VisitorImpl(std::string* value) : value_(value), ok_(false), xt_(0) {} bool ok(int64_t* xtp) { if (xtp) *xtp = xt_; return ok_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { value_->clear(); value_->append(vbuf, vsiz); ok_ = true; xt_ = *xtp; return NOP; } std::string* value_; bool ok_; int64_t xt_; }; VisitorImpl visitor(value); if (!accept(key.data(), key.size(), &visitor, false)) { if (xtp) *xtp = 0; return false; } if (!visitor.ok(xtp)) { set_error(kc::BasicDB::Error::NOREC, "no record"); return false; } return true; } /** * Retrieve the value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the buffer into which the value of the corresponding record is * written. * @param max the size of the buffer. * @param xtp the pointer to the variable into which the expiration time from now in seconds * is assigned. If it is NULL, it is ignored. * @return the size of the value, or -1 on failure. */ int32_t get(const char* kbuf, size_t ksiz, char* vbuf, size_t max, int64_t* xtp = NULL) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf); class VisitorImpl : public Visitor { public: explicit VisitorImpl(char* vbuf, size_t max) : vbuf_(vbuf), max_(max), vsiz_(-1), xt_(0) {} int32_t vsiz(int64_t* xtp) { if (xtp) *xtp = xt_; return vsiz_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { vsiz_ = vsiz; xt_ = *xtp; size_t max = vsiz < max_ ? vsiz : max_; std::memcpy(vbuf_, vbuf, max); return NOP; } char* vbuf_; size_t max_; int32_t vsiz_; int64_t xt_; }; VisitorImpl visitor(vbuf, max); if (!accept(kbuf, ksiz, &visitor, false)) return -1; int32_t vsiz = visitor.vsiz(xtp); if (vsiz < 0) { set_error(kc::BasicDB::Error::NOREC, "no record"); return -1; } return vsiz; } /** * Check the existence of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param xtp the pointer to the variable into which the absolute expiration time is assigned. * If it is NULL, it is ignored. * @return the size of the value, or -1 on failure. */ int32_t check(const char* kbuf, size_t ksiz, int64_t* xtp = NULL) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); class VisitorImpl : public Visitor { public: explicit VisitorImpl() : vsiz_(-1), xt_(0) {} int32_t vsiz(int64_t* xtp) { if (xtp) *xtp = xt_; return vsiz_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { vsiz_ = vsiz; xt_ = *xtp; return NOP; } char* vbuf_; int32_t vsiz_; int64_t xt_; }; VisitorImpl visitor; if (!accept(kbuf, ksiz, &visitor, false)) { if (xtp) *xtp = 0; return -1; } int32_t vsiz = visitor.vsiz(xtp); if (vsiz < 0) { set_error(kc::BasicDB::Error::NOREC, "no record"); if (xtp) *xtp = 0; return -1; } return vsiz; } /** * Check the existence of a record. * @note Equal to the original DB::check method except that the first parameters is the key * string. */ int32_t check(const std::string& key, int64_t* xtp = NULL) { return check(key.data(), key.size(), xtp); } /** * Retrieve the value of a record and remove it atomically. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param xtp the pointer to the variable into which the absolute expiration time is assigned. * If it is NULL, it is ignored. * @return the pointer to the value region of the corresponding record, or NULL on failure. * @note If no record corresponds to the key, NULL is returned. Because an additional zero * code is appended at the end of the region of the return value, the return value can be * treated as a C-style string. Because the region of the return value is allocated with the * the new[] operator, it should be released with the delete[] operator when it is no longer * in use. */ char* seize(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp = NULL) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && sp); class VisitorImpl : public Visitor { public: explicit VisitorImpl() : vbuf_(NULL), vsiz_(0), xt_(0) {} char* pop(size_t* sp, int64_t* xtp) { *sp = vsiz_; if (xtp) *xtp = xt_; return vbuf_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { vbuf_ = new char[vsiz+1]; std::memcpy(vbuf_, vbuf, vsiz); vbuf_[vsiz] = '\0'; vsiz_ = vsiz; xt_ = *xtp; return REMOVE; } char* vbuf_; size_t vsiz_; int64_t xt_; }; VisitorImpl visitor; if (!accept(kbuf, ksiz, &visitor, true)) { *sp = 0; if (xtp) *xtp = 0; return NULL; } size_t vsiz; char* vbuf = visitor.pop(&vsiz, xtp); if (!vbuf) { set_error(kc::BasicDB::Error::NOREC, "no record"); *sp = 0; if (xtp) *xtp = 0; return NULL; } *sp = vsiz; return vbuf; } /** * Retrieve the value of a record and remove it atomically. * @note Equal to the original DB::get method except that the first parameters is the key * string and the second parameter is a string to contain the result and the return value is * bool for success. */ bool seize(const std::string& key, std::string* value, int64_t* xtp = NULL) { _assert_(value); class VisitorImpl : public Visitor { public: explicit VisitorImpl(std::string* value) : value_(value), ok_(false), xt_(0) {} bool ok(int64_t* xtp) { if (xtp) *xtp = xt_; return ok_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { value_->clear(); value_->append(vbuf, vsiz); ok_ = true; xt_ = *xtp; return REMOVE; } std::string* value_; bool ok_; int64_t xt_; }; VisitorImpl visitor(value); if (!accept(key.data(), key.size(), &visitor, true)) { if (xtp) *xtp = 0; return false; } if (!visitor.ok(xtp)) { set_error(kc::BasicDB::Error::NOREC, "no record"); return false; } return true; } /** * Store records at once. * @param recs the records to store. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @param atomic true to perform all operations atomically, or false for non-atomic operations. * @return the number of stored records, or -1 on failure. */ int64_t set_bulk(const std::map& recs, int64_t xt = kc::INT64MAX, bool atomic = true) { _assert_(true); if (atomic) { std::vector keys; keys.reserve(recs.size()); std::map::const_iterator rit = recs.begin(); std::map::const_iterator ritend = recs.end(); while (rit != ritend) { keys.push_back(rit->first); ++rit; } class VisitorImpl : public Visitor { public: explicit VisitorImpl(const std::map& recs, int64_t xt) : recs_(recs), xt_(xt) {} private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { std::map::const_iterator rit = recs_.find(std::string(kbuf, ksiz)); if (rit == recs_.end()) return NOP; *sp = rit->second.size(); *xtp = xt_; return rit->second.data(); } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { std::map::const_iterator rit = recs_.find(std::string(kbuf, ksiz)); if (rit == recs_.end()) return NOP; *sp = rit->second.size(); *xtp = xt_; return rit->second.data(); } const std::map& recs_; int64_t xt_; }; VisitorImpl visitor(recs, xt); if (!accept_bulk(keys, &visitor, true)) return -1; return keys.size(); } std::map::const_iterator rit = recs.begin(); std::map::const_iterator ritend = recs.end(); while (rit != ritend) { if (!set(rit->first.data(), rit->first.size(), rit->second.data(), rit->second.size(), xt)) return -1; ++rit; } return recs.size(); } /** * Remove records at once. * @param keys the keys of the records to remove. * @param atomic true to perform all operations atomically, or false for non-atomic operations. * @return the number of removed records, or -1 on failure. */ int64_t remove_bulk(const std::vector& keys, bool atomic = true) { _assert_(true); if (atomic) { class VisitorImpl : public Visitor { public: explicit VisitorImpl() : cnt_(0) {} int64_t cnt() const { return cnt_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { cnt_++; return REMOVE; } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { return REMOVE; } int64_t cnt_; }; VisitorImpl visitor; if (!accept_bulk(keys, &visitor, true)) return -1; return visitor.cnt(); } int64_t cnt = 0; std::vector::const_iterator kit = keys.begin(); std::vector::const_iterator kitend = keys.end(); while (kit != kitend) { if (remove(kit->data(), kit->size())) { cnt++; } else if (error() != kc::BasicDB::Error::NOREC) { return -1; } ++kit; } return cnt; } /** * Retrieve records at once. * @param keys the keys of the records to retrieve. * @param recs a string map to contain the retrieved records. * @param atomic true to perform all operations atomically, or false for non-atomic operations. * @return the number of retrieved records, or -1 on failure. */ int64_t get_bulk(const std::vector& keys, std::map* recs, bool atomic = true) { _assert_(recs); if (atomic) { class VisitorImpl : public Visitor { public: explicit VisitorImpl(std::map* recs) : recs_(recs) {} private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { (*recs_)[std::string(kbuf, ksiz)] = std::string(vbuf, vsiz); return NOP; } std::map* recs_; }; VisitorImpl visitor(recs); if (!accept_bulk(keys, &visitor, false)) return -1; return recs->size(); } std::vector::const_iterator kit = keys.begin(); std::vector::const_iterator kitend = keys.end(); while (kit != kitend) { size_t vsiz; const char* vbuf = get(kit->data(), kit->size(), &vsiz); if (vbuf) { (*recs)[*kit] = std::string(vbuf, vsiz); delete[] vbuf; } else if (error() != kc::BasicDB::Error::NOREC) { return -1; } ++kit; } return recs->size(); } /** * Dump records into a data stream. * @param dest the destination stream. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. */ bool dump_snapshot(std::ostream* dest, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(dest); return db_.dump_snapshot(dest, checker); } /** * Dump records into a file. * @param dest the path of the destination file. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. */ bool dump_snapshot(const std::string& dest, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(true); return db_.dump_snapshot(dest, checker); } /** * Load records from a data stream. * @param src the source stream. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. */ bool load_snapshot(std::istream* src, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(src); return db_.load_snapshot(src, checker); } /** * Load records from a file. * @param src the path of the source file. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. */ bool load_snapshot(const std::string& src, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(true); return db_.load_snapshot(src, checker); } /** * Dump records atomically into a file. * @param dest the path of the destination file. * @param zcomp the data compressor object. If it is NULL, no compression is performed. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. */ bool dump_snapshot_atomic(const std::string& dest, kc::Compressor* zcomp = NULL, kc::BasicDB::ProgressChecker* checker = NULL); /** * Load records atomically from a file. * @param src the path of the source file. * @param zcomp the data compressor object. If it is NULL, no decompression is performed. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. */ bool load_snapshot_atomic(const std::string& src, kc::Compressor* zcomp = NULL, kc::BasicDB::ProgressChecker* checker = NULL); /** * Reveal the inner database object. * @return the inner database object, or NULL on failure. */ kc::BasicDB* reveal_inner_db() { _assert_(true); return db_.reveal_inner_db(); } /** * Scan the database and eliminate regions of expired records. * @param step the number of steps. If it is not more than 0, the whole region is scanned. * @return true on success, or false on failure. */ bool vacuum(int64_t step = 0) { _assert_(true); bool err = false; if (xcur_) { if (step > 1) { if (step > kc::INT64MAX / XTSCUNIT) step = kc::INT64MAX / XTSCUNIT; if (!expire_records(step * XTSCUNIT)) err = true; } else { xcur_->jump(); xsc_ = 0; if (!expire_records(kc::INT64MAX)) err = true; xsc_ = 0; } } if (!defrag(step)) err = true; return !err; } /** * Recover the database with an update log message. * @param mbuf the pointer to the message region. * @param msiz the size of the message region. * @return true on success, or false on failure. */ bool recover(const char* mbuf, size_t msiz) { _assert_(mbuf && msiz <= kc::MEMMAXSIZ); bool err = false; if (msiz < 1) { set_error(kc::BasicDB::Error::INVALID, "invalid message format"); return false; } const char* rp = mbuf; uint8_t op = *(uint8_t*)(rp++); msiz--; switch (op) { case USET: { if (msiz < 2) { set_error(kc::BasicDB::Error::INVALID, "invalid message format"); return false; } uint64_t ksiz; size_t step = kc::readvarnum(rp, msiz, &ksiz); rp += step; msiz -= step; uint64_t vsiz; step = kc::readvarnum(rp, msiz, &vsiz); rp += step; msiz -= step; const char* kbuf = rp; const char* vbuf = rp + ksiz; if (msiz != ksiz + vsiz) { set_error(kc::BasicDB::Error::INVALID, "invalid message format"); return false; } if (!db_.set(kbuf, ksiz, vbuf, vsiz)) err = true; if (utrigger_) log_update(utrigger_, kbuf, ksiz, vbuf, vsiz); break; } case UREMOVE: { if (msiz < 1) { set_error(kc::BasicDB::Error::INVALID, "invalid message format"); return false; } uint64_t ksiz; size_t step = kc::readvarnum(rp, msiz, &ksiz); rp += step; msiz -= step; const char* kbuf = rp; if (msiz != ksiz) { set_error(kc::BasicDB::Error::INVALID, "invalid message format"); return false; } if (!db_.remove(kbuf, ksiz) && db_.error() != kc::BasicDB::Error::NOREC) err = true; if (utrigger_) log_update(utrigger_, kbuf, ksiz, TimedVisitor::REMOVE, 0); break; } case UCLEAR: { if (msiz != 0) { set_error(kc::BasicDB::Error::INVALID, "invalid message format"); return false; } if (!db_.clear()) err = true; break; } default: { break; } } if (xcur_ && !expire_records(XTSCUNIT)) err = true; return !err; } /** * Get keys matching a prefix string. * @param prefix the prefix string. * @param strvec a string vector to contain the result. * @param max the maximum number to retrieve. If it is negative, no limit is specified. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return the number of retrieved keys or -1 on failure. */ int64_t match_prefix(const std::string& prefix, std::vector* strvec, int64_t max = -1, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(strvec); return db_.match_prefix(prefix, strvec, max, checker); } /** * Get keys matching a regular expression string. * @param regex the regular expression string. * @param strvec a string vector to contain the result. * @param max the maximum number to retrieve. If it is negative, no limit is specified. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return the number of retrieved keys or -1 on failure. */ int64_t match_regex(const std::string& regex, std::vector* strvec, int64_t max = -1, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(strvec); return db_.match_regex(regex, strvec, max, checker); } /** * Get keys similar to a string in terms of the levenshtein distance. * @param origin the origin string. * @param range the maximum distance of keys to adopt. * @param utf flag to treat keys as UTF-8 strings. * @param strvec a string vector to contain the result. * @param max the maximum number to retrieve. If it is negative, no limit is specified. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return the number of retrieved keys or -1 on failure. */ int64_t match_similar(const std::string& origin, size_t range, bool utf, std::vector* strvec, int64_t max = -1, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(strvec); return db_.match_similar(origin, range, utf, strvec, max, checker); } /** * Merge records from other databases. * @param srcary an array of the source detabase objects. * @param srcnum the number of the elements of the source array. * @param mode the merge mode. TimedDB::MSET to overwrite the existing value, TimedDB::MADD to * keep the existing value, TimedDB::MREPLACE to modify the existing record only, * TimedDB::MAPPEND to append the new value. * @param checker a progress checker object. If it is NULL, no checking is performed. * @return true on success, or false on failure. */ bool merge(TimedDB** srcary, size_t srcnum, MergeMode mode = MSET, kc::BasicDB::ProgressChecker* checker = NULL) { _assert_(srcary && srcnum <= kc::MEMMAXSIZ); bool err = false; kc::Comparator* comp = kc::LEXICALCOMP; std::priority_queue lines; int64_t allcnt = 0; for (size_t i = 0; i < srcnum; i++) { MergeLine line; line.cur = srcary[i]->cursor(); line.comp = comp; line.cur->jump(); line.kbuf = line.cur->get(&line.ksiz, &line.vbuf, &line.vsiz, &line.xt, true); if (line.kbuf) { lines.push(line); int64_t count = srcary[i]->count(); if (count > 0) allcnt += count; } else { delete line.cur; } } if (checker && !checker->check("merge", "beginning", 0, allcnt)) { set_error(kc::BasicDB::Error::LOGIC, "checker failed"); err = true; } int64_t curcnt = 0; while (!err && !lines.empty()) { MergeLine line = lines.top(); lines.pop(); switch (mode) { case MSET: { if (!set(line.kbuf, line.ksiz, line.vbuf, line.vsiz, -line.xt)) err = true; break; } case MADD: { if (!add(line.kbuf, line.ksiz, line.vbuf, line.vsiz, -line.xt) && error() != kc::BasicDB::Error::DUPREC) err = true; break; } case MREPLACE: { if (!replace(line.kbuf, line.ksiz, line.vbuf, line.vsiz, -line.xt) && error() != kc::BasicDB::Error::NOREC) err = true; break; } case MAPPEND: { if (!append(line.kbuf, line.ksiz, line.vbuf, line.vsiz, -line.xt)) err = true; break; } } delete[] line.kbuf; line.kbuf = line.cur->get(&line.ksiz, &line.vbuf, &line.vsiz, &line.xt, true); if (line.kbuf) { lines.push(line); } else { delete line.cur; } curcnt++; if (checker && !checker->check("merge", "processing", curcnt, allcnt)) { set_error(kc::BasicDB::Error::LOGIC, "checker failed"); err = true; break; } } if (checker && !checker->check("merge", "ending", -1, allcnt)) { set_error(kc::BasicDB::Error::LOGIC, "checker failed"); err = true; } while (!lines.empty()) { MergeLine line = lines.top(); lines.pop(); delete[] line.kbuf; delete line.cur; } return !err; } /** * Create a cursor object. * @return the return value is the created cursor object. * @note Because the object of the return value is allocated by the constructor, it should be * released with the delete operator when it is no longer in use. */ Cursor* cursor() { _assert_(true); return new Cursor(this); } /** * Set the internal logger. * @param logger the logger object. The same as with kc::BasicDB. * @param kinds kinds of logged messages by bitwise-or: The same as with kc::BasicDB. * @return true on success, or false on failure. */ bool tune_logger(kc::BasicDB::Logger* logger, uint32_t kinds = kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR) { _assert_(logger); return db_.tune_logger(logger, kinds); } /** * Set the internal update trigger. * @param trigger the trigger object. * @return true on success, or false on failure. */ bool tune_update_trigger(UpdateTrigger* trigger) { _assert_(trigger); utrigger_ = trigger; return true; } /** * Tokenize an update log message. * @param mbuf the pointer to the message region. * @param msiz the size of the message region. * @param tokens a string vector to contain the result. * @return true on success, or false on failure. */ static bool tokenize_update_log(const char* mbuf, size_t msiz, std::vector* tokens) { _assert_(mbuf && msiz <= kc::MEMMAXSIZ && tokens); tokens->clear(); if (msiz < 1) return false; const char* rp = mbuf; uint8_t op = *(uint8_t*)(rp++); msiz--; switch (op) { case USET: { if (msiz < 2) return false; uint64_t ksiz; size_t step = kc::readvarnum(rp, msiz, &ksiz); rp += step; msiz -= step; uint64_t vsiz; step = kc::readvarnum(rp, msiz, &vsiz); rp += step; msiz -= step; const char* kbuf = rp; const char* vbuf = rp + ksiz; if (msiz != ksiz + vsiz) return false; tokens->push_back("set"); tokens->push_back(std::string(kbuf, ksiz)); tokens->push_back(std::string(vbuf, vsiz)); break; } case UREMOVE: { if (msiz < 1) return false; uint64_t ksiz; size_t step = kc::readvarnum(rp, msiz, &ksiz); rp += step; msiz -= step; const char* kbuf = rp; if (msiz != ksiz) return false; tokens->push_back("remove"); tokens->push_back(std::string(kbuf, ksiz)); break; } case UCLEAR: { if (msiz != 0) return false; tokens->push_back("clear"); break; } default: { tokens->push_back("unknown"); tokens->push_back(std::string(mbuf, msiz)); break; } } return true; } /** * Get status of an atomic snapshot file. * @param src the path of the source file. * @param tsp the pointer to the variable into which the time stamp of the snapshot data is * assigned. If it is NULL, it is ignored. * @param cntp the pointer to the variable into which the number of records in the original * database is assigned. If it is NULL, it is ignored. * @param sizp the pointer to the variable into which the size of the original database is * assigned. If it is NULL, it is ignored. * @return true on success, or false on failure. */ static bool status_snapshot_atomic(const std::string& src, uint64_t* tsp = NULL, int64_t* cntp = NULL, int64_t* sizp = NULL); private: /** * Tuning Options. */ enum Option { TPERSIST = 1 << 1 ///< disable expiration }; /** * Update Operations. */ enum UpdateOperation { UNOP = 0xa0, ///< no operation USET, ///< setting the value UREMOVE, ///< removing the record UOPEN, ///< opening UCLOSE, ///< closing UCLEAR, ///< clearing UITERATE, ///< iteration USYNCHRONIZE, ///< synchronization UBEGINTRAN, ///< beginning transaction UCOMMITTRAN, ///< committing transaction UABORTTRAN, ///< aborting transaction UUNKNOWN ///< unknown operation }; /** * Visitor to handle records with time stamps. */ class TimedVisitor : public kc::BasicDB::Visitor { public: TimedVisitor(TimedDB* db, TimedDB::Visitor* visitor, int64_t ct, bool isiter) : db_(db), visitor_(visitor), ct_(ct), isiter_(isiter), jbuf_(NULL), again_(false) { _assert_(db && visitor && ct >= 0); } ~TimedVisitor() { _assert_(true); delete[] jbuf_; } bool again() { _assert_(true); return again_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp) { _assert_(kbuf && vbuf && sp); if (db_->opts_ & TimedDB::TPERSIST) { size_t rsiz; int64_t xt = kc::INT64MAX; const char* rbuf = visitor_->visit_full(kbuf, ksiz, vbuf, vsiz, &rsiz, &xt); *sp = rsiz; if (db_->utrigger_) log_update(db_->utrigger_, kbuf, ksiz, rbuf, rsiz); return rbuf; } if (vsiz < (size_t)XTWIDTH) return NOP; int64_t xt = kc::readfixnum(vbuf, XTWIDTH); if (ct_ > xt) { if (isiter_) { again_ = true; return NOP; } db_->set_error(kc::BasicDB::Error::NOREC, "no record (expired)"); size_t rsiz; const char* rbuf = visitor_->visit_empty(kbuf, ksiz, &rsiz, &xt); if (rbuf == TimedDB::Visitor::NOP) return NOP; if (rbuf == TimedDB::Visitor::REMOVE) { if (db_->utrigger_) log_update(db_->utrigger_, kbuf, ksiz, REMOVE, 0); return REMOVE; } delete[] jbuf_; xt = modify_exptime(xt, ct_); size_t jsiz; jbuf_ = make_record_value(rbuf, rsiz, xt, &jsiz); *sp = jsiz; if (db_->utrigger_) log_update(db_->utrigger_, kbuf, ksiz, jbuf_, jsiz); return jbuf_; } vbuf += XTWIDTH; vsiz -= XTWIDTH; size_t rsiz; const char* rbuf = visitor_->visit_full(kbuf, ksiz, vbuf, vsiz, &rsiz, &xt); if (rbuf == TimedDB::Visitor::NOP) return NOP; if (rbuf == TimedDB::Visitor::REMOVE) { if (db_->utrigger_) log_update(db_->utrigger_, kbuf, ksiz, REMOVE, 0); return REMOVE; } delete[] jbuf_; xt = modify_exptime(xt, ct_); size_t jsiz; jbuf_ = make_record_value(rbuf, rsiz, xt, &jsiz); *sp = jsiz; if (db_->utrigger_) log_update(db_->utrigger_, kbuf, ksiz, jbuf_, jsiz); return jbuf_; } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp) { if (db_->opts_ & TimedDB::TPERSIST) { size_t rsiz; int64_t xt = kc::INT64MAX; const char* rbuf = visitor_->visit_empty(kbuf, ksiz, &rsiz, &xt); *sp = rsiz; if (db_->utrigger_) log_update(db_->utrigger_, kbuf, ksiz, rbuf, rsiz); return rbuf; } size_t rsiz; int64_t xt = -1; const char* rbuf = visitor_->visit_empty(kbuf, ksiz, &rsiz, &xt); if (rbuf == TimedDB::Visitor::NOP) return NOP; if (rbuf == TimedDB::Visitor::REMOVE) { if (db_->utrigger_) log_update(db_->utrigger_, kbuf, ksiz, REMOVE, 0); return REMOVE; } delete[] jbuf_; xt = modify_exptime(xt, ct_); size_t jsiz; jbuf_ = make_record_value(rbuf, rsiz, xt, &jsiz); *sp = jsiz; if (db_->utrigger_) log_update(db_->utrigger_, kbuf, ksiz, jbuf_, jsiz); return jbuf_; } void visit_before() { _assert_(true); visitor_->visit_before(); } void visit_after() { _assert_(true); visitor_->visit_after(); } TimedDB* db_; TimedDB::Visitor* visitor_; int64_t ct_; bool isiter_; char* jbuf_; bool again_; }; /** * Trigger of meta database operations. */ class TimedMetaTrigger : public kc::BasicDB::MetaTrigger { public: TimedMetaTrigger(TimedDB* db) : db_(db) { _assert_(db); } private: void trigger(Kind kind, const char* message) { _assert_(message); if (!db_->utrigger_) return; switch (kind) { case CLEAR: { char mbuf[1]; *mbuf = UCLEAR; db_->utrigger_->trigger(mbuf, 1); break; } case BEGINTRAN: { db_->utrigger_->begin_transaction(); break; } case COMMITTRAN: { db_->utrigger_->end_transaction(true); break; } case ABORTTRAN: { db_->utrigger_->end_transaction(false); break; } default: { break; } } } TimedDB* db_; }; /** * Front line of a merging list. */ struct MergeLine { TimedDB::Cursor* cur; ///< cursor kc::Comparator* comp; ///< comparator char* kbuf; ///< pointer to the key size_t ksiz; ///< size of the key const char* vbuf; ///< pointer to the value size_t vsiz; ///< size of the value int64_t xt; ///< expiration time /** comparing operator */ bool operator <(const MergeLine& right) const { return comp->compare(kbuf, ksiz, right.kbuf, right.ksiz) > 0; } }; /** * Remove expired records. * @param score the score of expiration. * @return true on success, or false on failure. */ bool expire_records(int64_t score) { _assert_(score >= 0); xsc_ += score; if (xsc_ < XTSCUNIT * XTUNIT) return true; if (!xlock_.lock_try()) return true; int64_t step = (int64_t)xsc_ / XTSCUNIT; xsc_ -= step * XTSCUNIT; int64_t ct = std::time(NULL); class VisitorImpl : public kc::BasicDB::Visitor { public: VisitorImpl(int64_t ct) : ct_(ct) {} private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp) { if (vsiz < (size_t)XTWIDTH) return NOP; int64_t xt = kc::readfixnum(vbuf, XTWIDTH); if (ct_ <= xt) return NOP; return REMOVE; } int64_t ct_; }; VisitorImpl visitor(ct); bool err = false; for (int64_t i = 0; i < step; i++) { if (!xcur_->accept(&visitor, true, true)) { kc::BasicDB::Error::Code code = db_.error().code(); if (code == kc::BasicDB::Error::INVALID || code == kc::BasicDB::Error::NOREC) { xcur_->jump(); } else { err = true; } xsc_ = 0; break; } } if (capcnt_ > 0) { int64_t count = db_.count(); while (count > capcnt_) { if (!xcur_->remove()) { kc::BasicDB::Error::Code code = db_.error().code(); if (code == kc::BasicDB::Error::INVALID || code == kc::BasicDB::Error::NOREC) { xcur_->jump(); } else { err = true; } break; } count--; } if (!defrag(step)) err = true; } if (capsiz_ > 0) { int64_t size = db_.size(); if (size > capsiz_) { for (int64_t i = 0; i < step; i++) { if (!xcur_->remove()) { kc::BasicDB::Error::Code code = db_.error().code(); if (code == kc::BasicDB::Error::INVALID || code == kc::BasicDB::Error::NOREC) { xcur_->jump(); } else { err = true; } break; } } if (!defrag(step)) err = true; } } xlock_.unlock(); return !err; } /** * Perform defragmentation of the database file. * @param step the number of steps. If it is not more than 0, the whole region is defraged. * @return true on success, or false on failure. */ bool defrag(int step) { _assert_(true); bool err = false; kc::BasicDB* idb = db_.reveal_inner_db(); if (idb) { const std::type_info& info = typeid(*idb); if (info == typeid(kc::HashDB)) { kc::HashDB* hdb = (kc::HashDB*)idb; if (!hdb->defrag(step)) err = true; } else if (info == typeid(kc::TreeDB)) { kc::TreeDB* tdb = (kc::TreeDB*)idb; if (!tdb->defrag(step)) err = true; } } return !err; } /** * Make the record value with meta data. * @param vbuf the buffer of the original record value. * @param vsiz the size of the original record value. * @param xt the expiration time. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @return the pointer to the result buffer. */ static char* make_record_value(const char* vbuf, size_t vsiz, int64_t xt, size_t* sp) { _assert_(vbuf && vsiz <= kc::MEMMAXSIZ); size_t jsiz = vsiz + XTWIDTH; char* jbuf = new char[jsiz]; kc::writefixnum(jbuf, xt, XTWIDTH); std::memcpy(jbuf + XTWIDTH, vbuf, vsiz); *sp = jsiz; return jbuf; } /** * Modify an expiration time by the current time. * @param xt the expiration time. * @param ct the current time. * @return the modified expiration time. */ static int64_t modify_exptime(int64_t xt, int64_t ct) { _assert_(true); if (xt < 0) { if (xt < kc::INT64MIN / 2) xt = kc::INT64MIN / 2; xt = -xt; } else { if (xt > kc::INT64MAX / 2) xt = kc::INT64MAX / 2; xt += ct; } if (xt > XTMAX) xt = XTMAX; return xt; } /** * Log a record update operation. * @param utrigger the update trigger. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. */ static void log_update(UpdateTrigger* utrigger, const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) { _assert_(utrigger && kbuf); if (vbuf == TimedVisitor::REMOVE) { size_t msiz = 1 + sizeof(uint64_t) + ksiz; char stack[LOGBUFSIZ]; char* mbuf = msiz > sizeof(stack) ? new char[msiz] : stack; char* wp = mbuf; *(wp++) = UREMOVE; wp += kc::writevarnum(wp, ksiz); std::memcpy(wp, kbuf, ksiz); wp += ksiz; utrigger->trigger(mbuf, wp - mbuf); if (mbuf != stack) delete[] mbuf; } else if (vbuf != TimedVisitor::NOP) { size_t msiz = 1 + sizeof(uint64_t) * 2 + ksiz + vsiz; char stack[LOGBUFSIZ]; char* mbuf = msiz > sizeof(stack) ? new char[msiz] : stack; char* wp = mbuf; *(wp++) = USET; wp += kc::writevarnum(wp, ksiz); wp += kc::writevarnum(wp, vsiz); std::memcpy(wp, kbuf, ksiz); wp += ksiz; std::memcpy(wp, vbuf, vsiz); wp += vsiz; utrigger->trigger(mbuf, wp - mbuf); if (mbuf != stack) delete[] mbuf; } } /** Dummy constructor to forbid the use. */ TimedDB(const TimedDB&); /** Dummy Operator to forbid the use. */ TimedDB& operator =(const TimedDB&); /** The expiration cursor lock. */ kc::SpinLock xlock_; /** The internal database. */ kc::PolyDB db_; /** The internal meta trigger. */ TimedMetaTrigger mtrigger_; /** The internal update trigger. */ UpdateTrigger* utrigger_; /** The open mode. */ uint32_t omode_; /** The options. */ uint8_t opts_; /** The capacity of record number. */ int64_t capcnt_; /** The capacity of memory usage. */ int64_t capsiz_; /** The cursor for expiration. */ kc::PolyDB::Cursor* xcur_; /** The score of expiration. */ kc::AtomicInt64 xsc_; }; } // common namespace #endif // duplication check // END OF FILE kyototycoon-0.9.56/COPYING0000644000175000017500000010451311441176761014265 0ustar mikiomikio GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . kyototycoon-0.9.56/ktthserv.h0000644000175000017500000004007611757471602015262 0ustar mikiomikio/************************************************************************************************* * Threaded Server * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTTHSERV_H // duplication check #define _KTTHSERV_H #include #include #include namespace kyototycoon { // common namespace /** * Threaded TCP Server. */ class ThreadedServer { public: class Logger; class Worker; class Session; private: class TaskQueueImpl; class SessionTask; public: /** * Interface to log internal information and errors. */ class Logger { public: /** * Event kinds. */ enum Kind { DEBUG = 1 << 0, ///< normal information INFO = 1 << 1, ///< normal information SYSTEM = 1 << 2, ///< system information ERROR = 1 << 3 ///< error }; /** * Destructor. */ virtual ~Logger() { _assert_(true); } /** * Process a log message. * @param kind the kind of the event. Logger::DEBUG for debugging, Logger::INFO for normal * information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error. * @param message the log message. */ virtual void log(Kind kind, const char* message) = 0; }; /** * Interface to process each request. */ class Worker { public: /** * Destructor. */ virtual ~Worker() { _assert_(true); } /** * Process each request. * @param serv the server. * @param sess the session with the client. * @return true to reuse the session, or false to close the session. */ virtual bool process(ThreadedServer* serv, Session* sess) = 0; /** * Process each idle event. * @param serv the server. */ virtual void process_idle(ThreadedServer* serv) { _assert_(serv); } /** * Process each timer event. * @param serv the server. */ virtual void process_timer(ThreadedServer* serv) { _assert_(serv); } /** * Process the starting event. * @param serv the server. */ virtual void process_start(ThreadedServer* serv) { _assert_(serv); } /** * Process the finishing event. * @param serv the server. */ virtual void process_finish(ThreadedServer* serv) { _assert_(serv); } }; /** * Interface to access each session data. */ class Session : public Socket { friend class ThreadedServer; public: class Data; public: /** * Interface of session local data. */ class Data { public: /** * Destructor. */ virtual ~Data() { _assert_(true); } }; /** * Get the ID number of the session. * @return the ID number of the session. */ uint64_t id() { _assert_(true); return id_; } /** * Get the ID number of the worker thread. * @return the ID number of the worker thread. It is from 0 to less than the number of * worker threads. */ uint32_t thread_id() { _assert_(true); return thid_; } /** * Set the session local data. * @param data the session local data. If it is NULL, no data is registered. * @note The registered data is destroyed implicitly when the session object is destroyed or * this method is called again. */ void set_data(Data* data) { _assert_(true); delete data_; data_ = data; } /** * Get the session local data. * @return the session local data, or NULL if no data is registered. */ Data* data() { _assert_(true); return data_; } private: /** * Default Constructor. */ explicit Session(uint64_t id) : id_(id), thid_(0), data_(NULL) { _assert_(true); } /** * Destructor. */ ~Session() { _assert_(true); delete data_; } private: /** The ID number of the session. */ uint64_t id_; /** The ID number of the worker thread. */ uint32_t thid_; /** The session local data. */ Data* data_; }; /** * Default constructor. */ explicit ThreadedServer() : run_(false), expr_(), timeout_(0), logger_(NULL), logkinds_(0), worker_(NULL), thnum_(0), sock_(), poll_(), queue_(this), sesscnt_(0), idlesem_(0), timersem_(0) { _assert_(true); } /** * Destructor. */ ~ThreadedServer() { _assert_(true); } /** * Set the network configurations. * @param expr an expression of the address and the port of the server. * @param timeout the timeout of each network operation in seconds. If it is not more than 0, * no timeout is specified. */ void set_network(const std::string& expr, double timeout = -1) { expr_ = expr; timeout_ = timeout; } /** * Set the logger to process each log message. * @param logger the logger object. * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, * Logger::INFO for normal information, Logger::SYSTEM for system information, and * Logger::ERROR for fatal error. */ void set_logger(Logger* logger, uint32_t kinds = Logger::SYSTEM | Logger::ERROR) { _assert_(logger); logger_ = logger; logkinds_ = kinds; } /** * Set the worker to process each request. * @param worker the worker object. * @param thnum the number of worker threads. */ void set_worker(Worker* worker, size_t thnum = 1) { _assert_(worker && thnum > 0 && thnum < kc::MEMMAXSIZ); worker_ = worker; thnum_ = thnum; } /** * Start the service. * @return true on success, or false on failure. * @note This function blocks until the server stops by the ThreadedServer::stop method. */ bool start() { log(Logger::SYSTEM, "starting the server: expr=%s", expr_.c_str()); if (run_) { log(Logger::ERROR, "alreadiy running"); return false; } if (expr_.empty()) { log(Logger::ERROR, "the network configuration is not set"); return false; } if (!worker_) { log(Logger::ERROR, "the worker is not set"); return false; } if (!sock_.open(expr_)) { log(Logger::ERROR, "socket error: expr=%s msg=%s", expr_.c_str(), sock_.error()); return false; } log(Logger::SYSTEM, "server socket opened: expr=%s timeout=%.1f", expr_.c_str(), timeout_); if (!poll_.open()) { log(Logger::ERROR, "poller error: msg=%s", poll_.error()); sock_.close(); return false; } log(Logger::SYSTEM, "listening server socket started: fd=%d", sock_.descriptor()); bool err = false; sock_.set_event_flags(Pollable::EVINPUT); if (!poll_.deposit(&sock_)) { log(Logger::ERROR, "poller error: msg=%s", poll_.error()); err = true; } queue_.set_worker(worker_); queue_.start(thnum_); uint32_t timercnt = 0; run_ = true; while (run_) { if (poll_.wait(0.1)) { Pollable* event; while ((event = poll_.next()) != NULL) { if (event == &sock_) { Session* sess = new Session(++sesscnt_); if (timeout_ > 0) sess->set_timeout(timeout_); if (sock_.accept(sess)) { log(Logger::INFO, "connected: expr=%s", sess->expression().c_str()); sess->set_event_flags(Pollable::EVINPUT); if (!poll_.deposit(sess)) { log(Logger::ERROR, "poller error: msg=%s", poll_.error()); err = true; } } else { log(Logger::ERROR, "socket error: msg=%s", sock_.error()); err = true; } sock_.set_event_flags(Pollable::EVINPUT); if (!poll_.undo(&sock_)) { log(Logger::ERROR, "poller error: msg=%s", poll_.error()); err = true; } } else { Session* sess = (Session*)event; SessionTask* task = new SessionTask(sess); queue_.add_task(task); } } timercnt++; } else { if (queue_.count() < 1 && idlesem_.cas(0, 1)) { SessionTask* task = new SessionTask(SESSIDLE); queue_.add_task(task); } timercnt += kc::UINT8MAX / 4; } if (timercnt > kc::UINT8MAX && timersem_.cas(0, 1)) { SessionTask* task = new SessionTask(SESSTIMER); queue_.add_task(task); timercnt = 0; } } log(Logger::SYSTEM, "server stopped"); if (err) log(Logger::SYSTEM, "one or more errors were detected"); return !err; } /** * Stop the service. * @return true on success, or false on failure. */ bool stop() { if (!run_) { log(Logger::ERROR, "not running"); return false; } run_ = false; sock_.abort(); poll_.abort(); return true; } /** * Finish the service. * @return true on success, or false on failure. */ bool finish() { log(Logger::SYSTEM, "finishing the server"); if (run_) { log(Logger::ERROR, "not stopped"); return false; } bool err = false; queue_.finish(); if (queue_.error()) { log(Logger::SYSTEM, "one or more errors were detected"); err = true; } if (poll_.flush()) { Pollable* event; while ((event = poll_.next()) != NULL) { if (event == &sock_) continue; Session* sess = (Session*)event; log(Logger::INFO, "disconnecting: expr=%s", sess->expression().c_str()); if (!poll_.withdraw(sess)) { log(Logger::ERROR, "poller error: msg=%s", poll_.error()); err = true; } if (!sess->close()) { log(Logger::ERROR, "socket error: fd=%d msg=%s", sess->descriptor(), sess->error()); err = true; } delete sess; } } else { log(Logger::ERROR, "poller error: msg=%s", poll_.error()); err = true; } if (!poll_.close()) { log(Logger::ERROR, "poller error: msg=%s", poll_.error()); err = true; } log(Logger::SYSTEM, "closing the server socket"); if (!sock_.close()) { log(Logger::ERROR, "socket error: fd=%d msg=%s", sock_.descriptor(), sock_.error()); err = true; } return !err; } /** * Log a message. * @param kind the kind of the event. Logger::DEBUG for debugging, Logger::INFO for normal * information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error. * @param format the printf-like format string. The conversion character `%' can be used with * such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `%'. * @param ... used according to the format string. */ void log(Logger::Kind kind, const char* format, ...) { _assert_(format); if (!logger_ || !(kind & logkinds_)) return; std::string msg; va_list ap; va_start(ap, format); kc::vstrprintf(&msg, format, ap); va_end(ap); logger_->log(kind, msg.c_str()); } /** * Log a message. * @note Equal to the original Cursor::set_value method except that the last parameters is * va_list. */ void log_v(Logger::Kind kind, const char* format, va_list ap) { _assert_(format); if (!logger_ || !(kind & logkinds_)) return; std::string msg; kc::vstrprintf(&msg, format, ap); logger_->log(kind, msg.c_str()); } /** * Get the number of connections. * @return the number of connections. */ int64_t connection_count() { _assert_(true); return poll_.count() - 1; } /** * Get the number of tasks in the queue. * @return the number of tasks in the queue. */ int64_t task_count() { _assert_(true); return queue_.count(); } /** * Check whether the thread is to be aborted. * @return true if the thread is to be aborted, or false if not. */ bool aborted() { _assert_(true); return !run_; } private: /** The magic pointer of an idle session. */ static Session* const SESSIDLE; /** The magic pointer of a timer session. */ static Session* const SESSTIMER; /** * Task queue implementation. */ class TaskQueueImpl : public kc::TaskQueue { public: explicit TaskQueueImpl(ThreadedServer* serv) : serv_(serv), worker_(NULL), err_(false) { _assert_(true); } void set_worker(Worker* worker) { _assert_(worker); worker_ = worker; } bool error() { _assert_(true); return err_; } private: void do_task(kc::TaskQueue::Task* task) { _assert_(task); SessionTask* mytask = (SessionTask*)task; Session* sess = mytask->sess_; if (sess == SESSIDLE) { worker_->process_idle(serv_); serv_->idlesem_.set(0); } else if (sess == SESSTIMER) { worker_->process_timer(serv_); serv_->timersem_.set(0); } else { bool keep = false; if (mytask->aborted()) { serv_->log(Logger::INFO, "aborted a request: expr=%s", sess->expression().c_str()); } else { sess->thid_ = mytask->thread_id(); do { keep = worker_->process(serv_, sess); } while (keep && sess->left_size() > 0); } if (keep) { sess->set_event_flags(Pollable::EVINPUT); if (!serv_->poll_.undo(sess)) { serv_->log(Logger::ERROR, "poller error: msg=%s", serv_->poll_.error()); err_ = true; } } else { serv_->log(Logger::INFO, "disconnecting: expr=%s", sess->expression().c_str()); if (!serv_->poll_.withdraw(sess)) { serv_->log(Logger::ERROR, "poller error: msg=%s", serv_->poll_.error()); err_ = true; } if (!sess->close()) { serv_->log(Logger::ERROR, "socket error: msg=%s", sess->error()); err_ = true; } delete sess; } } delete mytask; } void do_start(const kc::TaskQueue::Task* task) { _assert_(task); worker_->process_start(serv_); } void do_finish(const kc::TaskQueue::Task* task) { _assert_(task); worker_->process_finish(serv_); } ThreadedServer* serv_; Worker* worker_; bool err_; }; /** * Task with a session. */ class SessionTask : public kc::TaskQueue::Task { friend class ThreadedServer; public: explicit SessionTask(Session* sess) : sess_(sess) {} private: Session* sess_; }; /** Dummy constructor to forbid the use. */ ThreadedServer(const ThreadedServer&); /** Dummy Operator to forbid the use. */ ThreadedServer& operator =(const ThreadedServer&); /** The flag of running. */ bool run_; /** The expression of the server socket. */ std::string expr_; /** The timeout of each network operation. */ double timeout_; /** The internal logger. */ Logger* logger_; /** The kinds of logged messages. */ uint32_t logkinds_; /** The worker operator. */ Worker* worker_; /** The number of worker threads. */ size_t thnum_; /** The server socket. */ ServerSocket sock_; /** The event poller. */ Poller poll_; /** The task queue. */ TaskQueueImpl queue_; /** The session count. */ uint64_t sesscnt_; /** The idle event semaphore. */ kc::AtomicInt64 idlesem_; /** The timer event semaphore. */ kc::AtomicInt64 timersem_; }; } // common namespace #endif // duplication check // END OF FILE kyototycoon-0.9.56/ktrpc.h0000644000175000017500000004765211757471602014542 0ustar mikiomikio/************************************************************************************************* * RPC utilities * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTRPC_H // duplication check #define _KTRPC_H #include #include #include #include #include #define KTRPCPATHPREFIX "/rpc/" ///< prefix of the RPC entry #define KTRPCFORMMTYPE "application/x-www-form-urlencoded" ///< MIME type of form data #define KTRPCTSVMTYPE "text/tab-separated-values" ///< MIME type of TSV #define KTRPCTSVMATTR "colenc" ///< encoding attribute of TSV namespace kyototycoon { // common namespace /** * RPC client. * @note Although all methods of this class are thread-safe, its instance does not have mutual * exclusion mechanism. So, multiple threads must not share the same instance and they must use * their own respective instances. */ class RPCClient { public: /** * Return value. */ enum ReturnValue { RVSUCCESS, ///< success RVENOIMPL, ///< not implemented RVEINVALID, ///< invalid operation RVELOGIC, ///< logical inconsistency RVETIMEOUT, ///< timeout RVEINTERNAL, ///< internal error RVENETWORK, ///< network error RVEMISC = 15 ///< miscellaneous error }; /** * Default constructor. */ RPCClient() : ua_(), host_(), port_(0), timeout_(0), open_(false), alive_(false) { _assert_(true); } /** * Destructor. */ ~RPCClient() { _assert_(true); if (open_) close(); } /** * Open the connection. * @param host the name or the address of the server. If it is an empty string, the local host * is specified. * @param port the port numger of the server. * @param timeout the timeout of each operation in seconds. If it is not more than 0, no * timeout is specified. * @return true on success, or false on failure. */ bool open(const std::string& host = "", int32_t port = DEFPORT, double timeout = -1) { _assert_(true); if (open_ || port < 1) return false; if (!ua_.open(host, port, timeout)) return false; host_ = host; port_ = port; timeout_ = timeout; open_ = true; alive_ = true; return true; } /** * Close the connection. * @param grace true for graceful shutdown, or false for immediate disconnection. * @return true on success, or false on failure. */ bool close(bool grace = true) { _assert_(true); if (!open_) return false; bool err = false; if (alive_ && !ua_.close(grace)) err = true; return !err; } /** * Call a remote procedure. * @param name the name of the procecude. * @param inmap a string map which contains the input of the procedure. If it is NULL, it is * ignored. * @param outmap a string map to contain the output parameters. If it is NULL, it is ignored. * @return the return value of the procedure. */ ReturnValue call(const std::string& name, const std::map* inmap = NULL, std::map* outmap = NULL) { _assert_(true); if (outmap) outmap->clear(); if (!open_) return RVENETWORK; if (!alive_ && !ua_.open(host_, port_, timeout_)) return RVENETWORK; alive_ = true; std::string pathquery = KTRPCPATHPREFIX; char* zstr = kc::urlencode(name.data(), name.size()); pathquery.append(zstr); delete[] zstr; std::map reqheads; std::string reqbody; if (inmap) { std::map tmap; tmap.insert(inmap->begin(), inmap->end()); int32_t enc = checkmapenc(tmap); std::string outtype = KTRPCTSVMTYPE; switch (enc) { case 'B': kc::strprintf(&outtype, "; %s=B", KTRPCTSVMATTR); break; case 'Q': kc::strprintf(&outtype, "; %s=Q", KTRPCTSVMATTR); break; case 'U': kc::strprintf(&outtype, "; %s=U", KTRPCTSVMATTR); break; } reqheads["content-type"] = outtype; if (enc != 0) tsvmapencode(&tmap, enc); maptotsv(tmap, &reqbody); } std::map resheads; std::string resbody; int32_t code = ua_.fetch(pathquery, HTTPClient::MPOST, &resbody, &resheads, &reqbody, &reqheads); if (outmap) { const char* rp = strmapget(resheads, "content-type"); if (rp) { if (kc::strifwm(rp, KTRPCFORMMTYPE)) { wwwformtomap(resbody.c_str(), outmap); } else if (kc::strifwm(rp, KTRPCTSVMTYPE)) { rp += sizeof(KTRPCTSVMTYPE) - 1; int32_t enc = 0; while (*rp != '\0') { while (*rp == ' ' || *rp == ';') { rp++; } if (kc::strifwm(rp, KTRPCTSVMATTR) && rp[sizeof(KTRPCTSVMATTR)-1] == '=') { rp += sizeof(KTRPCTSVMATTR); if (*rp == '"') rp++; switch (*rp) { case 'b': case 'B': enc = 'B'; break; case 'q': case 'Q': enc = 'Q'; break; case 'u': case 'U': enc = 'U'; break; } } while (*rp != '\0' && *rp != ' ' && *rp != ';') { rp++; } } tsvtomap(resbody, outmap); if (enc != 0) tsvmapdecode(outmap, enc); } } } ReturnValue rv; if (code < 1) { rv = RVENETWORK; ua_.close(false); alive_ = false; } else if (code >= 200 && code < 300) { rv = RVSUCCESS; } else if (code >= 400 && code < 500) { if (code >= 450) { rv = RVELOGIC; } else { rv = RVEINVALID; } } else if (code >= 500 && code < 600) { if (code == 501) { rv = RVENOIMPL; } else if (code == 503) { rv = RVETIMEOUT; } else { rv = RVEINTERNAL; } } else { rv = RVEMISC; } return rv; } /** * Get the expression of the socket. * @return the expression of the socket or an empty string on failure. */ const std::string expression() { _assert_(true); if (!open_) return ""; std::string expr; kc::strprintf(&expr, "%s:%d", host_.c_str(), port_); return expr; } /** * Reveal the internal HTTP client. * @return the internal HTTP client. */ HTTPClient* reveal_core() { _assert_(true); return &ua_; } private: /** The HTTP client. */ HTTPClient ua_; /** The host name of the server. */ std::string host_; /** The port numer of the server. */ uint32_t port_; /** The timeout. */ double timeout_; /** The open flag. */ bool open_; /** The alive flag. */ bool alive_; }; /** * RPC server. */ class RPCServer { public: class Logger; class Worker; class Session; private: class WorkerAdapter; public: /** * Interface to log internal information and errors. */ class Logger : public HTTPServer::Logger { public: /** * Destructor. */ virtual ~Logger() { _assert_(true); } }; /** * Interface to process each request. */ class Worker { public: /** * Destructor. */ virtual ~Worker() { _assert_(true); } /** * Process each request of RPC. * @param serv the server. * @param sess the session with the client. * @param name the name of the procecude. * @param inmap a string map which contains the input of the procedure. * @param outmap a string map to contain the input parameters. * @return the return value of the procedure. */ virtual RPCClient::ReturnValue process(RPCServer* serv, Session* sess, const std::string& name, const std::map& inmap, std::map& outmap) = 0; /** * Process each request of the others. * @param serv the server. * @param sess the session with the client. * @param path the path of the requested resource. * @param method the kind of the request methods. * @param reqheads a string map which contains the headers of the request. Header names are * converted into lower cases. The empty key means the request-line. * @param reqbody a string which contains the entity body of the request. * @param resheads a string map to contain the headers of the response. * @param resbody a string to contain the entity body of the response. * @param misc a string map which contains miscellaneous information. "url" means the * absolute URL. "query" means the query string of the URL. * @return the status code of the response. If it is less than 1, internal server error is * sent to the client and the connection is closed. */ virtual int32_t process(HTTPServer* serv, HTTPServer::Session* sess, const std::string& path, HTTPClient::Method method, const std::map& reqheads, const std::string& reqbody, std::map& resheads, std::string& resbody, const std::map& misc) { _assert_(serv && sess); return 501; } /** * Process each binary request. * @param serv the server. * @param sess the session with the client. * @return true to reuse the session, or false to close the session. */ virtual bool process_binary(ThreadedServer* serv, ThreadedServer::Session* sess) { _assert_(serv && sess); return false; } /** * Process each idle event. * @param serv the server. */ virtual void process_idle(RPCServer* serv) { _assert_(serv); } /** * Process each timer event. * @param serv the server. */ virtual void process_timer(RPCServer* serv) { _assert_(serv); } /** * Process the starting event. * @param serv the server. */ virtual void process_start(RPCServer* serv) { _assert_(serv); } /** * Process the finishing event. * @param serv the server. */ virtual void process_finish(RPCServer* serv) { _assert_(serv); } }; /** * Interface to log internal information and errors. */ class Session { friend class RPCServer; public: /** * Interface of session local data. */ class Data : public HTTPServer::Session::Data { public: /** * Destructor. */ virtual ~Data() { _assert_(true); } }; /** * Get the ID number of the session. * @return the ID number of the session. */ uint64_t id() { _assert_(true); return sess_->id(); } /** * Get the ID number of the worker thread. * @return the ID number of the worker thread. It is from 0 to less than the number of * worker threads. */ uint32_t thread_id() { _assert_(true); return sess_->thread_id(); } /** * Set the session local data. * @param data the session local data. If it is NULL, no data is registered. * @note The registered data is destroyed implicitly when the session object is destroyed or * this method is called again. */ void set_data(Data* data) { _assert_(true); sess_->set_data(data); } /** * Get the session local data. * @return the session local data, or NULL if no data is registered. */ Data* data() { _assert_(true); return (Data*)sess_->data(); } /** * Get the expression of the socket. * @return the expression of the socket or an empty string on failure. */ const std::string expression() { _assert_(true); return sess_->expression(); } private: /** * Constructor. */ explicit Session(HTTPServer::Session* sess) : sess_(sess) { _assert_(true); } /** * Destructor. */ virtual ~Session() { _assert_(true); } private: HTTPServer::Session* sess_; }; /** * Default constructor. */ explicit RPCServer() : serv_(), worker_() { _assert_(true); } /** * Destructor. */ ~RPCServer() { _assert_(true); } /** * Set the network configurations. * @param expr an expression of the address and the port of the server. * @param timeout the timeout of each network operation in seconds. If it is not more than 0, * no timeout is specified. */ void set_network(const std::string& expr, double timeout = -1) { _assert_(true); serv_.set_network(expr, timeout); } /** * Set the logger to process each log message. * @param logger the logger object. * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, * Logger::INFO for normal information, Logger::SYSTEM for system information, and * Logger::ERROR for fatal error. */ void set_logger(Logger* logger, uint32_t kinds = Logger::SYSTEM | Logger::ERROR) { _assert_(true); serv_.set_logger(logger, kinds); } /** * Set the worker to process each request. * @param worker the worker object. * @param thnum the number of worker threads. */ void set_worker(Worker* worker, size_t thnum = 1) { _assert_(true); worker_.serv_ = this; worker_.worker_ = worker; serv_.set_worker(&worker_, thnum); } /** * Start the service. * @return true on success, or false on failure. * @note This function blocks until the server stops by the RPCServer::stop method. */ bool start() { _assert_(true); return serv_.start(); } /** * Stop the service. * @return true on success, or false on failure. */ bool stop() { _assert_(true); return serv_.stop(); } /** * Finish the service. * @return true on success, or false on failure. */ bool finish() { _assert_(true); return serv_.finish(); } /** * Log a message. * @param kind the kind of the event. Logger::DEBUG for debugging, Logger::INFO for normal * information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error. * @param format the printf-like format string. The conversion character `%' can be used with * such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `%'. * @param ... used according to the format string. */ void log(Logger::Kind kind, const char* format, ...) { _assert_(format); va_list ap; va_start(ap, format); serv_.log_v(kind, format, ap); va_end(ap); } /** * Log a message. * @note Equal to the original Cursor::set_value method except that the last parameters is * va_list. */ void log_v(Logger::Kind kind, const char* format, va_list ap) { _assert_(format); serv_.log_v(kind, format, ap); } /** * Reveal the internal HTTP server. * @return the internal HTTP server. */ HTTPServer* reveal_core() { _assert_(true); return &serv_; } private: /** * Adapter for the worker. */ class WorkerAdapter : public HTTPServer::Worker { friend class RPCServer; public: WorkerAdapter() : serv_(NULL), worker_(NULL) { _assert_(true); } private: int32_t process(HTTPServer* serv, HTTPServer::Session* sess, const std::string& path, HTTPClient::Method method, const std::map& reqheads, const std::string& reqbody, std::map& resheads, std::string& resbody, const std::map& misc) { const char* name = path.c_str(); if (!kc::strfwm(name, KTRPCPATHPREFIX)) return worker_->process(serv, sess, path, method, reqheads, reqbody, resheads, resbody, misc); name += sizeof(KTRPCPATHPREFIX) - 1; size_t zsiz; char* zbuf = kc::urldecode(name, &zsiz); std::string rawname(zbuf, zsiz); delete[] zbuf; std::map inmap; const char* rp = strmapget(misc, "query"); if (rp) wwwformtomap(rp, &inmap); rp = strmapget(reqheads, "content-type"); if (rp) { if (kc::strifwm(rp, KTRPCFORMMTYPE)) { wwwformtomap(reqbody.c_str(), &inmap); } else if (kc::strifwm(rp, KTRPCTSVMTYPE)) { rp += sizeof(KTRPCTSVMTYPE) - 1; int32_t enc = 0; while (*rp != '\0') { while (*rp == ' ' || *rp == ';') { rp++; } if (kc::strifwm(rp, KTRPCTSVMATTR) && rp[sizeof(KTRPCTSVMATTR)-1] == '=') { rp += sizeof(KTRPCTSVMATTR); if (*rp == '"') rp++; switch (*rp) { case 'b': case 'B': enc = 'B'; break; case 'q': case 'Q': enc = 'Q'; break; case 'u': case 'U': enc = 'U'; break; } } while (*rp != '\0' && *rp != ' ' && *rp != ';') { rp++; } } tsvtomap(reqbody, &inmap); if (enc != 0) tsvmapdecode(&inmap, enc); } } std::map outmap; Session mysess(sess); RPCClient::ReturnValue rv = worker_->process(serv_, &mysess, rawname, inmap, outmap); int32_t code = -1; switch (rv) { case RPCClient::RVSUCCESS: code = 200; break; case RPCClient::RVENOIMPL: code = 501; break; case RPCClient::RVEINVALID: code = 400; break; case RPCClient::RVELOGIC: code = 450; break; case RPCClient::RVETIMEOUT: code = 503; break; default: code = 500; break; } int32_t enc = checkmapenc(outmap); std::string outtype = KTRPCTSVMTYPE; switch (enc) { case 'B': kc::strprintf(&outtype, "; %s=B", KTRPCTSVMATTR); break; case 'Q': kc::strprintf(&outtype, "; %s=Q", KTRPCTSVMATTR); break; case 'U': kc::strprintf(&outtype, "; %s=U", KTRPCTSVMATTR); break; } resheads["content-type"] = outtype; if (enc != 0) tsvmapencode(&outmap, enc); maptotsv(outmap, &resbody); return code; } bool process_binary(ThreadedServer* serv, ThreadedServer::Session* sess) { return worker_->process_binary(serv, sess); } void process_idle(HTTPServer* serv) { worker_->process_idle(serv_); } void process_timer(HTTPServer* serv) { worker_->process_timer(serv_); } void process_start(HTTPServer* serv) { worker_->process_start(serv_); } void process_finish(HTTPServer* serv) { worker_->process_finish(serv_); } RPCServer* serv_; RPCServer::Worker* worker_; }; /** Dummy constructor to forbid the use. */ RPCServer(const RPCServer&); /** Dummy Operator to forbid the use. */ RPCServer& operator =(const RPCServer&); /** The internal server. */ HTTPServer serv_; /** The adapter for worker. */ WorkerAdapter worker_; }; } // common namespace #endif // duplication check // END OF FILE kyototycoon-0.9.56/ktcommon.h0000644000175000017500000000253211757471602015232 0ustar mikiomikio/************************************************************************************************* * Common symbols for the library * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTCOMMON_H // duplication check #define _KTCOMMON_H #include #include #include #include #include #include /** * All symbols of Kyoto Tycoon. */ namespace kyototycoon { namespace kc = kyotocabinet; } #endif // duplication check // END OF FILE kyototycoon-0.9.56/example/0000755000175000017500000000000011757471566014674 5ustar mikiomikiokyototycoon-0.9.56/example/ktreplprint.rb0000644000175000017500000000214111757471566017575 0ustar mikiomikiorequire 'base64' rtspath = "ktreplprint.rts" mode = File::Constants::RDWR | File::Constants::CREAT File::open(rtspath, mode) do |rtsfile| while true begin line = $stdin.readline rescue break end line = line.strip fields = line.split("\t") next if fields.length < 4 rts = fields[0] rsid = fields[1] rdbid = fields[2] rcmd = fields[3] args = [] i = 4 while i < fields.length args.push(fields[i].unpack("m")[0]) i += 1 end printf("ts=%d sid=%d dbid=%d: ", rts, rsid, rdbid) case rcmd when "set" if args.length >= 2 key = args[0] value = args[1][5,args[1].length] nums = args[1].unpack("C5") xt = 0 nums.each do |num| xt = (xt << 8) + num end printf("set: key=%s value=%s xt=%d", key, value, xt) end when "remove" if args.length >= 1 key = args[0] printf("remove: key=%s", key) end when "clear" printf("clear") end printf("\n") rtsfile.pos = 0 rtsfile.printf("%020d\n", rts) end end exit 0 kyototycoon-0.9.56/example/ktmemcfastex.pl0000644000175000017500000000337011757471566017727 0ustar mikiomikiouse strict; use warnings; use Cache::Memcached::Fast; my $servers = [{ address => "127.0.0.1:11211", noreply => 1, }]; printf("connecting...\n"); my $cache = Cache::Memcached::Fast->new({ servers => $servers }); if (!defined($cache)) { printf("new failed\n"); } printf("checking the version...\n"); my $versions = $cache->server_versions(); while (my ($server, $version) = each(%$versions)) { printf("versions: %s: %s\n", $server, $version); } printf("flusing...\n"); if (!$cache->flush_all()) { printf("flush_all failed\n"); } printf("flusing without reply...\n"); $cache->flush_all(); printf("setting...\n"); for (my $i = 1; $i <= 10; $i++) { if (!$cache->set($i, $i)) { printf("set failed\n"); } } printf("incrementing...\n"); for (my $i = 1; $i <= 10; $i++) { if (!defined($cache->incr($i, 10000))) { printf("incr failed\n"); } if (!defined($cache->decr($i, 1000))) { printf("decr failed\n"); } } printf("retrieving...\n"); for (my $i = 1; $i <= 10; $i++) { my $value = $cache->get($i); printf("get: %s: %s\n", $i, $value); } printf("removing...\n"); for (my $i = 1; $i <= 10; $i++) { if (!$cache->remove($i)) { printf("remove failed\n"); } } printf("setting without reply...\n"); for (my $i = 1; $i <= 10; $i++) { $cache->set($i, $i); } printf("incrementing without reply...\n"); for (my $i = 1; $i <= 10; $i++) { $cache->incr($i, 1000); } printf("retrieving in bulk...\n"); my $values = $cache->get_multi(1..10); while (my ($key, $value) = each(%$values)) { printf("get_multi: %s: %s\n", $key, $value); } printf("removing without reply...\n"); for (my $i = 1; $i <= 10; $i++) { $cache->delete($i); } printf("disconnecting...\n"); $cache->disconnect_all(); kyototycoon-0.9.56/example/ktrestex.pl0000644000175000017500000000406411757471566017106 0ustar mikiomikiouse strict; use warnings; use LWP::UserAgent; use URI::Escape; { # RESTful interface of Kyoto Tycoon package KyotoTycoon; # constructor sub new { my $self = {}; bless $self; return $self; } # connect to the server sub open { my ($self, $host, $port, $timeout) = @_; $host = "127.0.0.1" if (!defined($host)); $port = 1978 if (!defined($port)); $timeout = 30 if (!defined($timeout)); $self->{base} = "http://$host:$port/"; $self->{ua} = LWP::UserAgent->new(keep_alive => 1); $self->{ua}->timeout($timeout); return undef; } # close the connection sub close { my ($self) = @_; $self->{ua} = undef; return undef; } # store a record sub set { my ($self, $key, $value, $xt) = @_; my $url = $self->{base} . URI::Escape::uri_escape($key); my @headers; if (defined($xt)) { $xt = time() + $xt; push(@headers, "X-Kt-Xt"); push(@headers, $xt); } my $req = HTTP::Request->new(PUT => $url, \@headers, $value); my $res = $self->{ua}->request($req); my $code = $res->code(); return $code == 201; } # remove a record sub remove { my ($self, $key) = @_; my $url = $self->{base} . URI::Escape::uri_escape($key); my $req = HTTP::Request->new(DELETE => $url); my $res = $self->{ua}->request($req); my $code = $res->code(); return $code == 204; } # retrieve the value of a record sub get { my ($self, $key) = @_; my $url = $self->{base} . URI::Escape::uri_escape($key); my $req = HTTP::Request->new(GET => $url); my $res = $self->{ua}->request($req); my $code = $res->code(); return undef if ($code != 200); return $res->content(); } } # sample usage my $kt = new KyotoTycoon; $kt->open("localhost", 1978); $kt->set("japan", "tokyo", 30); printf("%s\n", $kt->get("japan")); $kt->remove("japan"); $kt->close(); kyototycoon-0.9.56/example/ktremoteex.cc0000644000175000017500000000167411757471566017402 0ustar mikiomikio#include using namespace std; using namespace kyototycoon; // main routine int main(int argc, char** argv) { // create the database object RemoteDB db; // open the database if (!db.open()) { cerr << "open error: " << db.error().name() << endl; } // store records if (!db.set("foo", "hop") || !db.set("bar", "step") || !db.set("baz", "jump")) { cerr << "set error: " << db.error().name() << endl; } // retrieve a record string value; if (db.get("foo", &value)) { cout << value << endl; } else { cerr << "get error: " << db.error().name() << endl; } // traverse records RemoteDB::Cursor* cur = db.cursor(); cur->jump(); string ckey, cvalue; while (cur->get(&ckey, &cvalue, NULL, true)) { cout << ckey << ":" << cvalue << endl; } delete cur; // close the database if (!db.close()) { cerr << "close error: " << db.error().name() << endl; } return 0; } kyototycoon-0.9.56/example/Makefile0000644000175000017500000000340311460057211016306 0ustar mikiomikio# Makefile for sample programs of Kyoto Tycoon #================================================================ # Setting Variables #================================================================ # Generic settings SHELL = /bin/sh # Targets MYBINS = ktremoteex ktpollex ktthservex kthttpex # Building binaries CC = gcc CXX = g++ CFLAGS = -I. -I.. -Wall -ansi -pedantic -fsigned-char -O2 CXXFLAGS = -I. -I.. -Wall -fsigned-char -O2 LDFLAGS = LIBS = -L. -L.. -lkyototycoon -lkyotocabinet -lstdc++ -lz -lrt -lpthread -lm -lc LDENV = LD_RUN_PATH=/lib:/usr/lib:$(HOME)/lib:/usr/local/lib:.:.. RUNENV = LD_LIBRARY_PATH=/lib:/usr/lib:$(HOME)/lib:/usr/local/lib:.:.. #================================================================ # Suffix rules #================================================================ .SUFFIXES : .SUFFIXES : .c .cc .o .c.o : $(CC) -c $(CFLAGS) $< .cc.o : $(CXX) -c $(CXXFLAGS) $< #================================================================ # Actions #================================================================ all : $(MYBINS) clean : rm -rf $(MYBINS) *.exe *.o a.out check.out gmon.out leak.log casket* *~ static : make LDFLAGS="$(LDFLAGS) -static" check : rm -rf casket* $(RUNENV) ./ktremoteex .PHONY : all clean static #================================================================ # Building binaries #================================================================ ktremoteex : ktremoteex.o $(LDENV) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(LIBS) ktpollex : ktpollex.o $(LDENV) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(LIBS) ktthservex : ktthservex.o $(LDENV) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(LIBS) kthttpex : kthttpex.o $(LDENV) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(LIBS) # END OF FILE kyototycoon-0.9.56/example/ktpollex.cc0000644000175000017500000000473311757471566017054 0ustar mikiomikio#include using namespace std; using namespace kyototycoon; // the flag whether the server is alive Poller* g_poll = NULL; // stop the running server static void stopserver(int signum) { if (g_poll) g_poll->abort(); g_poll = NULL; } // main routine int main(int argc, char** argv) { // set the signal handler to stop the server setkillsignalhandler(stopserver); // open the server socket ServerSocket serv; serv.open("127.0.0.1:1978"); // open the event notifier Poller poll; poll.open(); g_poll = &poll; // deposit the server socket into the poller serv.set_event_flags(Pollable::EVINPUT); poll.deposit(&serv); // event loop while (g_poll) { // wait one or more active requests if (poll.wait()) { // iterate all active requests Pollable* event; while ((event = poll.next()) != NULL) { if (event == &serv) { // accept a new connection Socket* sock = new Socket; sock->set_timeout(1.0); if (serv.accept(sock)) { sock->set_event_flags(Pollable::EVINPUT); poll.deposit(sock); } // undo the server socket serv.set_event_flags(Pollable::EVINPUT); poll.undo(&serv); } else { // process each request Socket* sock = (Socket*)event; // read a line from the client socket char line[1024]; if (sock->receive_line(line, sizeof(line))) { if (!kc::stricmp(line, "/quit")) { // process the quit command sock->printf("> Bye!\n"); poll.withdraw(sock); sock->close(); delete sock; } else { // echo back the message sock->printf("> %s\n", line); // undo the client socket serv.set_event_flags(Pollable::EVINPUT); poll.undo(sock); } } else { // process a connection closed by the client poll.withdraw(sock); sock->close(); delete sock; } } } } } // clean up all connections if (poll.flush()) { Pollable* event; while ((event = poll.next()) != NULL) { if (event != &serv) { Socket* sock = (Socket*)event; poll.withdraw(sock); sock->close(); delete sock; } } } // close the event notifier poll.close(); // close the server socket serv.close(); return 0; } kyototycoon-0.9.56/example/ktthservex.cc0000644000175000017500000000236011757471566017413 0ustar mikiomikio#include using namespace std; using namespace kyototycoon; // the flag whether the server is alive ThreadedServer* g_serv = NULL; // stop the running server static void stopserver(int signum) { if (g_serv) g_serv->stop(); g_serv = NULL; } // main routine int main(int argc, char** argv) { // set the signal handler to stop the server setkillsignalhandler(stopserver); // prepare the worker class Worker : public ThreadedServer::Worker { bool process(ThreadedServer* serv, ThreadedServer::Session* sess) { bool keep = false; // read a line from the client socket char line[1024]; if (sess->receive_line(line, sizeof(line))) { if (!kc::stricmp(line, "/quit")) { // process the quit command sess->printf("> Bye!\n"); } else { // echo back the message sess->printf("> %s\n", line); keep = true; } } return keep; } }; Worker worker; // prepare the server ThreadedServer serv; serv.set_network("127.0.0.1:1978", 1.0); serv.set_worker(&worker, 4); g_serv = &serv; // start the server and block until its stop serv.start(); // clean up connections and other resources serv.finish(); return 0; } kyototycoon-0.9.56/example/ktscrjsonex.lua0000644000175000017500000000747411757471566017770 0ustar mikiomikiokt = __kyototycoon__ db = kt.db json = require("json") -- post a new document function writedoc(inmap, outmap) local doc = inmap.doc if not doc then return kt.RVEINVALID end local doc = json.decode(doc) local owner = tonumber(doc.owner) local date = tonumber(doc.date) local title = tostring(doc.title) local text = tostring(doc.text) local key = string.format("%010d:%010d", owner, date) local doc = {} doc.title = title doc.text = text local value = json.encode(doc) if not db:add(key, value) then local err = db:error() if err:code() == kt.Error.DUPREC then return kt.RVELOGIC end return kt.RVEINTERNAL end return kt.RVSUCCESS end -- post a new comment function addcomment(inmap, outmap) local owner = tonumber(inmap.owner) local date = tonumber(inmap.date) local comowner = tonumber(inmap.comowner) local comdate = tostring(inmap.comdate) local comtext = tostring(inmap.comtext) if not owner or not date or not comowner or not comdate or not comtext then return kt.RVEINVALID end local key = string.format("%010d:%010d", owner, date) local hit = false local function visit(rkey, rvalue) local doc = json.decode(rvalue) if not doc.comments then doc.comments = {} end local newcom = {} newcom.owner = comowner newcom.date = comdate newcom.text = comtext table.insert(doc.comments, newcom) hit = true return json.encode(doc) end if not db:accept(key, visit) then local err = db:error() if err:code() == kt.Error.DUPREC then return kt.RVELOGIC end return kt.RVEINTERNAL end if not hit then return kt.RVELOGIC end return kt.RVSUCCESS end -- get a document function getdoc(inmap, outmap) local owner = tonumber(inmap.owner) local date = tonumber(inmap.date) if not owner or not date then return kt.RVEINVALID end local key = string.format("%010d:%010d", owner, date) local value = db:get(key) if not value then return kt.RVELOGIC end local doc = _composedoc(key, value) outmap.doc = json.encode(doc) return kt.RVSUCCESS end -- list documents of a user function listnewdocs(inmap, outmap) local owner = tonumber(inmap.owner) local max = tonumber(inmap.max) if not owner then return kt.RVEINVALID end if not max then max = 10 end local key = string.format("%010d:", owner) local cur = db:cursor() cur:jump_back(key .. "~") local num = 0 while num < max do local rkey, rvalue = cur:get() if not rkey or not kt.strfwm(rkey, key) then break end cur:step_back() local doc = _composedoc(rkey, rvalue) num = num + 1 outmap[num] = json.encode(doc) end return kt.RVSUCCESS end -- list documents of a user without the text and the comments function listnewdocslight(inmap, outmap) local owner = tonumber(inmap.owner) local max = tonumber(inmap.max) if not owner then return kt.RVEINVALID end if not max then max = 10 end local key = string.format("%010d:", owner) local cur = db:cursor() cur:jump_back(key .. "~") local num = 0 while num < max do local rkey, rvalue = cur:get() if not rkey or not kt.strfwm(rkey, key) then break end cur:step_back() local doc = _composedoc(rkey, rvalue) doc.text = nil doc.comnum = #doc.comments doc.comments = nil num = num + 1 outmap[num] = json.encode(doc) end return kt.RVSUCCESS end -- helper to compose a document object function _composedoc(key, value) local doc = json.decode(value) doc.owner = string.gsub(key, ":%d*", "") doc.date = string.gsub(key, "%d*:", "") if not doc.comments then doc.comments = {} end return doc end kyototycoon-0.9.56/example/ktreplmysql.rb0000644000175000017500000000355311757471566017616 0ustar mikiomikiorequire 'dbi' require 'base64' hostname = "localhost" dbname = "kttest" username = "root" password = "" rtspath = "ktreplmysql.rts" # $ mysql --user=root # > create database kttest; # > create table kttest ( # k varchar(256) primary key, # v varchar(256) not null, # xt datetime not null # ) TYPE=InnoDB; begin dbh = DBI::connect("dbi:Mysql:#{dbname}:#{hostname}", username, password) sthins = dbh.prepare("INSERT INTO kttest ( k, v, xt ) VALUES ( ?, ?, ? )" + " ON DUPLICATE KEY UPDATE v = ?, xt = ?;") sthrem = dbh.prepare("DELETE FROM kttest WHERE k = ?;") sthclr = dbh.prepare("DELETE FROM kttest;") mode = File::Constants::RDWR | File::Constants::CREAT File::open(rtspath, mode) do |rtsfile| while true begin line = $stdin.readline rescue break end line = line.strip fields = line.split("\t") next if fields.length < 4 rts = fields[0] rsid = fields[1] rdbid = fields[2] rcmd = fields[3] args = [] i = 4 while i < fields.length args.push(fields[i].unpack("m")[0]) i += 1 end case rcmd when "set" if args.length >= 2 key = args[0] value = args[1][5,args[1].length] nums = args[1].unpack("C5") xt = 0 nums.each do |num| xt = (xt << 8) + num end xt = 1 << 32 if xt > (1 << 32) xt = Time::at(xt).strftime("%Y-%m-%d %H:%M:%S") sthins.execute(key, value, xt, value, xt) end when "remove" if args.length >= 1 key = args[0] sthrem.execute(key) end when "clear" sthclr.execute() end rtsfile.pos = 0 rtsfile.printf("%020d\n", rts) end end rescue Exception => e printf("Error: %s\n", e) ensure dbh.disconnect if dbh end exit 0 kyototycoon-0.9.56/example/ktmemcex.rb0000644000175000017500000000204511757471566017037 0ustar mikiomikiorequire 'memcache' host = "127.0.0.1:11211" options = { :timeout => 3600, } printf("connecting...\n") cache = MemCache.new([host], options) printf("count: %s\n", cache.stats[host]["curr_items"]) printf("flusing...\n") cache.flush_all printf("count: %s\n", cache.stats[host]["curr_items"]) printf("setting...\n") (1..10).each do |i| str = i.to_s cache.set(str, str, 180, { :raw => true }) cache.add(str, str, 180, { :raw => true }) cache.replace(str, str, 180, { :raw => true }) end printf("count: %s\n", cache.stats[host]["curr_items"]) printf("incrementing...\n") (1..10).each do |i| str = i.to_s cache.incr(str, 10000) cache.decr(str, 1000) end printf("count: %s\n", cache.stats[host]["curr_items"]) printf("getting...\n") (1..10).each do |i| str = i.to_s value = cache.get(str, { :raw => true }) printf("get: %s: %s\n", str, value) end printf("count: %s\n", cache.stats[host]["curr_items"]) printf("removing...\n") (1..10).each do |i| str = i.to_s cache.delete(str) end printf("count: %s\n", cache.stats[host]["curr_items"]) kyototycoon-0.9.56/example/ktrestex.rb0000644000175000017500000000213211757471566017070 0ustar mikiomikiorequire 'uri' require 'net/http' # RESTful interface of Kyoto Tycoon class KyotoTycoon # connect to the server def open(host = "127.0.0.1", port = 1978, timeout = 30) @ua = Net::HTTP::new(host, port) @ua.read_timeout = timeout @ua.start end # close the connection def close @ua.finish end # store a record def set(key, value, xt = nil) key = "/" + URI::encode(key) req = Net::HTTP::Put::new(key) if xt xt = Time::now.to_i + xt req.add_field("X-Kt-Xt", xt) end res = @ua.request(req, value) res.code.to_i == 201 end # remove a record def remove(key) key = "/" + URI::encode(key) req = Net::HTTP::Delete::new(key) res = @ua.request(req) res.code.to_i == 204 end # retrieve the value of a record def get(key) key = "/" + URI::encode(key) req = Net::HTTP::Get::new(key) res = @ua.request(req) return nil if res.code.to_i != 200 res.body end end # sample usage kt = KyotoTycoon::new kt.open("localhost", 1978) kt.set("japan", "tokyo", 60) printf("%s\n", kt.get("japan")) kt.remove("japan") kt.close kyototycoon-0.9.56/example/ktmemcmqex.rb0000644000175000017500000000201011757471566017365 0ustar mikiomikiorequire 'memcache' host = "127.0.0.1:11211" options = { :timeout => 3600, } thnum = 4 rnum = 100 gcache = MemCache.new([host], options) gcache.flush_all producers = Array::new for thid in 0...thnum th = Thread::new(thid) { |id| cache = MemCache.new([host], options) mid = rnum / 4 for i in 0...rnum name = (i % 10).to_s value = i.to_s printf("set: %s: %s\n", name, value) cache.set(name, value, 0, { :raw => true }) wt = rand() * 0.1 sleep(wt) if i >= mid && wt >= 0.01 end } producers.push(th) end workers = Array::new for thid in 0...thnum th = Thread::new(thid) { |id| cache = MemCache.new([host], options) for i in 0...rnum name = (i % 10).to_s value = cache.get(name, { :raw => true }) printf("get: %s: %s\n", name, value ? value : "(miss)") cache.delete(name) end } workers.push(th) end workers.each { |th| th.join } producers.each { |th| th.join } GC.start printf("count: %s\n", gcache.stats[host]["curr_items"]) kyototycoon-0.9.56/example/ktrestex.py0000644000175000017500000000307511757471566017124 0ustar mikiomikioimport time import urllib import http.client # RESTful interface of Kyoto Tycoon class KyotoTycoon: # connect to the server def open(self, host = "127.0.0.1", port = 1978, timeout = 30): self.ua = http.client.HTTPConnection(host, port, False, timeout) # close the connection def close(self): self.ua.close() # store a record def set(self, key, value, xt = None): if isinstance(key, str): key = key.encode("UTF-8") if isinstance(value, str): value = value.encode("UTF-8") key = "/" + urllib.parse.quote(key) headers = {} if xt != None: xt = int(time.time()) + xt headers["X-Kt-Xt"] = str(xt) self.ua.request("PUT", key, value, headers) res = self.ua.getresponse() body = res.read() return res.status == 201 # remove a record def remove(self, key): if isinstance(key, str): key = key.encode("UTF-8") key = "/" + urllib.parse.quote(key) self.ua.request("DELETE", key) res = self.ua.getresponse() body = res.read() return res.status == 204 # retrieve the value of a record def get(self, key): if isinstance(key, str): key = key.encode("UTF-8") key = "/" + urllib.parse.quote(key) self.ua.request("GET", key) res = self.ua.getresponse() body = res.read() if res.status != 200: return None return body # sample usage kt = KyotoTycoon() kt.open("localhost", 1978) kt.set("japan", "tokyo", 60) print(kt.get("japan")) kt.remove("japan") kt.close() kyototycoon-0.9.56/example/kthttpex.cc0000644000175000017500000000271311757471566017061 0ustar mikiomikio#include using namespace std; using namespace kyototycoon; // the flag whether the server is alive HTTPServer* g_serv = NULL; // stop the running server static void stopserver(int signum) { if (g_serv) g_serv->stop(); g_serv = NULL; } // main routine int main(int argc, char** argv) { // set the signal handler to stop the server setkillsignalhandler(stopserver); // prepare the worker class Worker : public HTTPServer::Worker { int32_t process(HTTPServer* serv, HTTPServer::Session* sess, const string& path, HTTPClient::Method method, const map& reqheads, const string& reqbody, map& resheads, string& resbody, const map& misc) { // echo back the input data for (map::const_iterator it = reqheads.begin(); it != reqheads.end(); it++) { if (!it->first.empty()) resbody.append(it->first + ": "); resbody.append(it->second + "\n"); } resbody.append(reqbody); // return the status code return 200; } }; Worker worker; // prepare the server HTTPServer serv; serv.set_network("127.0.0.1:1978", 1.0); serv.set_worker(&worker, 4); g_serv = &serv; // start the server and block until its stop serv.start(); // clean up connections and other resources serv.finish(); return 0; } kyototycoon-0.9.56/example/ktscrtableex.lua0000644000175000017500000001116411757471566020075 0ustar mikiomikiokt = __kyototycoon__ db = kt.db -- prepare secondary indices idxdbs = {} for dbname, dbobj in pairs(kt.dbs) do if kt.strbwm(dbname, ".kct") then local prefix = kt.regex(dbname, ".*/", "") prefix = kt.regex(dbname, ".kct$", "") if #prefix > 0 then idxdbs[prefix] = dbobj end end end -- set a record function set(inmap, outmap) local id = tostring(inmap.id) if not id then return kt.RVEINVALID end local err = false inmap.id = nil local serial = kt.mapdump(inmap) -- visitor function local function visit(key, value, xt) -- clean up indices if value then local obj = kt.mapload(value) for rkey, rvalue in pairs(obj) do local idxdb = idxdbs[rkey] if idxdb then local idxkey = rvalue .. " " .. id if not idxdb:remove(idxkey) then kt.log("error", "removing an index entry failed") err = true end end end end -- insert into indices for rkey, rvalue in pairs(inmap) do local idxdb = idxdbs[rkey] if idxdb then local idxkey = rvalue .. " " .. id if not idxdb:set(idxkey, "") then kt.log("error", "setting an index entry failed") err = true end end end -- insert the serialized data into the main database return serial end -- perform the visitor atomically if not db:accept(id, visit) then kt.log("error", "inserting a record failed") err = true end if err then return kt.EVEINTERNAL end return kt.RVSUCCESS end -- get a record function get(inmap, outmap) local id = tostring(inmap.id) if not id then return kt.RVEINVALID end local serial = db:get(id) if not serial then return kt.RVELOGIC end local rec = kt.mapload(serial) for rkey, rvalue in pairs(rec) do outmap[rkey] = rvalue end return kt.RVSUCCESS end -- get heading records function head(inmap, outmap) local name = tostring(inmap.name) if not name then return kt.RVEINVALID end local max = tonumber(inmap.max) if not max then max = 10 end local idxdb = idxdbs[name] if not idxdb then return kt.RVELOGIC end local cur = idxdb:cursor() cur:jump() local rec while max > 0 do local key = cur:get_key(true) if not key then break end local rkey = kt.regex(key, "[^ ]+ ", "") local rvalue = kt.regex(key, " .*", "") outmap[rkey] = rvalue max = max - 1 end cur:disable() return kt.RVSUCCESS end -- get tailing records function tail(inmap, outmap) local name = tostring(inmap.name) if not name then return kt.RVEINVALID end local max = tonumber(inmap.max) if not max then max = 10 end local idxdb = idxdbs[name] if not idxdb then return kt.RVELOGIC end local cur = idxdb:cursor() cur:jump_back() local rec while max > 0 do local key = cur:get_key() if not key then break end local rkey = kt.regex(key, "[^ ]+ ", "") local rvalue = kt.regex(key, " .*", "") outmap[rkey] = rvalue cur:step_back() max = max - 1 end cur:disable() return kt.RVSUCCESS end -- reindex an index function reindex(inmap, outmap) local name = tostring(inmap.name) if not name then return kt.RVEINVALID end local idxdb = idxdbs[name] if not idxdb then return kt.RVELOGIC end local err = false -- map function: invert the record data local function map(key, value, emit) local obj = kt.mapload(value) for rkey, rvalue in pairs(obj) do local idxdb = idxdbs[rkey] if idxdb then emit(rvalue, key) end end return true end -- reduce function: insert into the index local function reduce(key, iter) local value while true do value = iter() if not value then break end local idxkey = key .. " " .. value if not idxdb:set(idxkey, "") then kt.log("error", "setting an index entry failed") err = true end end if err then return false end return true end -- clear the index if not idxdb:clear() then kt.log("error", "clearing an index failed") err = true end -- update the index if not db:mapreduce(map, reduce) then kt.log("error", "mapreduce failed") err = true end if err then return kt.EVEINTERNAL end return kt.RVSUCCESS end kyototycoon-0.9.56/example/ktscrex.lua0000644000175000017500000001377111757471566017073 0ustar mikiomikiokt = __kyototycoon__ db = kt.db -- log the start-up message if kt.thid == 0 then kt.log("system", "the Lua script has been loaded") end -- echo back the input data as the output data function echo(inmap, outmap) for key, value in pairs(inmap) do outmap[key] = value end return kt.RVSUCCESS end -- report the internal state of the server function report(inmap, outmap) outmap["__kyototycoon__.VERSION"] = kt.VERSION outmap["__kyototycoon__.thid"] = kt.thid outmap["__kyototycoon__.db"] = tostring(kt.db) for i = 1, #kt.dbs do local key = "__kyototycoon__.dbs[" .. i .. "]" outmap[key] = tostring(kt.dbs[i]) end local names = "" for name, value in pairs(kt.dbs) do if #names > 0 then names = names .. "," end names = names .. name end outmap["names"] = names return kt.RVSUCCESS end -- log a message function log(inmap, outmap) local kind = inmap.kind local message = inmap.message if not message then return kt.RVEINVALID end if not kind then kind = "info" end kt.log(kind, message) return kt.RVSUCCESS end -- store a record function set(inmap, outmap) local key = inmap.key local value = inmap.value if not key or not value then return kt.RVEINVALID end local xt = inmap.xt if not db:set(key, value, xt) then return kt.RVEINTERNAL end return kt.RVSUCCESS end -- remove a record function remove(inmap, outmap) local key = inmap.key if not key then return kt.RVEINVALID end if not db:remove(key) then local err = db:error() if err:code() == kt.Error.NOREC then return kt.RVELOGIC end return kt.RVEINTERNAL end return kt.RVSUCCESS end -- increment the numeric string value function increment(inmap, outmap) local key = inmap.key local num = inmap.num if not key or not num then return kt.RVEINVALID end local function visit(rkey, rvalue, rxt) rvalue = tonumber(rvalue) if not rvalue then rvalue = 0 end num = rvalue + num return num end if not db:accept(key, visit) then return kt.REINTERNAL end outmap.num = num return kt.RVSUCCESS end -- retrieve the value of a record function get(inmap, outmap) local key = inmap.key if not key then return kt.RVEINVALID end local value, xt = db:get(key) if value then outmap.value = value outmap.xt = xt else local err = db:error() if err:code() == kt.Error.NOREC then return kt.RVELOGIC end return kt.RVEINTERNAL end return kt.RVSUCCESS end -- store records at once function setbulk(inmap, outmap) local num = db:set_bulk(inmap) if num < 0 then return kt.RVEINTERNAL end outmap["num"] = num return kt.RVSUCCESS end -- remove records at once function removebulk(inmap, outmap) local keys = {} for key, value in pairs(inmap) do table.insert(keys, key) end local num = db:remove_bulk(keys) if num < 0 then return kt.RVEINTERNAL end outmap["num"] = num return kt.RVSUCCESS end -- retrieve records at once function getbulk(inmap, outmap) local keys = {} for key, value in pairs(inmap) do table.insert(keys, key) end local res = db:get_bulk(keys) if not res then return kt.RVEINTERNAL end for key, value in pairs(res) do outmap[key] = value end return kt.RVSUCCESS end -- move the value of a record to another function move(inmap, outmap) local srckey = inmap.src local destkey = inmap.dest if not srckey or not destkey then return kt.RVEINVALID end local keys = { srckey, destkey } local first = true local srcval = nil local srcxt = nil local function visit(key, value, xt) if first then srcval = value srcxt = xt first = false return kt.Visitor.REMOVE end if srcval then return srcval, srcxt end return kt.Visitor.NOP end if not db:accept_bulk(keys, visit) then return kt.REINTERNAL end if not srcval then return kt.RVELOGIC end return kt.RVSUCCESS end -- list all records function list(inmap, outmap) local cur = db:cursor() cur:jump() while true do local key, value, xt = cur:get(true) if not key then break end outmap[key] = value end return kt.RVSUCCESS end -- upcate all characters in the value of a record function upcase(inmap, outmap) local key = inmap.key if not key then return kt.RVEINVALID end local function visit(key, value, xt) if not value then return kt.Visitor.NOP end return string.upper(value) end if not db:accept(key, visit) then return kt.RVEINTERNAL end return kt.RVSUCCESS end -- prolong the expiration time of a record function survive(inmap, outmap) local key = inmap.key if not key then return kt.RVEINVALID end local function visit(key, value, xt) if not value then return kt.Visitor.NOP end outmap.old_xt = xt if xt > kt.time() + 3600 then return kt.Visitor.NOP end return value, 3600 end if not db:accept(key, visit) then return kt.RVEINTERNAL end return kt.RVSUCCESS end -- count words with the MapReduce framework function countwords(inmap, outmap) local function map(key, value, emit) local values = kt.split(value, " ") for i = 1, #values do local word = kt.regex(values[i], "[ .?!:;]", "") word = string.lower(word) if #word > 0 then if not emit(word, "") then return false end end end return true end local function reduce(key, iter) local count = 0 while true do local value = iter() if not value then break end count = count + 1 end outmap[key] = count return true end if not db:mapreduce(map, reduce, nil, kt.DB.XNOLOCK) then return kt.RVEINTERNAL end return kt.RVSUCCESS end kyototycoon-0.9.56/ktdbext.h0000644000175000017500000006577011757471602015065 0ustar mikiomikio/************************************************************************************************* * Database extension * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTDBEXT_H // duplication check #define _KTDBEXT_H #include #include #include #include #include namespace kyototycoon { // common namespace /** * MapReduce framework. * @note Although this framework is not distributed or concurrent, it is useful for aggregate * calculation with less CPU loading and less memory usage. */ class MapReduce { public: class ValueIterator; private: class FlushThread; class ReduceTaskQueue; class MapVisitor; struct MergeLine; /** An alias of vector of loaded values. */ typedef std::vector Values; /** The default number of temporary databases. */ static const size_t DEFDBNUM = 8; /** The maxinum number of temporary databases. */ static const size_t MAXDBNUM = 256; /** The default cache limit. */ static const int64_t DEFCLIM = 512LL << 20; /** The default cache bucket numer. */ static const int64_t DEFCBNUM = 1048583LL; /** The bucket number of temprary databases. */ static const int64_t DBBNUM = 512LL << 10; /** The page size of temprary databases. */ static const int32_t DBPSIZ = 32768; /** The mapped size of temprary databases. */ static const int64_t DBMSIZ = 516LL * 4096; /** The page cache capacity of temprary databases. */ static const int64_t DBPCCAP = 16LL << 20; /** The default number of threads in parallel mode. */ static const size_t DEFTHNUM = 8; /** The number of slots of the record lock. */ static const int32_t RLOCKSLOT = 256; public: /** * Value iterator for the reducer. */ class ValueIterator { friend class MapReduce; public: /** * Get the next value. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @return the pointer to the next value region, or NULL if no value remains. */ const char* next(size_t* sp) { _assert_(sp); if (!vptr_) { if (vit_ == vend_) return NULL; vptr_ = vit_->data(); vsiz_ = vit_->size(); vit_++; } uint64_t vsiz; size_t step = kc::readvarnum(vptr_, vsiz_, &vsiz); vptr_ += step; vsiz_ -= step; const char* vbuf = vptr_; *sp = vsiz; vptr_ += vsiz; vsiz_ -= vsiz; if (vsiz_ < 1) vptr_ = NULL; return vbuf; } private: /** * Default constructor. */ explicit ValueIterator(Values::const_iterator vit, Values::const_iterator vend) : vit_(vit), vend_(vend), vptr_(NULL), vsiz_(0) { _assert_(true); } /** * Destructor. */ ~ValueIterator() { _assert_(true); } /** Dummy constructor to forbid the use. */ ValueIterator(const ValueIterator&); /** Dummy Operator to forbid the use. */ ValueIterator& operator =(const ValueIterator&); /** The current iterator of loaded values. */ Values::const_iterator vit_; /** The ending iterator of loaded values. */ Values::const_iterator vend_; /** The pointer of the current value. */ const char* vptr_; /** The size of the current value. */ size_t vsiz_; }; /** * Execution options. */ enum Option { XNOLOCK = 1 << 0, ///< avoid locking against update operations XPARAMAP = 1 << 1, ///< run mappers in parallel XPARARED = 1 << 2, ///< run reducers in parallel XPARAFLS = 1 << 3, ///< run cache flushers in parallel XNOCOMP = 1 << 8 ///< avoid compression of temporary databases }; /** * Default constructor. */ explicit MapReduce() : rcomp_(NULL), tmpdbs_(NULL), dbnum_(DEFDBNUM), dbclock_(0), mapthnum_(DEFTHNUM), redthnum_(DEFTHNUM), flsthnum_(DEFTHNUM), cache_(NULL), csiz_(0), clim_(DEFCLIM), cbnum_(DEFCBNUM), flsths_(NULL), redtasks_(NULL), redaborted_(false), rlocks_(NULL) { _assert_(true); } /** * Destructor. */ virtual ~MapReduce() { _assert_(true); } /** * Map a record data. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @return true on success, or false on failure. * @note This function can call the MapReduce::emit method to emit a record. To avoid * deadlock, any explicit database operation must not be performed in this function. */ virtual bool map(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) = 0; /** * Reduce a record data. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param iter the iterator to get the values. * @return true on success, or false on failure. * @note To avoid deadlock, any explicit database operation must not be performed in this * function. */ virtual bool reduce(const char* kbuf, size_t ksiz, ValueIterator* iter) = 0; /** * Preprocess the map operations. * @return true on success, or false on failure. * @note This function can call the MapReduce::emit method to emit a record. To avoid * deadlock, any explicit database operation must not be performed in this function. */ virtual bool preprocess() { _assert_(true); return true; } /** * Mediate between the map and the reduce phases. * @return true on success, or false on failure. * @note This function can call the MapReduce::emit method to emit a record. To avoid * deadlock, any explicit database operation must not be performed in this function. */ virtual bool midprocess() { _assert_(true); return true; } /** * Postprocess the reduce operations. * @return true on success, or false on failure. * @note To avoid deadlock, any explicit database operation must not be performed in this * function. */ virtual bool postprocess() { _assert_(true); return true; } /** * Process a log message. * @param name the name of the event. * @param message a supplement message. * @return true on success, or false on failure. */ virtual bool log(const char* name, const char* message) { _assert_(name && message); return true; } /** * Execute the MapReduce process about a database. * @param db the source database. * @param tmppath the path of a directory for the temporary data storage. If it is an empty * string, temporary data are handled on memory. * @param opts the optional features by bitwise-or: MapReduce::XNOLOCK to avoid locking * against update operations by other threads, MapReduce::XNOCOMP to avoid compression of * temporary databases. * @return true on success, or false on failure. */ bool execute(TimedDB* db, const std::string& tmppath = "", uint32_t opts = 0) { int64_t count = db->count(); if (count < 0) { if (db->error() != kc::BasicDB::Error::NOIMPL) return false; count = 0; } bool err = false; double stime, etime; db_ = db; rcomp_ = kc::LEXICALCOMP; kc::BasicDB* idb = db->reveal_inner_db(); const std::type_info& info = typeid(*idb); if (info == typeid(kc::GrassDB)) { kc::GrassDB* gdb = (kc::GrassDB*)idb; rcomp_ = gdb->rcomp(); } else if (info == typeid(kc::TreeDB)) { kc::TreeDB* tdb = (kc::TreeDB*)idb; rcomp_ = tdb->rcomp(); } else if (info == typeid(kc::ForestDB)) { kc::ForestDB* fdb = (kc::ForestDB*)idb; rcomp_ = fdb->rcomp(); } tmpdbs_ = new kc::BasicDB*[dbnum_]; if (tmppath.empty()) { if (!logf("prepare", "started to open temporary databases on memory")) err = true; stime = kc::time(); for (size_t i = 0; i < dbnum_; i++) { kc::GrassDB* gdb = new kc::GrassDB; int32_t myopts = 0; if (!(opts & XNOCOMP)) myopts |= kc::GrassDB::TCOMPRESS; gdb->tune_options(myopts); gdb->tune_buckets(DBBNUM / 2); gdb->tune_page(DBPSIZ); gdb->tune_page_cache(DBPCCAP); gdb->tune_comparator(rcomp_); gdb->open("%", kc::GrassDB::OWRITER | kc::GrassDB::OCREATE | kc::GrassDB::OTRUNCATE); tmpdbs_[i] = gdb; } etime = kc::time(); if (!logf("prepare", "opening temporary databases finished: time=%.6f", etime - stime)) err = true; if (err) { delete[] tmpdbs_; return false; } } else { kc::File::Status sbuf; if (!kc::File::status(tmppath, &sbuf) || !sbuf.isdir) { db->set_error(kc::BasicDB::Error::NOREPOS, "no such directory"); delete[] tmpdbs_; return false; } if (!logf("prepare", "started to open temporary databases under %s", tmppath.c_str())) err = true; stime = kc::time(); uint32_t pid = getpid() & kc::UINT16MAX; uint32_t tid = kc::Thread::hash() & kc::UINT16MAX; uint32_t ts = kc::time() * 1000; for (size_t i = 0; i < dbnum_; i++) { std::string childpath = kc::strprintf("%s%cmr-%04x-%04x-%08x-%03d%ckct", tmppath.c_str(), kc::File::PATHCHR, pid, tid, ts, (int)(i + 1), kc::File::EXTCHR); kc::TreeDB* tdb = new kc::TreeDB; int32_t myopts = kc::TreeDB::TSMALL | kc::TreeDB::TLINEAR; if (!(opts & XNOCOMP)) myopts |= kc::TreeDB::TCOMPRESS; tdb->tune_options(myopts); tdb->tune_buckets(DBBNUM); tdb->tune_page(DBPSIZ); tdb->tune_map(DBMSIZ); tdb->tune_page_cache(DBPCCAP); tdb->tune_comparator(rcomp_); if (!tdb->open(childpath, kc::TreeDB::OWRITER | kc::TreeDB::OCREATE | kc::TreeDB::OTRUNCATE)) { const kc::BasicDB::Error& e = tdb->error(); db->set_error(e.code(), e.message()); err = true; } tmpdbs_[i] = tdb; } etime = kc::time(); if (!logf("prepare", "opening temporary databases finished: time=%.6f", etime - stime)) err = true; if (err) { for (size_t i = 0; i < dbnum_; i++) { delete tmpdbs_[i]; } delete[] tmpdbs_; return false; } } if (opts & XPARARED) redtasks_ = new ReduceTaskQueue; if (opts & XPARAFLS) flsths_ = new std::deque; if (opts & XNOLOCK) { MapChecker mapchecker; MapVisitor mapvisitor(this, &mapchecker, count); mapvisitor.visit_before(); if (!err) { TimedDB::Cursor* cur = db->cursor(); if (!cur->jump() && cur->error() != kc::BasicDB::Error::NOREC) err = true; while (!err) { if (!cur->accept(&mapvisitor, false, true)) { if (cur->error() != kc::BasicDB::Error::NOREC) err = true; break; } } delete cur; } if (mapvisitor.error()) err = true; mapvisitor.visit_after(); } else if (opts & XPARAMAP) { MapChecker mapchecker; MapVisitor mapvisitor(this, &mapchecker, count); rlocks_ = new kc::SlottedMutex(RLOCKSLOT); if (!err && !db->scan_parallel(&mapvisitor, mapthnum_, &mapchecker)) { db_->set_error(kc::BasicDB::Error::LOGIC, "mapper failed"); err = true; } delete rlocks_; rlocks_ = NULL; if (mapvisitor.error()) err = true; } else { MapChecker mapchecker; MapVisitor mapvisitor(this, &mapchecker, count); if (!err && !db->iterate(&mapvisitor, false, &mapchecker)) err = true; if (mapvisitor.error()) err = true; } if (flsths_) { delete flsths_; flsths_ = NULL; } if (redtasks_) { delete redtasks_; redtasks_ = NULL; } if (!logf("clean", "closing the temporary databases")) err = true; stime = kc::time(); for (size_t i = 0; i < dbnum_; i++) { std::string path = tmpdbs_[i]->path(); if (!tmpdbs_[i]->clear()) { const kc::BasicDB::Error& e = tmpdbs_[i]->error(); db->set_error(e.code(), e.message()); err = true; } if (!tmpdbs_[i]->close()) { const kc::BasicDB::Error& e = tmpdbs_[i]->error(); db->set_error(e.code(), e.message()); err = true; } if (!tmppath.empty()) kc::File::remove(path); delete tmpdbs_[i]; } etime = kc::time(); if (!logf("clean", "closing the temporary databases finished: time=%.6f", etime - stime)) err = true; delete[] tmpdbs_; return !err; } /** * Set the storage configurations. * @param dbnum the number of temporary databases. * @param clim the limit size of the internal cache. * @param cbnum the bucket number of the internal cache. */ void tune_storage(int32_t dbnum, int64_t clim, int64_t cbnum) { _assert_(true); dbnum_ = dbnum > 0 ? dbnum : DEFDBNUM; if (dbnum_ > MAXDBNUM) dbnum_ = MAXDBNUM; clim_ = clim > 0 ? clim : DEFCLIM; cbnum_ = cbnum > 0 ? cbnum : DEFCBNUM; if (cbnum_ > kc::INT16MAX) cbnum_ = kc::nearbyprime(cbnum_); } /** * Set the thread configurations. * @param mapthnum the number of threads for the mapper. * @param redthnum the number of threads for the reducer. * @param flsthnum the number of threads for the internal flusher. */ void tune_thread(int32_t mapthnum, int32_t redthnum, int32_t flsthnum) { _assert_(true); mapthnum_ = mapthnum > 0 ? mapthnum : DEFTHNUM; redthnum_ = redthnum > 0 ? redthnum : DEFTHNUM; flsthnum_ = flsthnum > 0 ? flsthnum : DEFTHNUM; } protected: /** * Emit a record from the mapper. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @return true on success, or false on failure. */ bool emit(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ); bool err = false; size_t rsiz = kc::sizevarnum(vsiz) + vsiz; char stack[kc::NUMBUFSIZ*4]; char* rbuf = rsiz > sizeof(stack) ? new char[rsiz] : stack; char* wp = rbuf; wp += kc::writevarnum(rbuf, vsiz); std::memcpy(wp, vbuf, vsiz); if (rlocks_) { size_t bidx = kc::TinyHashMap::hash_record(kbuf, ksiz) % cbnum_; size_t lidx = bidx % RLOCKSLOT; rlocks_->lock(lidx); cache_->append(kbuf, ksiz, rbuf, rsiz); rlocks_->unlock(lidx); } else { cache_->append(kbuf, ksiz, rbuf, rsiz); } if (rbuf != stack) delete[] rbuf; csiz_ += kc::sizevarnum(ksiz) + ksiz + rsiz; return !err; } private: /** * Cache flusher. */ class FlushThread : public kc::Thread { public: /** constructor */ explicit FlushThread(MapReduce* mr, kc::BasicDB* tmpdb, kc::TinyHashMap* cache, size_t csiz, bool cown) : mr_(mr), tmpdb_(tmpdb), cache_(cache), csiz_(csiz), cown_(cown), err_(false) {} /** perform the concrete process */ void run() { if (!mr_->logf("map", "started to flushing the cache: count=%lld size=%lld", (long long)cache_->count(), (long long)csiz_)) err_ = true; double stime = kc::time(); kc::BasicDB* tmpdb = tmpdb_; kc::TinyHashMap* cache = cache_; bool cown = cown_; kc::TinyHashMap::Sorter sorter(cache); const char* kbuf, *vbuf; size_t ksiz, vsiz; while ((kbuf = sorter.get(&ksiz, &vbuf, &vsiz)) != NULL) { if (!tmpdb->append(kbuf, ksiz, vbuf, vsiz)) { const kc::BasicDB::Error& e = tmpdb->error(); mr_->db_->set_error(e.code(), e.message()); err_ = true; } sorter.step(); if (cown) cache->remove(kbuf, ksiz); } double etime = kc::time(); if (!mr_->logf("map", "flushing the cache finished: time=%.6f", etime - stime)) err_ = true; if (cown) delete cache; } /** check the error flag. */ bool error() { return err_; } private: MapReduce* mr_; ///< driver kc::BasicDB* tmpdb_; ///< temprary database kc::TinyHashMap* cache_; ///< cache for emitter size_t csiz_; ///< current cache size bool cown_; ///< cache ownership flag bool err_; ///< error flag }; /** * Task queue for parallel reducer. */ class ReduceTaskQueue : public kc::TaskQueue { public: /** * Task for parallel reducer. */ class ReduceTask : public Task { friend class ReduceTaskQueue; public: /** constructor */ explicit ReduceTask(MapReduce* mr, const char* kbuf, size_t ksiz, const Values& values) : mr_(mr), key_(kbuf, ksiz), values_(values) {} private: MapReduce* mr_; ///< driver std::string key_; ///< key Values values_; ///< values }; /** constructor */ explicit ReduceTaskQueue() {} private: /** process a task */ void do_task(Task* task) { ReduceTask* rtask = (ReduceTask*)task; ValueIterator iter(rtask->values_.begin(), rtask->values_.end()); if (!rtask->mr_->reduce(rtask->key_.data(), rtask->key_.size(), &iter)) rtask->mr_->redaborted_ = true; delete rtask; } }; /** * Checker for the map process. */ class MapChecker : public kc::BasicDB::ProgressChecker { public: /** constructor */ explicit MapChecker() : stop_(false) {} /** stop the process */ void stop() { stop_ = true; } /** check whether stopped */ bool stopped() { return stop_; } private: /** check whether stopped */ bool check(const char* name, const char* message, int64_t curcnt, int64_t allcnt) { return !stop_; } bool stop_; ///< flag for stop }; /** * Visitor for the map process. */ class MapVisitor : public TimedDB::Visitor { public: /** constructor */ explicit MapVisitor(MapReduce* mr, MapChecker* checker, int64_t scale) : mr_(mr), checker_(checker), scale_(scale), stime_(0), err_(false) {} /** get the error flag */ bool error() { return err_; } /** preprocess the mappter */ void visit_before() { mr_->dbclock_ = 0; mr_->cache_ = new kc::TinyHashMap(mr_->cbnum_); mr_->csiz_ = 0; if (!mr_->preprocess()) err_ = true; if (mr_->cache_->count() > 0 && !mr_->flush_cache()) err_ = true; if (!mr_->logf("map", "started the map process: scale=%lld", (long long)scale_)) err_ = true; stime_ = kc::time(); } /** postprocess the mappter and call the reducer */ void visit_after() { if (mr_->cache_->count() > 0 && !mr_->flush_cache()) err_ = true; double etime = kc::time(); if (!mr_->logf("map", "the map process finished: time=%.6f", etime - stime_)) err_ = true; if (!mr_->midprocess()) err_ = true; if (mr_->cache_->count() > 0 && !mr_->flush_cache()) err_ = true; delete mr_->cache_; if (mr_->flsths_ && !mr_->flsths_->empty()) { std::deque::iterator flthit = mr_->flsths_->begin(); std::deque::iterator flthitend = mr_->flsths_->end(); while (flthit != flthitend) { FlushThread* flth = *flthit; flth->join(); if (flth->error()) err_ = true; delete flth; ++flthit; } } if (!err_ && !mr_->execute_reduce()) err_ = true; if (!mr_->postprocess()) err_ = true; } private: /** visit a record */ const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { if (!mr_->map(kbuf, ksiz, vbuf, vsiz)) { checker_->stop(); err_ = true; } if (mr_->rlocks_) { if (mr_->csiz_ >= mr_->clim_) { mr_->rlocks_->lock_all(); if (mr_->csiz_ >= mr_->clim_ && !mr_->flush_cache()) { checker_->stop(); err_ = true; } mr_->rlocks_->unlock_all(); } } else { if (mr_->csiz_ >= mr_->clim_ && !mr_->flush_cache()) { checker_->stop(); err_ = true; } } return NOP; } MapReduce* mr_; ///< driver MapChecker* checker_; ///< checker int64_t scale_; ///< number of records double stime_; ///< start time bool err_; ///< error flag }; /** * Front line of a merging list. */ struct MergeLine { kc::BasicDB::Cursor* cur; ///< cursor kc::Comparator* rcomp; ///< record comparator char* kbuf; ///< pointer to the key size_t ksiz; ///< size of the key const char* vbuf; ///< pointer to the value size_t vsiz; ///< size of the value /** comparing operator */ bool operator <(const MergeLine& right) const { return rcomp->compare(kbuf, ksiz, right.kbuf, right.ksiz) > 0; } }; /** * Process a log message. * @param name the name of the event. * @param format the printf-like format string. * @param ... used according to the format string. * @return true on success, or false on failure. */ bool logf(const char* name, const char* format, ...) { _assert_(name && format); va_list ap; va_start(ap, format); std::string message; kc::vstrprintf(&message, format, ap); va_end(ap); return log(name, message.c_str()); } /** * Flush all cache records. * @return true on success, or false on failure. */ bool flush_cache() { _assert_(true); bool err = false; kc::BasicDB* tmpdb = tmpdbs_[dbclock_]; dbclock_ = (dbclock_ + 1) % dbnum_; if (flsths_) { size_t num = flsths_->size(); if (num >= flsthnum_ || num >= dbnum_) { FlushThread* flth = flsths_->front(); flsths_->pop_front(); flth->join(); if (flth->error()) err = true; delete flth; } FlushThread* flth = new FlushThread(this, tmpdb, cache_, csiz_, true); cache_ = new kc::TinyHashMap(cbnum_); csiz_ = 0; flth->start(); flsths_->push_back(flth); } else { FlushThread flth(this, tmpdb, cache_, csiz_, false); flth.run(); if (flth.error()) err = true; cache_->clear(); csiz_ = 0; } return !err; } /** * Execute the reduce part. * @return true on success, or false on failure. */ bool execute_reduce() { bool err = false; int64_t scale = 0; for (size_t i = 0; i < dbnum_; i++) { scale += tmpdbs_[i]->count(); } if (!logf("reduce", "started the reduce process: scale=%lld", (long long)scale)) err = true; double stime = kc::time(); if (redtasks_) redtasks_->start(redthnum_); std::priority_queue lines; for (size_t i = 0; i < dbnum_; i++) { MergeLine line; line.cur = tmpdbs_[i]->cursor(); line.rcomp = rcomp_; line.cur->jump(); line.kbuf = line.cur->get(&line.ksiz, &line.vbuf, &line.vsiz, true); if (line.kbuf) { lines.push(line); } else { delete line.cur; } } char* lkbuf = NULL; size_t lksiz = 0; Values values; while (!err && !lines.empty()) { MergeLine line = lines.top(); lines.pop(); if (lkbuf && (lksiz != line.ksiz || std::memcmp(lkbuf, line.kbuf, lksiz))) { if (!call_reducer(lkbuf, lksiz, values)) err = true; values.clear(); } values.push_back(std::string(line.vbuf, line.vsiz)); delete[] lkbuf; lkbuf = line.kbuf; lksiz = line.ksiz; line.kbuf = line.cur->get(&line.ksiz, &line.vbuf, &line.vsiz, true); if (line.kbuf) { lines.push(line); } else { delete line.cur; } } if (lkbuf) { if (!err && !call_reducer(lkbuf, lksiz, values)) err = true; values.clear(); delete[] lkbuf; } while (!lines.empty()) { MergeLine line = lines.top(); lines.pop(); delete[] line.kbuf; delete line.cur; } if (redtasks_) redtasks_->finish(); double etime = kc::time(); if (!logf("reduce", "the reduce process finished: time=%.6f", etime - stime)) err = true; return !err; } /** * Call the reducer. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param values a vector of the values. * @return true on success, or false on failure. */ bool call_reducer(const char* kbuf, size_t ksiz, const Values& values) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); if (redtasks_) { if (redaborted_) return false; ReduceTaskQueue::ReduceTask* task = new ReduceTaskQueue::ReduceTask(this, kbuf, ksiz, values); redtasks_->add_task(task); return true; } bool err = false; ValueIterator iter(values.begin(), values.end()); if (!reduce(kbuf, ksiz, &iter)) err = true; return !err; } /** Dummy constructor to forbid the use. */ MapReduce(const MapReduce&); /** Dummy Operator to forbid the use. */ MapReduce& operator =(const MapReduce&); /** The internal database. */ TimedDB* db_; /** The record comparator. */ kc::Comparator* rcomp_; /** The temporary databases. */ kc::BasicDB** tmpdbs_; /** The number of temporary databases. */ size_t dbnum_; /** The logical clock for temporary databases. */ int64_t dbclock_; /** The number of the mapper threads. */ size_t mapthnum_; /** The number of the reducer threads. */ size_t redthnum_; /** The number of the flusher threads. */ size_t flsthnum_; /** The cache for emitter. */ kc::TinyHashMap* cache_; /** The current size of the cache for emitter. */ int64_t csiz_; /** The limit size of the cache for emitter. */ int64_t clim_; /** The bucket number of the cache for emitter. */ int64_t cbnum_; /** The flush threads. */ std::deque* flsths_; /** The task queue for parallel reducer. */ kc::TaskQueue* redtasks_; /** The flag whether aborted. */ bool redaborted_; /** The whole lock. */ kc::SlottedMutex* rlocks_; }; } // common namespace #endif // duplication check // END OF FILE kyototycoon-0.9.56/ktserver.cc0000644000175000017500000034333311757471602015415 0ustar mikiomikio/************************************************************************************************* * A handy cache/storage server * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "cmdcommon.h" enum { // enumeration for operation counting CNTSET, // setting operations CNTSETMISS, // misses of setting operations CNTREMOVE, // removing operations CNTREMOVEMISS, // misses of removing operations CNTGET, // getting operations CNTGETMISS, // misses of getting operations CNTSCRIPT, // scripting operations CNTMISC // miscellaneous operations }; typedef uint64_t OpCount[CNTMISC+1]; // counters per thread // global variables const char* g_progname; // program name int32_t g_procid; // process ID number double g_starttime; // start time bool g_daemon; // daemon flag kt::RPCServer* g_serv; // running RPC server bool g_restart; // restart flag // function prototypes int main(int argc, char** argv); static void usage(); static void killserver(int signum); static int32_t run(int argc, char** argv); static int32_t proc(const std::vector& dbpaths, const char* host, int32_t port, double tout, int32_t thnum, const char* logpath, uint32_t logkinds, const char* ulogpath, int64_t ulim, double uasi, int32_t sid, int32_t omode, double asi, bool ash, const char* bgspath, double bgsi, kc::Compressor* bgscomp, bool dmn, const char* pidpath, const char* cmdpath, const char* scrpath, const char* mhost, int32_t mport, const char* rtspath, double riv, const char* plsvpath, const char* plsvex, const char* pldbpath); static bool dosnapshot(const char* bgspath, kc::Compressor* bgscomp, kt::TimedDB* dbs, int32_t dbnum, kt::RPCServer* serv); // logger implementation class Logger : public kt::RPCServer::Logger { public: // constructor explicit Logger() : strm_(NULL), lock_() {} // destructor ~Logger() { if (strm_) close(); } // open the stream bool open(const char* path) { if (strm_) return false; if (path && *path != '\0' && std::strcmp(path, "-")) { std::ofstream* strm = new std::ofstream; strm->open(path, std::ios_base::out | std::ios_base::binary | std::ios_base::app); if (!*strm) { delete strm; return false; } strm_ = strm; } else { strm_ = &std::cout; } return true; } // close the stream void close() { if (!strm_) return; if (strm_ != &std::cout) delete strm_; strm_ = NULL; } // process a log message. void log(Kind kind, const char* message) { if (!strm_) return; char date[48]; kt::datestrwww(kc::nan(), kc::INT32MAX, 6, date); const char* kstr = "MISC"; switch (kind) { case kt::RPCServer::Logger::DEBUG: kstr = "DEBUG"; break; case kt::RPCServer::Logger::INFO: kstr = "INFO"; break; case kt::RPCServer::Logger::SYSTEM: kstr = "SYSTEM"; break; case kt::RPCServer::Logger::ERROR: kstr = "ERROR"; break; } lock_.lock(); *strm_ << date << ": [" << kstr << "]: " << message << "\n"; strm_->flush(); lock_.unlock(); } private: std::ostream* strm_; kc::Mutex lock_; }; // database logger implementation class DBLogger : public kc::BasicDB::Logger { public: // constructor explicit DBLogger(::Logger* logger, uint32_t kinds) : logger_(logger), kinds_(kinds) {} // process a log message. void log(const char* file, int32_t line, const char* func, kc::BasicDB::Logger::Kind kind, const char* message) { kt::RPCServer::Logger::Kind rkind; switch (kind) { default: rkind = kt::RPCServer::Logger::DEBUG; break; case kc::BasicDB::Logger::INFO: rkind = kt::RPCServer::Logger::INFO; break; case kc::BasicDB::Logger::WARN: rkind = kt::RPCServer::Logger::SYSTEM; break; case kc::BasicDB::Logger::ERROR: rkind = kt::RPCServer::Logger::ERROR; break; } if (!(rkind & kinds_)) return; std::string lmsg; kc::strprintf(&lmsg, "[DB]: %s", message); logger_->log(rkind, lmsg.c_str()); } private: ::Logger* logger_; uint32_t kinds_; }; // replication slave implemantation class Slave : public kc::Thread { friend class Worker; public: // constructor explicit Slave(uint16_t sid, const char* rtspath, const char* host, int32_t port, double riv, kt::RPCServer* serv, kt::TimedDB* dbs, int32_t dbnum, kt::UpdateLogger* ulog, DBUpdateLogger* ulogdbs) : lock_(), sid_(sid), rtspath_(rtspath), host_(""), port_(port), riv_(riv), serv_(serv), dbs_(dbs), dbnum_(dbnum), ulog_(ulog), ulogdbs_(ulogdbs), wrts_(kc::UINT64MAX), rts_(0), alive_(true), hup_(false) { if (host) host_ = host; } // stop the slave void stop() { alive_ = false; } // restart the slave void restart() { hup_ = true; } // set the configuration of the master void set_master(const std::string& host, int32_t port, uint64_t ts, double iv) { kc::ScopedSpinLock lock(&lock_); host_ = host; port_ = port; wrts_ = ts; if (iv >= 0) riv_ = iv; } // get the host name of the master std::string host() { kc::ScopedSpinLock lock(&lock_); return host_; } // get the port number name of the master int32_t port() { kc::ScopedSpinLock lock(&lock_); return port_; } // get the replication time stamp uint64_t rts() { return rts_; } // get the replication interval double riv() { return riv_; } private: static const int32_t DUMMYFREQ = 256; static const size_t RTSFILESIZ = 21; // perform replication void run(void) { if (!rtspath_) return; kc::File rtsfile; if (!rtsfile.open(rtspath_, kc::File::OWRITER | kc::File::OCREATE, kc::NUMBUFSIZ) || !rtsfile.truncate(RTSFILESIZ)) { serv_->log(Logger::ERROR, "opening the RTS file failed: path=%s", rtspath_); return; } rts_ = read_rts(&rtsfile); write_rts(&rtsfile, rts_); kc::Thread::sleep(0.2); bool deferred = false; while (true) { lock_.lock(); std::string host = host_; int32_t port = port_; uint64_t wrts = wrts_; lock_.unlock(); if (!host.empty()) { if (wrts != kc::UINT64MAX) { lock_.lock(); wrts_ = kc::UINT64MAX; rts_ = wrts; write_rts(&rtsfile, rts_); lock_.unlock(); } kt::ReplicationClient rc; if (rc.open(host, port, 60, rts_, sid_)) { serv_->log(Logger::SYSTEM, "replication started: host=%s port=%d rts=%llu", host.c_str(), port, (unsigned long long)rts_); hup_ = false; double rivsum = 0; while (alive_ && !hup_ && rc.alive()) { size_t msiz; uint64_t mts; char* mbuf = rc.read(&msiz, &mts); if (mbuf) { if (msiz > 0) { size_t rsiz; uint16_t rsid, rdbid; const char* rbuf = DBUpdateLogger::parse(mbuf, msiz, &rsiz, &rsid, &rdbid); if (rbuf && rsid != sid_ && rdbid < dbnum_) { kt::TimedDB* db = dbs_ + rdbid; DBUpdateLogger* ulogdb = ulogdbs_ ? ulogdbs_ + rdbid : NULL; if (ulogdb) ulogdb->set_rsid(rsid); if (!db->recover(rbuf, rsiz)) { const kc::BasicDB::Error& e = db->error(); serv_->log(Logger::ERROR, "recovering a database failed: %s: %s", e.name(), e.message()); } if (ulogdb) ulogdb->clear_rsid(); } rivsum += riv_; } else { rivsum += riv_ * DUMMYFREQ / 4; } delete[] mbuf; while (rivsum > 100 && alive_ && !hup_ && rc.alive()) { kc::Thread::sleep(0.1); rivsum -= 100; } } if (mts > rts_) rts_ = mts; } rc.close(); serv_->log(Logger::SYSTEM, "replication finished: host=%s port=%d", host.c_str(), port); write_rts(&rtsfile, rts_); deferred = false; } else { if (!deferred) serv_->log(Logger::SYSTEM, "replication was deferred: host=%s port=%d", host.c_str(), port); deferred = true; } } if (alive_) { kc::Thread::sleep(1); } else { break; } } if (!rtsfile.close()) serv_->log(Logger::ERROR, "closing the RTS file failed"); } // read the replication time stamp uint64_t read_rts(kc::File* file) { char buf[RTSFILESIZ]; file->read_fast(0, buf, RTSFILESIZ); buf[sizeof(buf)-1] = '\0'; return kc::atoi(buf); } // write the replication time stamp void write_rts(kc::File* file, uint64_t rts) { char buf[kc::NUMBUFSIZ]; std::sprintf(buf, "%020llu\n", (unsigned long long)rts); if (!file->write_fast(0, buf, RTSFILESIZ)) serv_->log(Logger::SYSTEM, "writing the time stamp failed"); } kc::SpinLock lock_; const uint16_t sid_; const char* const rtspath_; std::string host_; int32_t port_; double riv_; kt::RPCServer* const serv_; kt::TimedDB* const dbs_; const int32_t dbnum_; kt::UpdateLogger* const ulog_; DBUpdateLogger* const ulogdbs_; uint64_t wrts_; uint64_t rts_; bool alive_; bool hup_; }; // plug-in server driver class PlugInDriver : public kc::Thread { public: // constructor explicit PlugInDriver(kt::PluggableServer* serv) : serv_(serv), error_(false) {} // get the error flag bool error() { return error_; } private: // perform service void run(void) { kc::Thread::sleep(0.4); if (serv_->start()) { if (!serv_->finish()) error_ = true; } else { error_ = true; } } kt::PluggableServer* serv_; bool error_; }; // worker implementation class Worker : public kt::RPCServer::Worker { private: class SLS; typedef kt::RPCClient::ReturnValue RV; public: // constructor explicit Worker(int32_t thnum, kc::CondMap* condmap, kt::TimedDB* dbs, int32_t dbnum, const std::map& dbmap, int32_t omode, double asi, bool ash, const char* bgspath, double bgsi, kc::Compressor* bgscomp, kt::UpdateLogger* ulog, DBUpdateLogger* ulogdbs, const char* cmdpath, ScriptProcessor* scrprocs, OpCount* opcounts) : thnum_(thnum), condmap_(condmap), dbs_(dbs), dbnum_(dbnum), dbmap_(dbmap), omode_(omode), asi_(asi), ash_(ash), bgspath_(bgspath), bgsi_(bgsi), bgscomp_(bgscomp), ulog_(ulog), ulogdbs_(ulogdbs), cmdpath_(cmdpath), scrprocs_(scrprocs), opcounts_(opcounts), idlecnt_(0), asnext_(0), bgsnext_(0), slave_(NULL) { asnext_ = kc::time() + asi_; bgsnext_ = kc::time() + bgsi_; } // set miscellaneous configuration void set_misc_conf(Slave* slave) { slave_ = slave; } private: // process each request of RPC. RV process(kt::RPCServer* serv, kt::RPCServer::Session* sess, const std::string& name, const std::map& inmap, std::map& outmap) { size_t rsiz; const char* rp = kt::strmapget(inmap, "WAIT", &rsiz); if (rp) { std::string condname(rp, rsiz); rp = kt::strmapget(inmap, "WAITTIME"); double wsec = rp ? kc::atof(rp) : 0.0; if (wsec <= 0) wsec = DEFTOUT; kt::ThreadedServer* thserv = serv->reveal_core()->reveal_core(); if (!condmap_->wait(condname, wsec) || thserv->aborted()) { set_message(outmap, "ERROR", "the condition timed out"); return kt::RPCClient::RVETIMEOUT; } } int32_t dbidx = 0; rp = kt::strmapget(inmap, "DB"); if (rp && *rp != '\0') { dbidx = -1; if (*rp >= '0' && *rp <= '9') { dbidx = kc::atoi(rp); } else { std::map::const_iterator it = dbmap_.find(rp); if (it != dbmap_.end()) dbidx = it->second; } } kt::TimedDB* db = dbidx >= 0 && dbidx < dbnum_ ? dbs_ + dbidx : NULL; int64_t curid = -1; rp = kt::strmapget(inmap, "CUR"); if (rp && *rp >= '0' && *rp <= '9') curid = kc::atoi(rp); kt::TimedDB::Cursor* cur = NULL; if (curid >= 0) { SLS* sls = SLS::create(sess); std::map::iterator it = sls->curs_.find(curid); if (it == sls->curs_.end()) { if (db) { cur = db->cursor(); sls->curs_[curid] = cur; } } else { cur = it->second; if (name == "cur_delete") { sls->curs_.erase(curid); delete cur; return kt::RPCClient::RVSUCCESS; } } } RV rv; if (name == "void") { rv = do_void(serv, sess, inmap, outmap); } else if (name == "echo") { rv = do_echo(serv, sess, inmap, outmap); } else if (name == "report") { rv = do_report(serv, sess, inmap, outmap); } else if (name == "play_script") { rv = do_play_script(serv, sess, inmap, outmap); } else if (name == "tune_replication") { rv = do_tune_replication(serv, sess, inmap, outmap); } else if (name == "ulog_list") { rv = do_ulog_list(serv, sess, inmap, outmap); } else if (name == "ulog_remove") { rv = do_ulog_remove(serv, sess, inmap, outmap); } else if (name == "status") { rv = do_status(serv, sess, db, inmap, outmap); } else if (name == "clear") { rv = do_clear(serv, sess, db, inmap, outmap); } else if (name == "synchronize") { rv = do_synchronize(serv, sess, db, inmap, outmap); } else if (name == "set") { rv = do_set(serv, sess, db, inmap, outmap); } else if (name == "add") { rv = do_add(serv, sess, db, inmap, outmap); } else if (name == "replace") { rv = do_replace(serv, sess, db, inmap, outmap); } else if (name == "append") { rv = do_append(serv, sess, db, inmap, outmap); } else if (name == "increment") { rv = do_increment(serv, sess, db, inmap, outmap); } else if (name == "increment_double") { rv = do_increment_double(serv, sess, db, inmap, outmap); } else if (name == "cas") { rv = do_cas(serv, sess, db, inmap, outmap); } else if (name == "remove") { rv = do_remove(serv, sess, db, inmap, outmap); } else if (name == "get") { rv = do_get(serv, sess, db, inmap, outmap); } else if (name == "check") { rv = do_check(serv, sess, db, inmap, outmap); } else if (name == "seize") { rv = do_seize(serv, sess, db, inmap, outmap); } else if (name == "set_bulk") { rv = do_set_bulk(serv, sess, db, inmap, outmap); } else if (name == "remove_bulk") { rv = do_remove_bulk(serv, sess, db, inmap, outmap); } else if (name == "get_bulk") { rv = do_get_bulk(serv, sess, db, inmap, outmap); } else if (name == "vacuum") { rv = do_vacuum(serv, sess, db, inmap, outmap); } else if (name == "match_prefix") { rv = do_match_prefix(serv, sess, db, inmap, outmap); } else if (name == "match_regex") { rv = do_match_regex(serv, sess, db, inmap, outmap); } else if (name == "match_similar") { rv = do_match_similar(serv, sess, db, inmap, outmap); } else if (name == "cur_jump") { rv = do_cur_jump(serv, sess, cur, inmap, outmap); } else if (name == "cur_jump_back") { rv = do_cur_jump_back(serv, sess, cur, inmap, outmap); } else if (name == "cur_step") { rv = do_cur_step(serv, sess, cur, inmap, outmap); } else if (name == "cur_step_back") { rv = do_cur_step_back(serv, sess, cur, inmap, outmap); } else if (name == "cur_set_value") { rv = do_cur_set_value(serv, sess, cur, inmap, outmap); } else if (name == "cur_remove") { rv = do_cur_remove(serv, sess, cur, inmap, outmap); } else if (name == "cur_get_key") { rv = do_cur_get_key(serv, sess, cur, inmap, outmap); } else if (name == "cur_get_value") { rv = do_cur_get_value(serv, sess, cur, inmap, outmap); } else if (name == "cur_get") { rv = do_cur_get(serv, sess, cur, inmap, outmap); } else if (name == "cur_seize") { rv = do_cur_seize(serv, sess, cur, inmap, outmap); } else { set_message(outmap, "ERROR", "not implemented: %s", name.c_str()); rv = kt::RPCClient::RVENOIMPL; } rp = kt::strmapget(inmap, "SIGNAL", &rsiz); if (rp) { std::string condname(rp, rsiz); rp = kt::strmapget(inmap, "SIGNALBROAD"); bool broad = rp ? true : false; size_t wnum = broad ? condmap_->broadcast(condname) : condmap_->signal(condname); set_message(outmap, "SIGNALED", "%lld", (long long)wnum); } return rv; } // process each request of the others. int32_t process(kt::HTTPServer* serv, kt::HTTPServer::Session* sess, const std::string& path, kt::HTTPClient::Method method, const std::map& reqheads, const std::string& reqbody, std::map& resheads, std::string& resbody, const std::map& misc) { const char* pstr = path.c_str(); if (*pstr == '/') pstr++; int32_t dbidx = 0; const char* rp = std::strchr(pstr, '/'); if (rp) { std::string dbexpr(pstr, rp - pstr); pstr = rp + 1; if (*pstr == '/') pstr++; size_t desiz; char* destr = kc::urldecode(dbexpr.c_str(), &desiz); if (*destr != '\0') { dbidx = -1; if (*destr >= '0' && *destr <= '9') { dbidx = kc::atoi(destr); } else { std::map::const_iterator it = dbmap_.find(destr); if (it != dbmap_.end()) dbidx = it->second; } } delete[] destr; } if (dbidx < 0 || dbidx >= dbnum_) { resbody.append("no such database\n"); return 400; } kt::TimedDB* db = dbs_ + dbidx; size_t ksiz; char* kbuf = kc::urldecode(pstr, &ksiz); int32_t code; switch (method) { case kt::HTTPClient::MGET: { code = do_rest_get(serv, sess, db, kbuf, ksiz, reqheads, reqbody, resheads, resbody, misc); break; } case kt::HTTPClient::MHEAD: { code = do_rest_head(serv, sess, db, kbuf, ksiz, reqheads, reqbody, resheads, resbody, misc); break; } case kt::HTTPClient::MPUT: { code = do_rest_put(serv, sess, db, kbuf, ksiz, reqheads, reqbody, resheads, resbody, misc); break; } case kt::HTTPClient::MDELETE: { code = do_rest_delete(serv, sess, db, kbuf, ksiz, reqheads, reqbody, resheads, resbody, misc); break; } default: { code = 501; break; } } delete[] kbuf; return code; } // process each binary request bool process_binary(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess) { int32_t magic = sess->receive_byte(); const char* cmd; bool rv; switch (magic) { case kt::RemoteDB::BMREPLICATION: { cmd = "bin_replication"; rv = do_bin_replication(serv, sess); break; } case kt::RemoteDB::BMPLAYSCRIPT: { cmd = "bin_play_script"; rv = do_bin_play_script(serv, sess); break; } case kt::RemoteDB::BMSETBULK: { cmd = "bin_set_bulk"; rv = do_bin_set_bulk(serv, sess); break; } case kt::RemoteDB::BMREMOVEBULK: { cmd = "bin_remove_bulk"; rv = do_bin_remove_bulk(serv, sess); break; } case kt::RemoteDB::BMGETBULK: { cmd = "bin_get_bulk"; rv = do_bin_get_bulk(serv, sess); break; } default: { cmd = "bin_unknown"; rv = false; break; } } std::string expr = sess->expression(); serv->log(kt::ThreadedServer::Logger::INFO, "(%s): %s: %d", expr.c_str(), cmd, rv); return rv; } // process each idle event void process_idle(kt::RPCServer* serv) { if (omode_ & kc::BasicDB::OWRITER) { int32_t dbidx = idlecnt_++ % dbnum_; kt::TimedDB* db = dbs_ + dbidx; kt::ThreadedServer* thserv = serv->reveal_core()->reveal_core(); for (int32_t i = 0; i < 4; i++) { if (thserv->task_count() > 0) break; if (!db->vacuum(2)) { const kc::BasicDB::Error& e = db->error(); log_db_error(serv, e); break; } kc::Thread::yield(); } } } // process each timer event void process_timer(kt::RPCServer* serv) { if (asi_ > 0 && (omode_ & kc::BasicDB::OWRITER) && kc::time() >= asnext_) { serv->log(Logger::INFO, "synchronizing databases"); for (int32_t i = 0; i < dbnum_; i++) { kt::TimedDB* db = dbs_ + i; if (!db->synchronize(ash_)) { const kc::BasicDB::Error& e = db->error(); log_db_error(serv, e); break; } kc::Thread::yield(); } asnext_ = kc::time() + asi_; } if (bgspath_ && bgsi_ > 0 && kc::time() >= bgsnext_) { serv->log(Logger::INFO, "snapshotting databases"); dosnapshot(bgspath_, bgscomp_, dbs_, dbnum_, serv); bgsnext_ = kc::time() + bgsi_; } } // process the starting event void process_start(kt::RPCServer* serv) { kt::maskthreadsignal(); } // set the error message void set_message(std::map& outmap, const char* key, const char* format, ...) { std::string message; va_list ap; va_start(ap, format); kc::vstrprintf(&message, format, ap); va_end(ap); outmap[key] = message; } // set the database error message void set_db_error(std::map& outmap, const kc::BasicDB::Error& e) { set_message(outmap, "ERROR", "DB: %d: %s: %s", e.code(), e.name(), e.message()); } // log the database error message void log_db_error(kt::RPCServer* serv, const kc::BasicDB::Error& e) { log_db_error(serv->reveal_core(), e); } // log the database error message void log_db_error(kt::HTTPServer* serv, const kc::BasicDB::Error& e) { serv->log(Logger::ERROR, "database error: %d: %s: %s", e.code(), e.name(), e.message()); } // process the void procedure RV do_void(kt::RPCServer* serv, kt::RPCServer::Session* sess, const std::map& inmap, std::map& outmap) { return kt::RPCClient::RVSUCCESS; } // process the echo procedure RV do_echo(kt::RPCServer* serv, kt::RPCServer::Session* sess, const std::map& inmap, std::map& outmap) { outmap.insert(inmap.begin(), inmap.end()); return kt::RPCClient::RVSUCCESS; } // process the report procedure RV do_report(kt::RPCServer* serv, kt::RPCServer::Session* sess, const std::map& inmap, std::map& outmap) { int64_t totalcount = 0; int64_t totalsize = 0; for (int32_t i = 0; i < dbnum_; i++) { int64_t count = dbs_[i].count(); int64_t size = dbs_[i].size(); std::string key; kc::strprintf(&key, "db_%d", i); set_message(outmap, key.c_str(), "count=%lld size=%lld path=%s", (long long)count, (long long)size, dbs_[i].path().c_str()); totalcount += count; totalsize += size; } set_message(outmap, "db_total_count", "%lld", (long long)totalcount); set_message(outmap, "db_total_size", "%lld", (long long)totalsize); kt::ThreadedServer* thserv = serv->reveal_core()->reveal_core(); set_message(outmap, "serv_conn_count", "%lld", (long long)thserv->connection_count()); set_message(outmap, "serv_task_count", "%lld", (long long)thserv->task_count()); set_message(outmap, "serv_thread_count", "%lld", (long long)thnum_); double ctime = kc::time(); set_message(outmap, "serv_current_time", "%.6f", ctime); set_message(outmap, "serv_running_term", "%.6f", ctime - g_starttime); set_message(outmap, "serv_proc_id", "%d", g_procid); std::map sysinfo; kc::getsysinfo(&sysinfo); std::map::iterator it = sysinfo.begin(); std::map::iterator itend = sysinfo.end(); while (it != itend) { std::string key; kc::strprintf(&key, "sys_%s", it->first.c_str()); set_message(outmap, key.c_str(), it->second.c_str()); ++it; } const std::string& mhost = slave_->host(); if (!mhost.empty()) { set_message(outmap, "repl_master_host", "%s", mhost.c_str()); set_message(outmap, "repl_master_port", "%d", slave_->port()); uint64_t rts = slave_->rts(); set_message(outmap, "repl_timestamp", "%llu", (unsigned long long)rts); set_message(outmap, "repl_interval", "%.6f", slave_->riv()); uint64_t cc = kt::UpdateLogger::clock_pure(); uint64_t delay = cc > rts ? cc - rts : 0; set_message(outmap, "repl_delay", "%.6f", delay / 1000000000.0); } OpCount ocsum; for (int32_t i = 0; i <= CNTMISC; i++) { ocsum[i] = 0; } for (int32_t i = 0; i < thnum_; i++) { for (int32_t j = 0; j <= CNTMISC; j++) { ocsum[j] += opcounts_[i][j]; } } set_message(outmap, "cnt_set", "%llu", (unsigned long long)ocsum[CNTSET]); set_message(outmap, "cnt_set_misses", "%llu", (unsigned long long)ocsum[CNTSETMISS]); set_message(outmap, "cnt_remove", "%llu", (unsigned long long)ocsum[CNTREMOVE]); set_message(outmap, "cnt_remove_misses", "%llu", (unsigned long long)ocsum[CNTREMOVEMISS]); set_message(outmap, "cnt_get", "%llu", (unsigned long long)ocsum[CNTGET]); set_message(outmap, "cnt_get_misses", "%llu", (unsigned long long)ocsum[CNTGETMISS]); set_message(outmap, "cnt_script", "%llu", (unsigned long long)ocsum[CNTSCRIPT]); set_message(outmap, "cnt_misc", "%llu", (unsigned long long)ocsum[CNTMISC]); set_message(outmap, "conf_kt_version", "%s (%d.%d)", kt::VERSION, kt::LIBVER, kt::LIBREV); set_message(outmap, "conf_kt_features", "%s", kt::FEATURES); set_message(outmap, "conf_kc_version", "%s (%d.%d)", kc::VERSION, kc::LIBVER, kc::LIBREV); set_message(outmap, "conf_kc_features", "%s", kc::FEATURES); set_message(outmap, "conf_os_name", "%s", kc::OSNAME); return kt::RPCClient::RVSUCCESS; } // process the play_script procedure RV do_play_script(kt::RPCServer* serv, kt::RPCServer::Session* sess, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!scrprocs_) { set_message(outmap, "ERROR", "the scripting extention is disabled"); return kt::RPCClient::RVENOIMPL; } ScriptProcessor* scrproc = scrprocs_ + thid; const char* nstr = kt::strmapget(inmap, "name"); if (!nstr || *nstr == '\0' || !kt::strisalnum(nstr)) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } std::map scrinmap; std::map::const_iterator it = inmap.begin(); std::map::const_iterator itend = inmap.end(); while (it != itend) { const char* kbuf = it->first.data(); size_t ksiz = it->first.size(); if (ksiz > 0 && *kbuf == '_') { std::string key(kbuf + 1, ksiz - 1); scrinmap[key] = it->second; } ++it; } opcounts_[thid][CNTSCRIPT]++; std::map scroutmap; RV rv = scrproc->call(nstr, scrinmap, scroutmap); if (rv == kt::RPCClient::RVSUCCESS) { it = scroutmap.begin(); itend = scroutmap.end(); while (it != itend) { std::string key = "_"; key.append(it->first); outmap[key] = it->second; ++it; } } else if (rv == kt::RPCClient::RVENOIMPL) { set_message(outmap, "ERROR", "no such scripting procedure"); } else { set_message(outmap, "ERROR", "the scripting procedure failed"); } return rv; } // process the tune_replication procedure RV do_tune_replication(kt::RPCServer* serv, kt::RPCServer::Session* sess, const std::map& inmap, std::map& outmap) { if (!slave_->rtspath_) { set_message(outmap, "ERROR", "the RTS file is not set"); return kt::RPCClient::RVENOIMPL; } const char* host = kt::strmapget(inmap, "host"); if (!host) host = ""; const char* rp = kt::strmapget(inmap, "port"); int32_t port = rp ? kc::atoi(rp) : 0; if (port < 1) port = kt::DEFPORT; rp = kt::strmapget(inmap, "ts"); uint64_t ts = kc::UINT64MAX; if (rp) { if (!std::strcmp(rp, "now")) { ts = kt::UpdateLogger::clock_pure(); } else { ts = kc::atoi(rp); } } rp = kt::strmapget(inmap, "iv"); double iv = rp ? kc::atof(rp) : -1; char tsstr[kc::NUMBUFSIZ]; if (ts == kc::UINT64MAX) { std::sprintf(tsstr, "*"); } else { std::sprintf(tsstr, "%llu", (unsigned long long)ts); } char ivstr[kc::NUMBUFSIZ]; if (iv < 0) { std::sprintf(ivstr, "*"); } else { std::sprintf(ivstr, "%.6f", iv); } serv->log(Logger::SYSTEM, "replication setting was modified: host=%s port=%d ts=%s iv=%s", host, port, tsstr, ivstr); slave_->set_master(host, port, ts, iv); slave_->restart(); return kt::RPCClient::RVSUCCESS; } // process the ulog_list procedure RV do_ulog_list(kt::RPCServer* serv, kt::RPCServer::Session* sess, const std::map& inmap, std::map& outmap) { if (!ulog_) { set_message(outmap, "ERROR", "no update log allows no replication"); return kt::RPCClient::RVEINVALID; } std::vector files; ulog_->list_files(&files); std::vector::iterator it = files.begin(); std::vector::iterator itend = files.end(); while (it != itend) { set_message(outmap, it->path.c_str(), "%llu:%llu", (unsigned long long)it->size, (unsigned long long)it->ts); ++it; } return kt::RPCClient::RVSUCCESS; } // process the ulog_remove procedure RV do_ulog_remove(kt::RPCServer* serv, kt::RPCServer::Session* sess, const std::map& inmap, std::map& outmap) { if (!ulog_) { set_message(outmap, "ERROR", "no update log allows no replication"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "ts"); uint64_t ts = kc::UINT64MAX; if (rp) { if (!std::strcmp(rp, "now")) { ts = kt::UpdateLogger::clock_pure(); } else { ts = kc::atoi(rp); } } bool err = false; std::vector files; ulog_->list_files(&files); std::vector::iterator it = files.begin(); std::vector::iterator itend = files.end(); if (it != itend) itend--; while (it != itend) { if (it->ts <= ts && !kc::File::remove(it->path)) { set_message(outmap, "ERROR", "removing a file failed: %s", it->path.c_str()); serv->log(Logger::ERROR, "removing a file failed: %s", it->path.c_str()); err = true; } ++it; } return err ? kt::RPCClient::RVEINTERNAL : kt::RPCClient::RVSUCCESS; } // process the status procedure RV do_status(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTMISC]++; std::map status; if (db->status(&status)) { rv = kt::RPCClient::RVSUCCESS; outmap.insert(status.begin(), status.end()); } else { const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the clear procedure RV do_clear(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTMISC]++; if (db->clear()) { rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the synchronize procedure RV do_synchronize(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "hard"); bool hard = rp ? true : false; rp = kt::strmapget(inmap, "command"); std::string command = rp ? rp : ""; class Visitor : public kc::BasicDB::FileProcessor { public: Visitor(kt::RPCServer* serv, Worker* worker, const std::string& command) : serv_(serv), worker_(worker), command_(command) {} private: bool process(const std::string& path, int64_t count, int64_t size) { if (command_.size() < 1) return true; const char* cmd = command_.c_str(); if (std::strchr(cmd, kc::File::PATHCHR) || !std::strcmp(cmd, kc::File::CDIRSTR) || !std::strcmp(cmd, kc::File::PDIRSTR)) { serv_->log(Logger::INFO, "invalid command name: %s", cmd); return false; } std::string cmdpath; kc::strprintf(&cmdpath, "%s%c%s", worker_->cmdpath_, kc::File::PATHCHR, cmd); std::vector args; args.push_back(cmdpath); args.push_back(path); std::string tsstr; uint64_t cc = worker_->ulog_ ? worker_->ulog_->clock() : kt::UpdateLogger::clock_pure(); if (!worker_->slave_->host().empty()) { uint64_t rts = worker_->slave_->rts(); if (rts < cc) cc = rts; } kc::strprintf(&tsstr, "%020llu", (unsigned long long)cc); args.push_back(tsstr); serv_->log(Logger::SYSTEM, "executing: %s \"%s\"", cmd, path.c_str()); if (kt::executecommand(args) != 0) { serv_->log(Logger::ERROR, "execution failed: %s \"%s\"", cmd, path.c_str()); return false; } return true; } kt::RPCServer* serv_; Worker* worker_; std::string command_; }; Visitor visitor(serv, this, command); RV rv; opcounts_[thid][CNTMISC]++; if (db->synchronize(hard, &visitor)) { rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the set procedure RV do_set(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); size_t vsiz; const char* vbuf = kt::strmapget(inmap, "value", &vsiz); if (!kbuf || !vbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; RV rv; opcounts_[thid][CNTSET]++; if (db->set(kbuf, ksiz, vbuf, vsiz, xt)) { rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the add procedure RV do_add(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); size_t vsiz; const char* vbuf = kt::strmapget(inmap, "value", &vsiz); if (!kbuf || !vbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; RV rv; opcounts_[thid][CNTSET]++; if (db->add(kbuf, ksiz, vbuf, vsiz, xt)) { rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::DUPREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the replace procedure RV do_replace(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); size_t vsiz; const char* vbuf = kt::strmapget(inmap, "value", &vsiz); if (!kbuf || !vbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; RV rv; opcounts_[thid][CNTSET]++; if (db->replace(kbuf, ksiz, vbuf, vsiz, xt)) { rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the append procedure RV do_append(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); size_t vsiz; const char* vbuf = kt::strmapget(inmap, "value", &vsiz); if (!kbuf || !vbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; RV rv; opcounts_[thid][CNTSET]++; if (db->append(kbuf, ksiz, vbuf, vsiz, xt)) { rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the increment procedure RV do_increment(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); const char* nstr = kt::strmapget(inmap, "num"); if (!kbuf || !nstr) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } int64_t num = kc::atoi(nstr); const char* rp = kt::strmapget(inmap, "orig"); int64_t orig; if (rp) { if (!std::strcmp(rp, "try")) { orig = kc::INT64MIN; } else if (!std::strcmp(rp, "set")) { orig = kc::INT64MAX; } else { orig = kc::atoi(rp); } } else { orig = 0; } rp = kt::strmapget(inmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; RV rv; opcounts_[thid][CNTSET]++; num = db->increment(kbuf, ksiz, num, orig, xt); if (num != kc::INT64MIN) { rv = kt::RPCClient::RVSUCCESS; set_message(outmap, "num", "%lld", (long long)num); } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::LOGIC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the increment_double procedure RV do_increment_double(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); const char* nstr = kt::strmapget(inmap, "num"); if (!kbuf || !nstr) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } double num = kc::atof(nstr); const char* rp = kt::strmapget(inmap, "orig"); double orig; if (rp) { if (!std::strcmp(rp, "try")) { orig = -kc::inf(); } else if (!std::strcmp(rp, "set")) { orig = kc::inf(); } else { orig = kc::atof(rp); } } else { orig = 0; } rp = kt::strmapget(inmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; RV rv; opcounts_[thid][CNTSET]++; num = db->increment_double(kbuf, ksiz, num, orig, xt); if (!kc::chknan(num)) { rv = kt::RPCClient::RVSUCCESS; set_message(outmap, "num", "%f", num); } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::LOGIC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the cas procedure RV do_cas(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); if (!kbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } size_t ovsiz; const char* ovbuf = kt::strmapget(inmap, "oval", &ovsiz); size_t nvsiz; const char* nvbuf = kt::strmapget(inmap, "nval", &nvsiz); const char* rp = kt::strmapget(inmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; RV rv; opcounts_[thid][CNTSET]++; if (db->cas(kbuf, ksiz, ovbuf, ovsiz, nvbuf, nvsiz, xt)) { rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::LOGIC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the remove procedure RV do_remove(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); if (!kbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTREMOVE]++; if (db->remove(kbuf, ksiz)) { rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTREMOVEMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the get procedure RV do_get(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); if (!kbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTGET]++; size_t vsiz; int64_t xt; const char* vbuf = db->get(kbuf, ksiz, &vsiz, &xt); if (vbuf) { outmap["value"] = std::string(vbuf, vsiz); if (xt < kt::TimedDB::XTMAX) set_message(outmap, "xt", "%lld", (long long)xt); delete[] vbuf; rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTGETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the check procedure RV do_check(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); if (!kbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTGET]++; int64_t xt; int32_t vsiz = db->check(kbuf, ksiz, &xt); if (vsiz >= 0) { set_message(outmap, "vsiz", "%lld", (long long)vsiz); if (xt < kt::TimedDB::XTMAX) set_message(outmap, "xt", "%lld", (long long)xt); rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTGETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the seize procedure RV do_seize(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); if (!kbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTREMOVE]++; opcounts_[thid][CNTGET]++; size_t vsiz; int64_t xt; const char* vbuf = db->seize(kbuf, ksiz, &vsiz, &xt); if (vbuf) { outmap["value"] = std::string(vbuf, vsiz); if (xt < kt::TimedDB::XTMAX) set_message(outmap, "xt", "%lld", (long long)xt); delete[] vbuf; rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTREMOVEMISS]++; opcounts_[thid][CNTGETMISS]++; const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the set_bulk procedure RV do_set_bulk(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; rp = kt::strmapget(inmap, "atomic"); bool atomic = rp ? true : false; std::map recs; std::map::const_iterator it = inmap.begin(); std::map::const_iterator itend = inmap.end(); while (it != itend) { const char* kbuf = it->first.data(); size_t ksiz = it->first.size(); if (ksiz > 0 && *kbuf == '_') { std::string key(kbuf + 1, ksiz - 1); std::string value(it->second.data(), it->second.size()); recs[key] = value; } ++it; } RV rv; opcounts_[thid][CNTSET] += recs.size(); int64_t num = db->set_bulk(recs, xt, atomic); if (num >= 0) { opcounts_[thid][CNTSETMISS] += recs.size() - (size_t)num; rv = kt::RPCClient::RVSUCCESS; set_message(outmap, "num", "%lld", (long long)num); } else { opcounts_[thid][CNTSETMISS] += recs.size(); const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the remove_bulk procedure RV do_remove_bulk(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "atomic"); bool atomic = rp ? true : false; std::vector keys; keys.reserve(inmap.size()); std::map::const_iterator it = inmap.begin(); std::map::const_iterator itend = inmap.end(); while (it != itend) { const char* kbuf = it->first.data(); size_t ksiz = it->first.size(); if (ksiz > 0 && *kbuf == '_') { std::string key(kbuf + 1, ksiz - 1); keys.push_back(key); } ++it; } RV rv; opcounts_[thid][CNTREMOVE] += keys.size(); int64_t num = db->remove_bulk(keys, atomic); if (num >= 0) { opcounts_[thid][CNTREMOVEMISS] += keys.size() - (size_t)num; rv = kt::RPCClient::RVSUCCESS; set_message(outmap, "num", "%lld", (long long)num); } else { opcounts_[thid][CNTREMOVEMISS] += keys.size(); const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the get_bulk procedure RV do_get_bulk(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "atomic"); bool atomic = rp ? true : false; std::vector keys; keys.reserve(inmap.size()); std::map::const_iterator it = inmap.begin(); std::map::const_iterator itend = inmap.end(); while (it != itend) { const char* kbuf = it->first.data(); size_t ksiz = it->first.size(); if (ksiz > 0 && *kbuf == '_') { std::string key(kbuf + 1, ksiz - 1); keys.push_back(key); } ++it; } RV rv; opcounts_[thid][CNTGET] += keys.size(); std::map recs; int64_t num = db->get_bulk(keys, &recs, atomic); if (num >= 0) { opcounts_[thid][CNTGETMISS] += keys.size() - (size_t)num; rv = kt::RPCClient::RVSUCCESS; std::map::iterator it = recs.begin(); std::map::iterator itend = recs.end(); while (it != itend) { std::string key("_"); key.append(it->first); outmap[key] = it->second; ++it; } set_message(outmap, "num", "%lld", (long long)num); } else { opcounts_[thid][CNTGETMISS] += keys.size(); const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the vacuum procedure RV do_vacuum(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "step"); int64_t step = rp ? kc::atoi(rp) : 0; RV rv; opcounts_[thid][CNTMISC]++; if (db->vacuum(step)) { rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the match_prefix procedure RV do_match_prefix(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t psiz; const char* pbuf = kt::strmapget(inmap, "prefix", &psiz); if (!pbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "max"); int64_t max = rp ? kc::atoi(rp) : -1; std::vector keys; RV rv; opcounts_[thid][CNTMISC]++; int64_t num = db->match_prefix(std::string(pbuf, psiz), &keys, max); if (num >= 0) { std::vector::iterator it = keys.begin(); std::vector::iterator itend = keys.end(); int64_t cnt = 0; while (it != itend) { std::string key = "_"; key.append(*it); outmap[key] = kc::strprintf("%lld", (long long)cnt); ++cnt; ++it; } set_message(outmap, "num", "%lld", (long long)num); rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } return rv; } // process the match_regex procedure RV do_match_regex(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t psiz; const char* pbuf = kt::strmapget(inmap, "regex", &psiz); if (!pbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "max"); int64_t max = rp ? kc::atoi(rp) : -1; std::vector keys; RV rv; opcounts_[thid][CNTMISC]++; int64_t num = db->match_regex(std::string(pbuf, psiz), &keys, max); if (num >= 0) { std::vector::iterator it = keys.begin(); std::vector::iterator itend = keys.end(); int64_t cnt = 0; while (it != itend) { std::string key = "_"; key.append(*it); outmap[key] = kc::strprintf("%lld", (long long)cnt); ++cnt; ++it; } set_message(outmap, "num", "%lld", (long long)num); rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::LOGIC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the match_similar procedure RV do_match_similar(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB* db, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!db) { set_message(outmap, "ERROR", "no such database"); return kt::RPCClient::RVEINVALID; } size_t osiz; const char* obuf = kt::strmapget(inmap, "origin", &osiz); if (!obuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "range"); int64_t range = rp ? kc::atoi(rp) : 1; if (range < 0) range = 1; rp = kt::strmapget(inmap, "utf"); bool utf = rp ? true : false; rp = kt::strmapget(inmap, "max"); int64_t max = rp ? kc::atoi(rp) : -1; std::vector keys; RV rv; opcounts_[thid][CNTMISC]++; int64_t num = db->match_similar(std::string(obuf, osiz), range, utf, &keys, max); if (num >= 0) { std::vector::iterator it = keys.begin(); std::vector::iterator itend = keys.end(); int64_t cnt = 0; while (it != itend) { std::string key = "_"; key.append(*it); outmap[key] = kc::strprintf("%lld", (long long)cnt); ++cnt; ++it; } set_message(outmap, "num", "%lld", (long long)num); rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = db->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::LOGIC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the cur_jump procedure RV do_cur_jump(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); RV rv; opcounts_[thid][CNTMISC]++; if (kbuf) { if (cur->jump(kbuf, ksiz)) { rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } } else { if (cur->jump()) { rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } } return rv; } // process the cur_jump_back procedure RV do_cur_jump_back(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } size_t ksiz; const char* kbuf = kt::strmapget(inmap, "key", &ksiz); RV rv; opcounts_[thid][CNTMISC]++; if (kbuf) { if (cur->jump_back(kbuf, ksiz)) { rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); switch (e.code()) { case kc::BasicDB::Error::NOIMPL: { rv = kt::RPCClient::RVENOIMPL; break; } case kc::BasicDB::Error::NOREC: { rv = kt::RPCClient::RVELOGIC; break; } default: { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; break; } } } } else { if (cur->jump_back()) { rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); switch (e.code()) { case kc::BasicDB::Error::NOIMPL: { rv = kt::RPCClient::RVENOIMPL; break; } case kc::BasicDB::Error::NOREC: { rv = kt::RPCClient::RVELOGIC; break; } default: { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; break; } } } } return rv; } // process the cur_step procedure RV do_cur_step(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTMISC]++; if (cur->step()) { rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the cur_step_back procedure RV do_cur_step_back(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTMISC]++; if (cur->step_back()) { rv = kt::RPCClient::RVSUCCESS; } else { const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); switch (e.code()) { case kc::BasicDB::Error::NOIMPL: { rv = kt::RPCClient::RVENOIMPL; break; } case kc::BasicDB::Error::NOREC: { rv = kt::RPCClient::RVELOGIC; break; } default: { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; break; } } } return rv; } // process the cur_set_value procedure RV do_cur_set_value(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } size_t vsiz; const char* vbuf = kt::strmapget(inmap, "value", &vsiz); if (!vbuf) { set_message(outmap, "ERROR", "invalid parameters"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "step"); bool step = rp ? true : false; rp = kt::strmapget(inmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; RV rv; opcounts_[thid][CNTSET]++; if (cur->set_value(vbuf, vsiz, xt, step)) { rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the remove procedure RV do_cur_remove(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTREMOVE]++; if (cur->remove()) { rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTREMOVEMISS]++; const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the cur_get_key procedure RV do_cur_get_key(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "step"); bool step = rp ? true : false; RV rv; opcounts_[thid][CNTGET]++; size_t ksiz; char* kbuf = cur->get_key(&ksiz, step); if (kbuf) { outmap["key"] = std::string(kbuf, ksiz); delete[] kbuf; rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTGETMISS]++; const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the cur_get_value procedure RV do_cur_get_value(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "step"); bool step = rp ? true : false; RV rv; opcounts_[thid][CNTGET]++; size_t vsiz; char* vbuf = cur->get_value(&vsiz, step); if (vbuf) { outmap["value"] = std::string(vbuf, vsiz); delete[] vbuf; rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTGETMISS]++; const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the cur_get procedure RV do_cur_get(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } const char* rp = kt::strmapget(inmap, "step"); bool step = rp ? true : false; RV rv; opcounts_[thid][CNTGET]++; size_t ksiz, vsiz; const char* vbuf; int64_t xt; char* kbuf = cur->get(&ksiz, &vbuf, &vsiz, &xt, step); if (kbuf) { outmap["key"] = std::string(kbuf, ksiz); outmap["value"] = std::string(vbuf, vsiz); if (xt < kt::TimedDB::XTMAX) set_message(outmap, "xt", "%lld", (long long)xt); delete[] kbuf; rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTGETMISS]++; const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the cur_seize procedure RV do_cur_seize(kt::RPCServer* serv, kt::RPCServer::Session* sess, kt::TimedDB::Cursor* cur, const std::map& inmap, std::map& outmap) { uint32_t thid = sess->thread_id(); if (!cur) { set_message(outmap, "ERROR", "no such cursor"); return kt::RPCClient::RVEINVALID; } RV rv; opcounts_[thid][CNTGET]++; size_t ksiz, vsiz; const char* vbuf; int64_t xt; char* kbuf = cur->seize(&ksiz, &vbuf, &vsiz, &xt); if (kbuf) { outmap["key"] = std::string(kbuf, ksiz); outmap["value"] = std::string(vbuf, vsiz); if (xt < kt::TimedDB::XTMAX) set_message(outmap, "xt", "%lld", (long long)xt); delete[] kbuf; rv = kt::RPCClient::RVSUCCESS; } else { opcounts_[thid][CNTGETMISS]++; const kc::BasicDB::Error& e = cur->error(); set_db_error(outmap, e); if (e == kc::BasicDB::Error::NOREC) { rv = kt::RPCClient::RVELOGIC; } else { log_db_error(serv, e); rv = kt::RPCClient::RVEINTERNAL; } } return rv; } // process the restful get command int32_t do_rest_get(kt::HTTPServer* serv, kt::HTTPServer::Session* sess, kt::TimedDB* db, const char* kbuf, size_t ksiz, const std::map& reqheads, const std::string& reqbody, std::map& resheads, std::string& resbody, const std::map& misc) { uint32_t thid = sess->thread_id(); int32_t code; opcounts_[thid][CNTGET]++; size_t vsiz; int64_t xt; const char* vbuf = db->get(kbuf, ksiz, &vsiz, &xt); if (vbuf) { resbody.append(vbuf, vsiz); if (xt < kt::TimedDB::XTMAX) { char buf[48]; kt::datestrhttp(xt, 0, buf); resheads["x-kt-xt"] = buf; } delete[] vbuf; code = 200; } else { opcounts_[thid][CNTGETMISS]++; const kc::BasicDB::Error& e = db->error(); kc::strprintf(&resheads["x-kt-error"], "DB: %d: %s: %s", e.code(), e.name(), e.message()); if (e == kc::BasicDB::Error::NOREC) { code = 404; } else { log_db_error(serv, e); code = 500; } } return code; } // process the restful head command int32_t do_rest_head(kt::HTTPServer* serv, kt::HTTPServer::Session* sess, kt::TimedDB* db, const char* kbuf, size_t ksiz, const std::map& reqheads, const std::string& reqbody, std::map& resheads, std::string& resbody, const std::map& misc) { uint32_t thid = sess->thread_id(); int32_t code; opcounts_[thid][CNTGET]++; size_t vsiz; int64_t xt; const char* vbuf = db->get(kbuf, ksiz, &vsiz, &xt); if (vbuf) { if (xt < kt::TimedDB::XTMAX) { char buf[48]; kt::datestrhttp(xt, 0, buf); resheads["x-kt-xt"] = buf; } kc::strprintf(&resheads["content-length"], "%lld", (long long)vsiz); delete[] vbuf; code = 200; } else { opcounts_[thid][CNTGETMISS]++; const kc::BasicDB::Error& e = db->error(); kc::strprintf(&resheads["x-kt-error"], "DB: %d: %s: %s", e.code(), e.name(), e.message()); resheads["content-length"] = "0"; if (e == kc::BasicDB::Error::NOREC) { code = 404; } else { log_db_error(serv, e); code = 500; } } return code; } // process the restful put command int32_t do_rest_put(kt::HTTPServer* serv, kt::HTTPServer::Session* sess, kt::TimedDB* db, const char* kbuf, size_t ksiz, const std::map& reqheads, const std::string& reqbody, std::map& resheads, std::string& resbody, const std::map& misc) { uint32_t thid = sess->thread_id(); int32_t mode = 0; const char* rp = kt::strmapget(reqheads, "x-kt-mode"); if (rp) { if (!kc::stricmp(rp, "add")) { mode = 1; } else if (!kc::stricmp(rp, "replace")) { mode = 2; } } rp = kt::strmapget(reqheads, "x-kt-xt"); int64_t xt = rp ? kt::strmktime(rp) : -1; xt = xt > 0 && xt < kt::TimedDB::XTMAX ? -xt : kc::INT64MAX; int32_t code; opcounts_[thid][CNTSET]++; bool rv; switch (mode) { default: { rv = db->set(kbuf, ksiz, reqbody.data(), reqbody.size(), xt); break; } case 1: { rv = db->add(kbuf, ksiz, reqbody.data(), reqbody.size(), xt); break; } case 2: { rv = db->replace(kbuf, ksiz, reqbody.data(), reqbody.size(), xt); break; } } if (rv) { const char* url = kt::strmapget(misc, "url"); if (url) resheads["location"] = url; code = 201; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); kc::strprintf(&resheads["x-kt-error"], "DB: %d: %s: %s", e.code(), e.name(), e.message()); if (e == kc::BasicDB::Error::DUPREC || e == kc::BasicDB::Error::NOREC) { code = 450; } else { log_db_error(serv, e); code = 500; } } return code; } // process the restful delete command int32_t do_rest_delete(kt::HTTPServer* serv, kt::HTTPServer::Session* sess, kt::TimedDB* db, const char* kbuf, size_t ksiz, const std::map& reqheads, const std::string& reqbody, std::map& resheads, std::string& resbody, const std::map& misc) { uint32_t thid = sess->thread_id(); int32_t code; opcounts_[thid][CNTREMOVE]++; if (db->remove(kbuf, ksiz)) { code = 204; } else { opcounts_[thid][CNTREMOVEMISS]++; const kc::BasicDB::Error& e = db->error(); kc::strprintf(&resheads["x-kt-error"], "DB: %d: %s: %s", e.code(), e.name(), e.message()); if (e == kc::BasicDB::Error::NOREC) { code = 404; } else { log_db_error(serv, e); code = 500; } } return code; } // process the binary replication command bool do_bin_replication(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess) { char tbuf[sizeof(uint32_t)+sizeof(uint64_t)+sizeof(uint16_t)]; if (!sess->receive(tbuf, sizeof(tbuf))) return false; const char* rp = tbuf; uint32_t flags = kc::readfixnum(rp, sizeof(flags)); rp += sizeof(flags); uint64_t ts = kc::readfixnum(rp, sizeof(ts)); rp += sizeof(ts); uint16_t sid = kc::readfixnum(rp, sizeof(sid)); bool white = flags & kt::ReplicationClient::WHITESID; bool err = false; if (ulog_) { kt::UpdateLogger::Reader ulrd; if (ulrd.open(ulog_, ts)) { char c = kt::RemoteDB::BMREPLICATION; if (sess->send(&c, 1)) { serv->log(kt::ThreadedServer::Logger::SYSTEM, "a slave was connected: ts=%llu sid=%u", (unsigned long long)ts, sid); char stack[kc::NUMBUFSIZ+RECBUFSIZ*4]; uint64_t rts = 0; int32_t miss = 0; while (!err && !serv->aborted()) { size_t msiz; uint64_t mts; char* mbuf = ulrd.read(&msiz, &mts); if (mbuf) { size_t rsiz; uint16_t rsid = 0; uint16_t rdbid = 0; const char* rbuf = DBUpdateLogger::parse(mbuf, msiz, &rsiz, &rsid, &rdbid); if (white) { if (rsid != sid) rbuf = NULL; } else { if (rsid == sid) rbuf = NULL; } if (rbuf) { miss = 0; size_t nsiz = 1 + sizeof(uint64_t) + sizeof(uint32_t) + msiz; char* nbuf = nsiz > sizeof(stack) ? new char[nsiz] : stack; char* wp = nbuf; *(wp++) = kt::RemoteDB::BMREPLICATION; kc::writefixnum(wp, mts, sizeof(uint64_t)); wp += sizeof(uint64_t); kc::writefixnum(wp, msiz, sizeof(uint32_t)); wp += sizeof(uint32_t); std::memcpy(wp, mbuf, msiz); if (!sess->send(nbuf, nsiz)) err = true; if (nbuf != stack) delete[] nbuf; } else { miss++; if (miss >= Slave::DUMMYFREQ) { char hbuf[1+sizeof(uint64_t)+sizeof(uint32_t)]; char* wp = hbuf; *(wp++) = kt::RemoteDB::BMREPLICATION; kc::writefixnum(wp, mts, sizeof(uint64_t)); wp += sizeof(uint64_t); kc::writefixnum(wp, 0, sizeof(uint32_t)); if (!sess->send(hbuf, sizeof(hbuf))) err = true; miss = 0; } } if (mts > rts) rts = mts; delete[] mbuf; } else { uint64_t cc = kt::UpdateLogger::clock_pure(); if (cc > 1000000000) cc -= 1000000000; if (cc < rts) cc = rts; char hbuf[1+sizeof(uint64_t)]; char* wp = hbuf; *(wp++) = kt::RemoteDB::BMNOP; kc::writefixnum(wp, cc, sizeof(uint64_t)); if (!sess->send(hbuf, sizeof(hbuf)) || sess->receive_byte() != kt::RemoteDB::BMREPLICATION) err = true; kc::Thread::sleep(0.1); } } serv->log(kt::ThreadedServer::Logger::SYSTEM, "a slave was disconnected: sid=%u", sid); if (!ulrd.close()) { serv->log(kt::ThreadedServer::Logger::ERROR, "closing an update log reader failed"); err = true; } } else { err = true; } } else { serv->log(kt::ThreadedServer::Logger::ERROR, "opening an update log reader failed"); char c = kt::RemoteDB::BMERROR; sess->send(&c, 1); err = true; } } else { char c = kt::RemoteDB::BMERROR; sess->send(&c, 1); serv->log(kt::ThreadedServer::Logger::INFO, "no update log allows no replication"); err = true; } return !err; } // process the binary play_script command bool do_bin_play_script(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess) { uint32_t thid = sess->thread_id(); char tbuf[sizeof(uint32_t)+sizeof(uint32_t)+sizeof(uint32_t)]; if (!sess->receive(tbuf, sizeof(tbuf))) return false; const char* rp = tbuf; uint32_t flags = kc::readfixnum(rp, sizeof(flags)); rp += sizeof(flags); uint32_t nsiz = kc::readfixnum(rp, sizeof(nsiz)); rp += sizeof(nsiz); uint32_t rnum = kc::readfixnum(rp, sizeof(rnum)); rp += sizeof(rnum); if (nsiz > kt::RemoteDB::DATAMAXSIZ) return false; bool norep = flags & kt::RemoteDB::BONOREPLY; bool err = false; char nstack[kc::NUMBUFSIZ+RECBUFSIZ]; char* nbuf = nsiz + 1 > sizeof(nstack) ? new char[nsiz+1] : nstack; if (sess->receive(nbuf, nsiz)) { nbuf[nsiz] = '\0'; char stack[kc::NUMBUFSIZ+RECBUFSIZ*4]; std::map scrinmap; for (uint32_t i = 0; !err && i < rnum; i++) { char hbuf[sizeof(uint32_t)+sizeof(uint32_t)]; if (sess->receive(hbuf, sizeof(hbuf))) { rp = hbuf; uint32_t ksiz = kc::readfixnum(rp, sizeof(ksiz)); rp += sizeof(ksiz); uint32_t vsiz = kc::readfixnum(rp, sizeof(vsiz)); rp += sizeof(vsiz); if (ksiz <= kt::RemoteDB::DATAMAXSIZ && vsiz <= kt::RemoteDB::DATAMAXSIZ) { size_t rsiz = ksiz + vsiz; char* rbuf = rsiz > sizeof(stack) ? new char[rsiz] : stack; if (sess->receive(rbuf, rsiz)) { std::string key(rbuf, ksiz); std::string value(rbuf + ksiz, vsiz); scrinmap[key] = value; } else { err = true; } if (rbuf != stack) delete[] rbuf; } else { err = true; } } else { err = true; } } if (!err) { if (scrprocs_) { ScriptProcessor* scrproc = scrprocs_ + thid; opcounts_[thid][CNTSCRIPT]++; std::map scroutmap; RV rv = scrproc->call(nbuf, scrinmap, scroutmap); if (rv == kt::RPCClient::RVSUCCESS) { size_t osiz = 1 + sizeof(uint32_t); std::map::iterator it = scroutmap.begin(); std::map::iterator itend = scroutmap.end(); while (it != itend) { osiz += sizeof(uint32_t) + sizeof(uint32_t) + it->first.size() + it->second.size(); ++it; } char* obuf = new char[osiz]; char* wp = obuf; *(wp++) = kt::RemoteDB::BMPLAYSCRIPT; kc::writefixnum(wp, scroutmap.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); it = scroutmap.begin(); itend = scroutmap.end(); while (it != itend) { kc::writefixnum(wp, it->first.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); kc::writefixnum(wp, it->second.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); std::memcpy(wp, it->first.data(), it->first.size()); wp += it->first.size(); std::memcpy(wp, it->second.data(), it->second.size()); wp += it->second.size(); ++it; } if (!norep && !sess->send(obuf, osiz)) err = true; delete[] obuf; } else { char c = kt::RemoteDB::BMERROR; if (!norep) sess->send(&c, 1); } } else { char c = kt::RemoteDB::BMERROR; if (!norep) sess->send(&c, 1); } } } if (nbuf != nstack) delete[] nbuf; return !err; } // process the binary set_bulk command bool do_bin_set_bulk(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess) { uint32_t thid = sess->thread_id(); char tbuf[sizeof(uint32_t)+sizeof(uint32_t)]; if (!sess->receive(tbuf, sizeof(tbuf))) return false; const char* rp = tbuf; uint32_t flags = kc::readfixnum(rp, sizeof(flags)); rp += sizeof(flags); uint32_t rnum = kc::readfixnum(rp, sizeof(rnum)); rp += sizeof(rnum); bool norep = flags & kt::RemoteDB::BONOREPLY; bool err = false; uint32_t hits = 0; char stack[kc::NUMBUFSIZ+RECBUFSIZ*4]; for (uint32_t i = 0; !err && i < rnum; i++) { char hbuf[sizeof(uint16_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(int64_t)]; if (sess->receive(hbuf, sizeof(hbuf))) { rp = hbuf; uint16_t dbidx = kc::readfixnum(rp, sizeof(dbidx)); rp += sizeof(dbidx); uint32_t ksiz = kc::readfixnum(rp, sizeof(ksiz)); rp += sizeof(ksiz); uint32_t vsiz = kc::readfixnum(rp, sizeof(vsiz)); rp += sizeof(vsiz); int64_t xt = kc::readfixnum(rp, sizeof(xt)); rp += sizeof(xt); if (ksiz <= kt::RemoteDB::DATAMAXSIZ && vsiz <= kt::RemoteDB::DATAMAXSIZ) { size_t rsiz = ksiz + vsiz; char* rbuf = rsiz > sizeof(stack) ? new char[rsiz] : stack; if (sess->receive(rbuf, rsiz)) { if (dbidx < dbnum_) { kt::TimedDB* db = dbs_ + dbidx; opcounts_[thid][CNTSET]++; if (db->set(rbuf, ksiz, rbuf + ksiz, vsiz, xt)) { hits++; } else { opcounts_[thid][CNTSETMISS]++; err = true; } } } else { err = true; } if (rbuf != stack) delete[] rbuf; } else { err = true; } } else { err = true; } } if (err) { char c = kt::RemoteDB::BMERROR; if (!norep) sess->send(&c, 1); } else { char hbuf[1+sizeof(hits)]; char* wp = hbuf; *(wp++) = kt::RemoteDB::BMSETBULK; kc::writefixnum(wp, hits, sizeof(hits)); if (!norep && !sess->send(hbuf, sizeof(hbuf))) err = true; } return !err; } // process the binary remove_bulk command bool do_bin_remove_bulk(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess) { uint32_t thid = sess->thread_id(); char tbuf[sizeof(uint32_t)+sizeof(uint32_t)]; if (!sess->receive(tbuf, sizeof(tbuf))) return false; const char* rp = tbuf; uint32_t flags = kc::readfixnum(rp, sizeof(flags)); rp += sizeof(flags); uint32_t rnum = kc::readfixnum(rp, sizeof(rnum)); rp += sizeof(rnum); bool norep = flags & kt::RemoteDB::BONOREPLY; bool err = false; uint32_t hits = 0; char stack[kc::NUMBUFSIZ+RECBUFSIZ*2]; for (uint32_t i = 0; !err && i < rnum; i++) { char hbuf[sizeof(uint16_t)+sizeof(uint32_t)]; if (sess->receive(hbuf, sizeof(hbuf))) { rp = hbuf; uint16_t dbidx = kc::readfixnum(rp, sizeof(dbidx)); rp += sizeof(dbidx); uint32_t ksiz = kc::readfixnum(rp, sizeof(ksiz)); rp += sizeof(ksiz); if (ksiz <= kt::RemoteDB::DATAMAXSIZ) { char* kbuf = ksiz > sizeof(stack) ? new char[ksiz] : stack; if (sess->receive(kbuf, ksiz)) { if (dbidx < dbnum_) { kt::TimedDB* db = dbs_ + dbidx; opcounts_[thid][CNTREMOVE]++; if (db->remove(kbuf, ksiz)) { hits++; } else { opcounts_[thid][CNTREMOVEMISS]++; if (db->error() != kc::BasicDB::Error::NOREC) err = true; } } } else { err = true; } if (kbuf != stack) delete[] kbuf; } else { err = true; } } else { err = true; } } if (err) { char c = kt::RemoteDB::BMERROR; if (!norep) sess->send(&c, 1); } else { char hbuf[1+sizeof(hits)]; char* wp = hbuf; *(wp++) = kt::RemoteDB::BMREMOVEBULK; kc::writefixnum(wp, hits, sizeof(hits)); if (!norep && !sess->send(hbuf, sizeof(hbuf))) err = true; } return !err; } // process the binary get_bulk command bool do_bin_get_bulk(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess) { uint32_t thid = sess->thread_id(); char tbuf[sizeof(uint32_t)+sizeof(uint32_t)]; if (!sess->receive(tbuf, sizeof(tbuf))) return false; const char* rp = tbuf; uint32_t flags = kc::readfixnum(rp, sizeof(flags)); rp += sizeof(flags); uint32_t rnum = kc::readfixnum(rp, sizeof(rnum)); rp += sizeof(rnum); bool err = false; uint32_t hits = 0; char stack[kc::NUMBUFSIZ+RECBUFSIZ*2]; size_t oasiz = kc::NUMBUFSIZ + RECBUFSIZ * 2; char* obuf = (char*)kc::xmalloc(oasiz); size_t osiz = 1 + sizeof(uint32_t); std::memset(obuf, 0, osiz); for (uint32_t i = 0; !err && i < rnum; i++) { char hbuf[sizeof(uint16_t)+sizeof(uint32_t)]; if (sess->receive(hbuf, sizeof(hbuf))) { rp = hbuf; uint16_t dbidx = kc::readfixnum(rp, sizeof(dbidx)); rp += sizeof(dbidx); uint32_t ksiz = kc::readfixnum(rp, sizeof(ksiz)); rp += sizeof(ksiz); if (ksiz <= kt::RemoteDB::DATAMAXSIZ) { char* kbuf = ksiz > sizeof(stack) ? new char[ksiz] : stack; if (sess->receive(kbuf, ksiz)) { if (dbidx < dbnum_) { kt::TimedDB* db = dbs_ + dbidx; opcounts_[thid][CNTGET]++; size_t vsiz; int64_t xt; char* vbuf = db->get(kbuf, ksiz, &vsiz, &xt); if (vbuf) { hits++; size_t usiz = sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(int64_t) + ksiz + vsiz; if (osiz + usiz > oasiz) { oasiz = oasiz * 2 + usiz; obuf = (char*)kc::xrealloc(obuf, oasiz); } kc::writefixnum(obuf + osiz, dbidx, sizeof(uint16_t)); osiz += sizeof(uint16_t); kc::writefixnum(obuf + osiz, ksiz, sizeof(uint32_t)); osiz += sizeof(uint32_t); kc::writefixnum(obuf + osiz, vsiz, sizeof(uint32_t)); osiz += sizeof(uint32_t); kc::writefixnum(obuf + osiz, xt, sizeof(int64_t)); osiz += sizeof(int64_t); std::memcpy(obuf + osiz, kbuf, ksiz); osiz += ksiz; std::memcpy(obuf + osiz, vbuf, vsiz); osiz += vsiz; delete[] vbuf; } else { opcounts_[thid][CNTGETMISS]++; if (db->error() != kc::BasicDB::Error::NOREC) err = true; } } } else { err = true; } if (kbuf != stack) delete[] kbuf; } else { err = true; } } else { err = true; } } if (err) { char c = kt::RemoteDB::BMERROR; sess->send(&c, 1); } else { *obuf = kt::RemoteDB::BMGETBULK; kc::writefixnum(obuf + 1, hits, sizeof(hits)); if (!sess->send(obuf, osiz)) err = true; } kc::xfree(obuf); return !err; } // session local storage class SLS : public kt::RPCServer::Session::Data { friend class Worker; private: SLS() : curs_() {} ~SLS() { std::map::iterator it = curs_.begin(); std::map::iterator itend = curs_.end(); while (it != itend) { kt::TimedDB::Cursor* cur = it->second; delete cur; ++it; } } static SLS* create(kt::RPCServer::Session* sess) { SLS* sls = (SLS*)sess->data(); if (!sls) { sls = new SLS; sess->set_data(sls); } return sls; } std::map curs_; }; int32_t thnum_; kc::CondMap* const condmap_; kt::TimedDB* const dbs_; const int32_t dbnum_; const std::map& dbmap_; const int32_t omode_; const double asi_; const bool ash_; const char* const bgspath_; const double bgsi_; kc::Compressor* const bgscomp_; kt::UpdateLogger* const ulog_; DBUpdateLogger* const ulogdbs_; const char* const cmdpath_; ScriptProcessor* const scrprocs_; OpCount* const opcounts_; uint64_t idlecnt_; double asnext_; double bgsnext_; Slave* slave_; }; // main routine int main(int argc, char** argv) { g_progname = argv[0]; g_procid = kc::getpid(); g_starttime = kc::time(); kc::setstdiobin(); kt::setkillsignalhandler(killserver); if (argc > 1 && !std::strcmp(argv[1], "--version")) { printversion(); return 0; } int32_t rv = run(argc, argv); return rv; } // print the usage and exit static void usage() { eprintf("%s: Kyoto Tycoon: a handy cache/storage server\n", g_progname); eprintf("\n"); eprintf("usage:\n"); eprintf(" %s [-host str] [-port num] [-tout num] [-th num] [-log file] [-li|-ls|-le|-lz]" " [-ulog dir] [-ulim num] [-uasi num] [-sid num] [-ord] [-oat|-oas|-onl|-otl|-onr]" " [-asi num] [-ash] [-bgs dir] [-bgsi num] [-bgc str]" " [-dmn] [-pid file] [-cmd dir] [-scr file]" " [-mhost str] [-mport num] [-rts file] [-riv num]" " [-plsv file] [-plex str] [-pldb file] [db...]\n", g_progname); eprintf("\n"); std::exit(1); } // kill the running server static void killserver(int signum) { if (g_serv) { g_serv->stop(); g_serv = NULL; if (g_daemon && signum == SIGHUP) g_restart = true; if (signum == SIGUSR1) g_restart = true; } } // parse arguments of the command static int32_t run(int argc, char** argv) { bool argbrk = false; std::vector dbpaths; const char* host = NULL; int32_t port = kt::DEFPORT; double tout = DEFTOUT; int32_t thnum = DEFTHNUM; const char* logpath = NULL; uint32_t logkinds = kc::UINT32MAX; const char* ulogpath = NULL; int64_t ulim = DEFULIM; double uasi = 0; int32_t sid = -1; int32_t omode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE; double asi = 0; bool ash = false; const char* bgspath = NULL; double bgsi = DEFBGSI; kc::Compressor* bgscomp = NULL; bool dmn = false; const char* pidpath = NULL; const char* cmdpath = NULL; const char* scrpath = NULL; const char* mhost = NULL; int32_t mport = kt::DEFPORT; const char* rtspath = NULL; double riv = DEFRIV; const char* plsvpath = NULL; const char* plsvex = ""; const char* pldbpath = NULL; for (int32_t i = 1; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-log")) { if (++i >= argc) usage(); logpath = argv[i]; } else if (!std::strcmp(argv[i], "-li")) { logkinds = Logger::INFO | Logger::SYSTEM | Logger::ERROR; } else if (!std::strcmp(argv[i], "-ls")) { logkinds = Logger::SYSTEM | Logger::ERROR; } else if (!std::strcmp(argv[i], "-le")) { logkinds = Logger::ERROR; } else if (!std::strcmp(argv[i], "-lz")) { logkinds = 0; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-uasi")) { if (++i >= argc) usage(); uasi = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-ord")) { omode &= ~kc::BasicDB::OWRITER; omode |= kc::BasicDB::OREADER; } else if (!std::strcmp(argv[i], "-oat")) { omode |= kc::BasicDB::OAUTOTRAN; } else if (!std::strcmp(argv[i], "-oas")) { omode |= kc::BasicDB::OAUTOSYNC; } else if (!std::strcmp(argv[i], "-onl")) { omode |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { omode |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { omode |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-asi")) { if (++i >= argc) usage(); asi = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ash")) { ash = true; } else if (!std::strcmp(argv[i], "-bgs")) { if (++i >= argc) usage(); bgspath = argv[i]; } else if (!std::strcmp(argv[i], "-bgsi")) { if (++i >= argc) usage(); bgsi = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-bgsc")) { if (++i >= argc) usage(); const char* cn = argv[i]; if (!kc::stricmp(cn, "zlib") || !kc::stricmp(cn, "gz")) { bgscomp = new kc::ZLIBCompressor; } else if (!kc::stricmp(cn, "lzo") || !kc::stricmp(cn, "oz")) { bgscomp = new kc::LZOCompressor; } else if (!kc::stricmp(cn, "lzma") || !kc::stricmp(cn, "xz")) { bgscomp = new kc::LZMACompressor; } } else if (!std::strcmp(argv[i], "-dmn")) { dmn = true; } else if (!std::strcmp(argv[i], "-pid")) { if (++i >= argc) usage(); pidpath = argv[i]; } else if (!std::strcmp(argv[i], "-cmd")) { if (++i >= argc) usage(); cmdpath = argv[i]; } else if (!std::strcmp(argv[i], "-scr")) { if (++i >= argc) usage(); scrpath = argv[i]; } else if (!std::strcmp(argv[i], "-mhost")) { if (++i >= argc) usage(); mhost = argv[i]; } else if (!std::strcmp(argv[i], "-mport")) { if (++i >= argc) usage(); mport = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-rts")) { if (++i >= argc) usage(); rtspath = argv[i]; } else if (!std::strcmp(argv[i], "-riv")) { if (++i >= argc) usage(); riv = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-plsv")) { if (++i >= argc) usage(); plsvpath = argv[i]; } else if (!std::strcmp(argv[i], "-plex")) { if (++i >= argc) usage(); plsvex = argv[i]; } else if (!std::strcmp(argv[i], "-pldb")) { if (++i >= argc) usage(); pldbpath = argv[i]; } else { usage(); } } else { argbrk = true; dbpaths.push_back(argv[i]); } } if (port < 1 || thnum < 1 || mport < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; if (dbpaths.empty()) { if (pldbpath) usage(); dbpaths.push_back(":"); } int32_t rv = proc(dbpaths, host, port, tout, thnum, logpath, logkinds, ulogpath, ulim, uasi, sid, omode, asi, ash, bgspath, bgsi, bgscomp, dmn, pidpath, cmdpath, scrpath, mhost, mport, rtspath, riv, plsvpath, plsvex, pldbpath); delete bgscomp; return rv; } // drive the server process static int32_t proc(const std::vector& dbpaths, const char* host, int32_t port, double tout, int32_t thnum, const char* logpath, uint32_t logkinds, const char* ulogpath, int64_t ulim, double uasi, int32_t sid, int32_t omode, double asi, bool ash, const char* bgspath, double bgsi, kc::Compressor* bgscomp, bool dmn, const char* pidpath, const char* cmdpath, const char* scrpath, const char* mhost, int32_t mport, const char* rtspath, double riv, const char* plsvpath, const char* plsvex, const char* pldbpath) { g_daemon = false; if (dmn) { if (kc::File::PATHCHR == '/') { if (logpath && *logpath != kc::File::PATHCHR) { eprintf("%s: %s: a daemon can accept absolute path only\n", g_progname, logpath); return 1; } if (ulogpath && *ulogpath != kc::File::PATHCHR) { eprintf("%s: %s: a daemon can accept absolute path only\n", g_progname, ulogpath); return 1; } if (bgspath && *bgspath != kc::File::PATHCHR) { eprintf("%s: %s: a daemon can accept absolute path only\n", g_progname, bgspath); return 1; } if (pidpath && *pidpath != kc::File::PATHCHR) { eprintf("%s: %s: a daemon can accept absolute path only\n", g_progname, pidpath); return 1; } if (cmdpath && *cmdpath != kc::File::PATHCHR) { eprintf("%s: %s: a daemon can accept absolute path only\n", g_progname, cmdpath); return 1; } if (scrpath && *scrpath != kc::File::PATHCHR) { eprintf("%s: %s: a daemon can accept absolute path only\n", g_progname, scrpath); return 1; } if (rtspath && *rtspath != kc::File::PATHCHR) { eprintf("%s: %s: a daemon can accept absolute path only\n", g_progname, rtspath); return 1; } if (plsvpath && *plsvpath != kc::File::PATHCHR) { eprintf("%s: %s: a daemon can accept absolute path only\n", g_progname, plsvpath); return 1; } if (pldbpath && *pldbpath != kc::File::PATHCHR) { eprintf("%s: %s: a daemon can accept absolute path only\n", g_progname, pldbpath); return 1; } } if (!kt::daemonize()) { eprintf("%s: switching to a daemon failed\n", g_progname); return 1; } g_procid = kc::getpid(); g_daemon = true; } if (ulogpath && sid < 0) { eprintf("%s: update log requires the server ID\n", g_progname); return 1; } if (!cmdpath) cmdpath = kc::File::CDIRSTR; if (mhost) { if (sid < 0) { eprintf("%s: replication requires the server ID\n", g_progname); return 1; } if (!rtspath) { eprintf("%s: replication requires the replication time stamp file\n", g_progname); return 1; } } if (sid < 0) sid = 0; kc::File::Status sbuf; if (bgspath && !kc::File::status(bgspath, &sbuf) && !kc::File::make_directory(bgspath)) { eprintf("%s: %s: could not open the directory\n", g_progname, bgspath); return 1; } if (!kc::File::status(cmdpath, &sbuf) || !sbuf.isdir) { eprintf("%s: %s: no such directory\n", g_progname, cmdpath); return 1; } if (scrpath && !kc::File::status(scrpath)) { eprintf("%s: %s: no such file\n", g_progname, scrpath); return 1; } if (dbpaths.size() > (size_t)OPENDBMAX) { eprintf("%s: too much databases\n", g_progname); return 1; } kt::RPCServer serv; Logger logger; if (!logger.open(logpath)) { eprintf("%s: %s: could not open the log file\n", g_progname, logpath ? logpath : "-"); return 1; } serv.set_logger(&logger, logkinds); serv.log(Logger::SYSTEM, "================ [START]: pid=%d", g_procid); std::string addr = ""; if (host) { addr = kt::Socket::get_host_address(host); if (addr.empty()) { serv.log(Logger::ERROR, "unknown host: %s", host); return 1; } } kt::SharedLibrary pldblib; kt::KTDBINIT pldbinit = NULL; if (pldbpath) { serv.log(Logger::SYSTEM, "loading a plug-in database file: path=%s", pldbpath); if (!pldblib.open(pldbpath)) { serv.log(Logger::ERROR, "could not load a plug-in database file: %s", pldbpath); return 1; } pldbinit = (kt::KTDBINIT)pldblib.symbol(kt::KTDBINITNAME); if (!pldbinit) { serv.log(Logger::ERROR, "could not find the initializer: %s: %s", pldbpath, kt::KTDBINITNAME); return 1; } } std::string expr = kc::strprintf("%s:%d", addr.c_str(), port); serv.set_network(expr, tout); int32_t dbnum = dbpaths.size(); kt::UpdateLogger* ulog = NULL; DBUpdateLogger* ulogdbs = NULL; if (ulogpath) { ulog = new kt::UpdateLogger; serv.log(Logger::SYSTEM, "opening the update log: path=%s sid=%u", ulogpath, sid); if (!ulog->open(ulogpath, ulim, uasi)) { serv.log(Logger::ERROR, "could not open the update log: %s", ulogpath); delete ulog; return 1; } ulogdbs = new DBUpdateLogger[dbnum]; } kt::TimedDB* dbs = new kt::TimedDB[dbnum]; DBLogger dblogger(&logger, logkinds); std::map dbmap; for (int32_t i = 0; i < dbnum; i++) { const std::string& dbpath = dbpaths[i]; serv.log(Logger::SYSTEM, "opening a database: path=%s", dbpath.c_str()); if (logkinds != 0) dbs[i].tune_logger(&dblogger, kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR); if (ulog) { ulogdbs[i].initialize(ulog, sid, i); dbs[i].tune_update_trigger(ulogdbs + i); } if (pldbinit) dbs[i].set_internal_db(pldbinit()); if (!dbs[i].open(dbpath, omode)) { const kc::BasicDB::Error& e = dbs[i].error(); serv.log(Logger::ERROR, "could not open a database file: %s: %s: %s", dbpath.c_str(), e.name(), e.message()); delete[] dbs; delete[] ulogdbs; delete ulog; return 1; } std::string path = dbs[i].path(); const char* rp = path.c_str(); const char* pv = std::strrchr(rp, kc::File::PATHCHR); if (pv) rp = pv + 1; dbmap[rp] = i; } if (bgspath) { kc::DirStream dir; if (dir.open(bgspath)) { std::string name; while (dir.read(&name)) { const char* nstr = name.c_str(); const char* pv = std::strrchr(nstr, kc::File::EXTCHR); int32_t idx = kc::atoi(nstr); if (*nstr >= '0' && *nstr <= '9' && pv && !kc::stricmp(pv + 1, BGSPATHEXT) && idx >= 0 && idx < dbnum) { std::string path; kc::strprintf(&path, "%s%c%s", bgspath, kc::File::PATHCHR, nstr); uint64_t ssts; int64_t sscount, sssize; if (kt::TimedDB::status_snapshot_atomic(path, &ssts, &sscount, &sssize)) { serv.log(Logger::SYSTEM, "applying a snapshot file: db=%d ts=%llu count=%lld size=%lld", idx, (unsigned long long)ssts, (long long)sscount, (long long)sssize); if (!dbs[idx].load_snapshot_atomic(path, bgscomp)) { const kc::BasicDB::Error& e = dbs[idx].error(); serv.log(Logger::ERROR, "could not apply a snapshot: %s: %s", e.name(), e.message()); } } } } dir.close(); } } ScriptProcessor* scrprocs = NULL; if (scrpath) { serv.log(Logger::SYSTEM, "loading a script file: path=%s", scrpath); scrprocs = new ScriptProcessor[thnum]; for (int32_t i = 0; i < thnum; i++) { if (!scrprocs[i].set_resources(i, &serv, dbs, dbnum, &dbmap)) { serv.log(Logger::ERROR, "could not initialize the scripting processor"); delete[] scrprocs; delete[] dbs; delete[] ulogdbs; delete ulog; return 1; } if (!scrprocs[i].load(scrpath)) serv.log(Logger::ERROR, "could not load a script file: %s", scrpath); } } kt::SharedLibrary plsvlib; kt::PluggableServer* plsv = NULL; if (plsvpath) { serv.log(Logger::SYSTEM, "loading a plug-in server file: path=%s", plsvpath); if (!plsvlib.open(plsvpath)) { serv.log(Logger::ERROR, "could not load a plug-in server file: %s", plsvpath); delete[] scrprocs; delete[] dbs; delete[] ulogdbs; delete ulog; return 1; } kt::KTSERVINIT init = (kt::KTSERVINIT)plsvlib.symbol(kt::KTSERVINITNAME); if (!init) { serv.log(Logger::ERROR, "could not find the initializer: %s: %s", plsvpath, kt::KTSERVINITNAME); delete[] scrprocs; delete[] dbs; delete[] ulogdbs; delete ulog; return 1; } plsv = init(); plsv->configure(dbs, dbnum, &logger, logkinds, plsvex); } OpCount* opcounts = new OpCount[thnum]; for (int32_t i = 0; i < thnum; i++) { for (int32_t j = 0; j <= CNTMISC; j++) { opcounts[i][j] = 0; } } kc::CondMap condmap; Worker worker(thnum, &condmap, dbs, dbnum, dbmap, omode, asi, ash, bgspath, bgsi, bgscomp, ulog, ulogdbs, cmdpath, scrprocs, opcounts); serv.set_worker(&worker, thnum); if (pidpath) { char numbuf[kc::NUMBUFSIZ]; size_t nsiz = std::sprintf(numbuf, "%d\n", g_procid); kc::File::write_file(pidpath, numbuf, nsiz); } bool err = false; while (true) { g_restart = false; g_serv = &serv; Slave slave(sid, rtspath, mhost, mport, riv, &serv, dbs, dbnum, ulog, ulogdbs); slave.start(); worker.set_misc_conf(&slave); PlugInDriver pldriver(plsv); if (plsv) pldriver.start(); if (serv.start()) { condmap.broadcast_all(); if (!serv.finish()) err = true; } else { err = true; } kc::Thread::sleep(0.5); if (plsv) { plsv->stop(); pldriver.join(); if (pldriver.error()) err = true; kc::Thread::sleep(0.1); } slave.stop(); slave.join(); if (!g_restart || err) break; logger.close(); if (!logger.open(logpath)) { eprintf("%s: %s: could not open the log file\n", g_progname, logpath ? logpath : "-"); err = true; break; } if (scrprocs) { serv.log(Logger::SYSTEM, "reloading a script file: path=%s", scrpath); for (int32_t i = 0; i < thnum; i++) { scrprocs[i].clear(); if (!scrprocs[i].set_resources(i, &serv, dbs, dbnum, &dbmap)) { serv.log(Logger::ERROR, "could not initialize the scripting processor"); err = true; break; } if (!scrprocs[i].load(scrpath)) serv.log(Logger::ERROR, "could not load a script file: %s", scrpath); } } if (err) break; } if (pidpath) kc::File::remove(pidpath); delete[] opcounts; if (plsv) { delete plsv; if (!plsvlib.close()) { eprintf("%s: closing a shared library failed\n", g_progname); err = true; } } if (bgspath) { serv.log(Logger::SYSTEM, "snapshotting databases"); if (!dosnapshot(bgspath, bgscomp, dbs, dbnum, &serv)) err = true; } delete[] scrprocs; for (int32_t i = 0; i < dbnum; i++) { const std::string& dbpath = dbpaths[i]; serv.log(Logger::SYSTEM, "closing a database: path=%s", dbpath.c_str()); if (!dbs[i].close()) { const kc::BasicDB::Error& e = dbs[i].error(); serv.log(Logger::ERROR, "could not close a database file: %s: %s: %s", dbpath.c_str(), e.name(), e.message()); err = true; } } delete[] dbs; if (ulog) { delete[] ulogdbs; if (!ulog->close()) { eprintf("%s: closing the update log faild\n", g_progname); err = true; } delete ulog; } if (pldbinit && !pldblib.close()) { eprintf("%s: closing a shared library failed\n", g_progname); err = true; } serv.log(Logger::SYSTEM, "================ [FINISH]: pid=%d", g_procid); return err ? 1 : 0; } // snapshot all databases static bool dosnapshot(const char* bgspath, kc::Compressor* bgscomp, kt::TimedDB* dbs, int32_t dbnum, kt::RPCServer* serv) { bool err = false; for (int32_t i = 0; i < dbnum; i++) { kt::TimedDB* db = dbs + i; std::string destpath; kc::strprintf(&destpath, "%s%c%08d%c%s", bgspath, kc::File::PATHCHR, i, kc::File::EXTCHR, BGSPATHEXT); std::string tmppath; kc::strprintf(&tmppath, "%s%ctmp", destpath.c_str(), kc::File::EXTCHR); int32_t cnt = 0; while (true) { if (db->dump_snapshot_atomic(tmppath, bgscomp)) { if (!kc::File::rename(tmppath, destpath)) { serv->log(Logger::ERROR, "renaming a file failed: %s: %s", tmppath.c_str(), destpath.c_str()); } kc::File::remove(tmppath); break; } kc::File::remove(tmppath); const kc::BasicDB::Error& e = db->error(); if (e != kc::BasicDB::Error::LOGIC) { serv->log(Logger::ERROR, "database error: %d: %s: %s", e.code(), e.name(), e.message()); break; } if (++cnt >= 3) { serv->log(Logger::SYSTEM, "snapshotting was abandoned"); err = true; break; } serv->log(Logger::INFO, "retrying snapshot: %d", cnt); } kc::Thread::yield(); } return !err; } // END OF FILE kyototycoon-0.9.56/ktplugservmemc.cc0000644000175000017500000007647111757471602016626 0ustar mikiomikio/************************************************************************************************* * A pluggable server for the memcached protocol * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include namespace kc = kyotocabinet; namespace kt = kyototycoon; const int32_t DEFPORTNUM = 11211; // port number const int32_t DEFTIMEOUT = 30; // networking timeout const int32_t DEFTHNUM = 16; // number of threads const double DEFQTIMEOUT = 10; // queue waiting timeout // pluggable server for the memcached protocol class MemcacheServer : public kt::PluggableServer { private: class Worker; class SLS; public: // default constructor explicit MemcacheServer() : dbary_(NULL), dbnum_(0), logger_(NULL), expr_(""), host_(""), port_(0), tout_(0), thnum_(0), opts_(0), qtout_(0), stime_(0), seq_(0), cond_(), serv_(), worker_(NULL) { _assert_(true); } // destructor ~MemcacheServer() { _assert_(true); } // configure server settings void configure(kt::TimedDB* dbary, size_t dbnum, kt::ThreadedServer::Logger* logger, uint32_t logkinds, const char* expr) { _assert_(dbary && logger && expr); dbary_ = dbary; dbnum_ = dbnum; logger_ = logger; logkinds_ = logkinds; expr_ = expr; serv_.set_logger(logger_, logkinds_); serv_.log(kt::ThreadedServer::Logger::SYSTEM, "the plug-in memcached server configured: expr=%s", expr); host_ = ""; port_ = 0; tout_ = 0; thnum_ = 0; opts_ = 0; qtout_ = 0; std::vector elems; kc::strsplit(expr_.c_str(), '#', &elems); std::vector::iterator it = elems.begin(); std::vector::iterator itend = elems.end(); while (it != itend) { std::vector fields; if (kc::strsplit(*it, '=', &fields) > 1) { const char* key = fields[0].c_str(); const char* value = fields[1].c_str(); if (!std::strcmp(key, "host")) { host_ = value; } else if (!std::strcmp(key, "port")) { port_ = kc::atoi(value); } else if (!std::strcmp(key, "tout") || !std::strcmp(key, "timeout")) { tout_ = kc::atof(value); } else if (!std::strcmp(key, "th") || !std::strcmp(key, "thnum")) { thnum_ = kc::atoi(value); } else if (!std::strcmp(key, "opts") || !std::strcmp(key, "options")) { if (std::strchr(value, 'f')) opts_ |= TFLAGS; if (std::strchr(value, 'q')) opts_ |= TQUEUE; } else if (!std::strcmp(key, "qtout") || !std::strcmp(key, "qtimeout")) { qtout_ = kc::atof(value); } } ++it; } if (port_ < 1) port_ = DEFPORTNUM; if (tout_ < 1) tout_ = DEFTIMEOUT; if (thnum_ < 1) thnum_ = DEFTHNUM; if (qtout_ <= 0) qtout_ = DEFQTIMEOUT; stime_ = kc::time(); } // start the server bool start() { _assert_(true); std::string addr; if (!host_.empty()) { addr = kt::Socket::get_host_address(host_); if (addr.empty()) { serv_.log(kt::ThreadedServer::Logger::ERROR, "unknown host: %s", host_.c_str()); return false; } } std::string nexpr; kc::strprintf(&nexpr, "%s:%d", addr.c_str(), port_); serv_.set_network(nexpr, tout_); worker_ = new Worker(this, thnum_); serv_.set_worker(worker_, thnum_); return serv_.start(); } // stop the server bool stop() { _assert_(true); return serv_.stop(); } // finish the server bool finish() { _assert_(true); bool err = false; cond_.broadcast_all(); if (!serv_.finish()) err = true; delete worker_; return !err; } private: // tuning options enum Option { TFLAGS = 1 << 1, TQUEUE = 1 << 2 }; // worker implementation class Worker : public kt::ThreadedServer::Worker { // symbols for operation counting enum { CNTSET, CNTSETMISS, CNTGET, CNTGETMISS, CNTDELETE, CNTDELETEMISS, CNTINCR, CNTINCRMISS, CNTDECR, CNTDECRMISS, CNTFLUSH }; typedef uint64_t OpCount[CNTFLUSH+1]; public: // constructor explicit Worker(MemcacheServer* serv, int32_t thnum) : serv_(serv), thnum_(thnum), opcounts_(NULL) { opcounts_ = new OpCount[thnum_]; for (int32_t i = 0; i < thnum_; i++) { for (int32_t j = 0; j <= CNTFLUSH; j++) { opcounts_[i][j] = 0; } } } // destructor ~Worker() { delete[] opcounts_; } private: // process each request. bool process(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess) { kt::TimedDB* db = serv_->dbary_; bool keep = false; char line[8192]; if (sess->receive_line(line, sizeof(line))) { keep = true; std::vector tokens; kt::strtokenize(line, &tokens); const std::string& cmd = tokens.empty() ? "" : tokens.front(); if (cmd == "set") { if (serv_->opts_ & TQUEUE) { keep = do_queue_set(serv, sess, tokens, db); } else { keep = do_set(serv, sess, tokens, db); } } else if (cmd == "add") { keep = do_add(serv, sess, tokens, db); } else if (cmd == "replace") { keep = do_replace(serv, sess, tokens, db); } else if (cmd == "get" || cmd == "gets") { if (serv_->opts_ & TQUEUE) { keep = do_queue_get(serv, sess, tokens, db); } else { keep = do_get(serv, sess, tokens, db); } } else if (cmd == "delete") { if (serv_->opts_ & TQUEUE) { keep = do_queue_delete(serv, sess, tokens, db); } else { keep = do_delete(serv, sess, tokens, db); } } else if (cmd == "incr") { keep = do_incr(serv, sess, tokens, db); } else if (cmd == "decr") { keep = do_decr(serv, sess, tokens, db); } else if (cmd == "stats") { keep = do_stats(serv, sess, tokens, db); } else if (cmd == "flush_all") { keep = do_flush_all(serv, sess, tokens, db); } else if (cmd == "version") { keep = do_version(serv, sess, tokens, db); } else if (cmd == "quit") { keep = false; } else { sess->printf("ERROR\r\n"); } std::string expr = sess->expression(); serv->log(kt::ThreadedServer::Logger::INFO, "(%s): %s", expr.c_str(), cmd.c_str()); } return keep; } // process the starting event void process_start(kt::ThreadedServer* serv) { kt::maskthreadsignal(); } // log the database error message void log_db_error(kt::ThreadedServer* serv, const kc::BasicDB::Error& e) { serv->log(kt::ThreadedServer::Logger::ERROR, "database error: %d: %s: %s", e.code(), e.name(), e.message()); } // process the set command bool do_set(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 5) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); const std::string& key = tokens[1]; uint32_t flags = kc::atoi(tokens[2].c_str()); int64_t xt = kc::atoi(tokens[3].c_str()); int64_t vsiz = kc::atoi(tokens[4].c_str()); bool norep = false; for (size_t i = 5; i < tokens.size(); i++) { if (tokens[i] == "noreply") norep = true; } if (xt < 1) { xt = kc::INT64MAX; } else if (xt > 1 << 24) { xt *= -1; } if (vsiz < 0 || vsiz > (int64_t)kt::RemoteDB::DATAMAXSIZ) return false; bool err = false; char* vbuf = new char[vsiz+sizeof(flags)]; if (sess->receive(vbuf, vsiz)) { int32_t c = sess->receive_byte(); if (c == '\r') c = sess->receive_byte(); if (c == '\n') { if (serv_->opts_ & TFLAGS) { kc::writefixnum(vbuf + vsiz, flags, sizeof(flags)); vsiz += sizeof(flags); } opcounts_[thid][CNTSET]++; if (db->set(key.data(), key.size(), vbuf, vsiz, xt)) { if (!norep && !sess->printf("STORED\r\n")) err = true; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); log_db_error(serv, e); if (!norep && !sess->printf("SERVER_ERROR DB::set failed\r\n")) err = true; } } else { err = true; } } else { err = true; } delete[] vbuf; return !err; } // process the add command bool do_add(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 5) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); const std::string& key = tokens[1]; uint32_t flags = kc::atoi(tokens[2].c_str()); int64_t xt = kc::atoi(tokens[3].c_str()); int64_t vsiz = kc::atoi(tokens[4].c_str()); bool norep = false; for (size_t i = 5; i < tokens.size(); i++) { if (tokens[i] == "noreply") norep = true; } if (xt < 1) { xt = kc::INT64MAX; } else if (xt > 1 << 24) { xt *= -1; } if (vsiz < 0 || vsiz > (int64_t)kt::RemoteDB::DATAMAXSIZ) return false; bool err = false; char* vbuf = new char[vsiz+sizeof(flags)]; if (sess->receive(vbuf, vsiz)) { int32_t c = sess->receive_byte(); if (c == '\r') c = sess->receive_byte(); if (c == '\n') { if (serv_->opts_ & TFLAGS) { kc::writefixnum(vbuf + vsiz, flags, sizeof(flags)); vsiz += sizeof(flags); } opcounts_[thid][CNTSET]++; if (db->add(key.data(), key.size(), vbuf, vsiz, xt)) { if (!norep && !sess->printf("STORED\r\n")) err = true; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); if (e == kc::BasicDB::Error::DUPREC) { if (!norep && !sess->printf("NOT_STORED\r\n")) err = true; } else { log_db_error(serv, e); if (!norep && !sess->printf("SERVER_ERROR DB::add failed\r\n")) err = true; } } } else { err = true; } } else { err = true; } delete[] vbuf; return !err; } // process the replace command bool do_replace(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 5) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); const std::string& key = tokens[1]; uint32_t flags = kc::atoi(tokens[2].c_str()); int64_t xt = kc::atoi(tokens[3].c_str()); int64_t vsiz = kc::atoi(tokens[4].c_str()); bool norep = false; for (size_t i = 5; i < tokens.size(); i++) { if (tokens[i] == "noreply") norep = true; } if (xt < 1) { xt = kc::INT64MAX; } else if (xt > 1 << 24) { xt *= -1; } if (vsiz < 0 || vsiz > (int64_t)kt::RemoteDB::DATAMAXSIZ) return false; bool err = false; char* vbuf = new char[vsiz+sizeof(flags)]; if (sess->receive(vbuf, vsiz)) { int32_t c = sess->receive_byte(); if (c == '\r') c = sess->receive_byte(); if (c == '\n') { if (serv_->opts_ & TFLAGS) { kc::writefixnum(vbuf + vsiz, flags, sizeof(flags)); vsiz += sizeof(flags); } opcounts_[thid][CNTSET]++; if (db->replace(key.data(), key.size(), vbuf, vsiz, xt)) { if (!norep && !sess->printf("STORED\r\n")) err = true; } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); if (e == kc::BasicDB::Error::NOREC) { if (!norep && !sess->printf("NOT_STORED\r\n")) err = true; } else { log_db_error(serv, e); if (!norep && !sess->printf("SERVER_ERROR DB::replace failed\r\n")) err = true; } } } else { err = true; } } else { err = true; } delete[] vbuf; return !err; } // process the get command bool do_get(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 1) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); bool err = false; std::vector::const_iterator it = tokens.begin(); std::vector::const_iterator itend = tokens.end(); ++it; std::string result; while (it != itend) { opcounts_[thid][CNTGET]++; size_t vsiz; char* vbuf = db->get(it->data(), it->size(), &vsiz); if (vbuf) { uint32_t flags = 0; if ((serv_->opts_ & TFLAGS) && vsiz >= sizeof(flags)) { flags = kc::readfixnum(vbuf + vsiz - sizeof(flags), sizeof(flags)); vsiz -= sizeof(flags); } kc::strprintf(&result, "VALUE %s %u %llu\r\n", it->c_str(), flags, (unsigned long long)vsiz); result.append(vbuf, vsiz); result.append("\r\n"); delete[] vbuf; } else { opcounts_[thid][CNTGETMISS]++; } ++it; } kc::strprintf(&result, "END\r\n"); if (!sess->send(result.data(), result.size())) err = true; return !err; } // process the delete command bool do_delete(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 2) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); const std::string& key = tokens[1]; bool norep = false; for (size_t i = 2; i < tokens.size(); i++) { if (tokens[i] == "noreply") norep = true; } bool err = false; opcounts_[thid][CNTDELETE]++; if (db->remove(key.data(), key.size())) { if (!norep && !sess->printf("DELETED\r\n")) err = true; } else { opcounts_[thid][CNTDELETEMISS]++; const kc::BasicDB::Error& e = db->error(); if (e == kc::BasicDB::Error::NOREC) { if (!norep && !sess->printf("NOT_FOUND\r\n")) err = true; } else { log_db_error(serv, e); if (!norep && !sess->printf("SERVER_ERROR DB::remove failed\r\n")) err = true; } } return !err; } // process the incr command bool do_incr(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 3) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); const std::string& key = tokens[1]; int64_t num = kc::atoi(tokens[2].c_str()); bool norep = false; for (size_t i = 3; i < tokens.size(); i++) { if (tokens[i] == "noreply") norep = true; } bool err = false; class Visitor : public kt::TimedDB::Visitor { public: explicit Visitor(int64_t num, uint8_t opts) : num_(num), opts_(opts), hit_(false), nbuf_() {} int64_t num() { return num_; } bool hit() { return hit_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { hit_ = true; if ((opts_ & TFLAGS) && vsiz >= sizeof(uint32_t)) { num_ += kc::atoin(vbuf, vsiz - sizeof(uint32_t)); if (num_ < 0) num_ = 0; size_t nsiz = std::sprintf(nbuf_, "%lld", (long long)num_); std::memcpy(nbuf_ + nsiz, vbuf + vsiz - sizeof(uint32_t), sizeof(uint32_t)); nsiz += sizeof(uint32_t); *sp = nsiz; } else { num_ += kc::atoin(vbuf, vsiz); if (num_ < 0) num_ = 0; *sp = std::sprintf(nbuf_, "%lld", (long long)num_); } *xtp = -*xtp; return nbuf_; } int64_t num_; uint8_t opts_; bool hit_; char nbuf_[kc::NUMBUFSIZ]; }; Visitor visitor(num, serv_->opts_); opcounts_[thid][CNTINCR]++; if (db->accept(key.data(), key.size(), &visitor, true)) { if (visitor.hit()) { if (!norep && !sess->printf("%lld\r\n", (long long)visitor.num())) err = true; } else { opcounts_[thid][CNTINCRMISS]++; if (!norep && !sess->printf("NOT_FOUND\r\n")) err = true; } } else { opcounts_[thid][CNTINCRMISS]++; const kc::BasicDB::Error& e = db->error(); log_db_error(serv, e); if (!norep && !sess->printf("SERVER_ERROR DB::accept failed\r\n")) err = true; } return !err; } // process the decr command bool do_decr(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 3) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); const std::string& key = tokens[1]; int64_t num = -kc::atoi(tokens[2].c_str()); bool norep = false; for (size_t i = 3; i < tokens.size(); i++) { if (tokens[i] == "noreply") norep = true; } bool err = false; class Visitor : public kt::TimedDB::Visitor { public: explicit Visitor(int64_t num, uint8_t opts) : num_(num), opts_(opts), hit_(false), nbuf_() {} int64_t num() { return num_; } bool hit() { return hit_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { hit_ = true; if ((opts_ & TFLAGS) && vsiz >= sizeof(uint32_t)) { num_ += kc::atoin(vbuf, vsiz - sizeof(uint32_t)); if (num_ < 0) num_ = 0; size_t nsiz = std::sprintf(nbuf_, "%lld", (long long)num_); std::memcpy(nbuf_ + nsiz, vbuf + vsiz - sizeof(uint32_t), sizeof(uint32_t)); nsiz += sizeof(uint32_t); *sp = nsiz; } else { num_ += kc::atoin(vbuf, vsiz); if (num_ < 0) num_ = 0; *sp = std::sprintf(nbuf_, "%lld", (long long)num_); } *xtp = -*xtp; return nbuf_; } int64_t num_; uint8_t opts_; bool hit_; char nbuf_[kc::NUMBUFSIZ]; }; Visitor visitor(num, serv_->opts_); opcounts_[thid][CNTDECR]++; if (db->accept(key.data(), key.size(), &visitor, true)) { if (visitor.hit()) { if (!norep && !sess->printf("%lld\r\n", (long long)visitor.num())) err = true; } else { opcounts_[thid][CNTDECRMISS]++; if (!norep && !sess->printf("NOT_FOUND\r\n")) err = true; } } else { opcounts_[thid][CNTDECRMISS]++; const kc::BasicDB::Error& e = db->error(); log_db_error(serv, e); if (!norep && !sess->printf("SERVER_ERROR DB::accept failed\r\n")) err = true; } return !err; } // process the stats command bool do_stats(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { if (tokens.size() < 1) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); bool err = false; std::string result; std::map status; if (db->status(&status)) { kc::strprintf(&result, "STAT pid %lld\r\n", (long long)kc::getpid()); double now = kc::time(); kc::strprintf(&result, "STAT uptime %lld\r\n", (long long)(now - serv_->stime_)); kc::strprintf(&result, "STAT time %lld\r\n", (long long)now); kc::strprintf(&result, "STAT version KyotoTycoon/%s\r\n", kt::VERSION); kc::strprintf(&result, "STAT pointer_size %d\r\n", (int)(sizeof(void*) * 8)); kc::strprintf(&result, "STAT curr_connections %d\r\n", (int)serv->connection_count()); kc::strprintf(&result, "STAT threads %d\r\n", (int)thnum_); kc::strprintf(&result, "STAT curr_items %lld\r\n", (long long)db->count()); kc::strprintf(&result, "STAT bytes %lld\r\n", (long long)db->size()); std::map::iterator it = status.begin(); std::map::iterator itend = status.end(); while (it != itend) { kc::strprintf(&result, "STAT db_%s %s\r\n", it->first.c_str(), it->second.c_str()); ++it; } OpCount ocsum; for (int32_t i = 0; i <= CNTFLUSH; i++) { ocsum[i] = 0; } for (int32_t i = 0; i < thnum_; i++) { for (int32_t j = 0; j <= CNTFLUSH; j++) { ocsum[j] += opcounts_[i][j]; } } kc::strprintf(&result, "STAT set_hits %lld\r\n", (long long)(ocsum[CNTSET] - ocsum[CNTSETMISS])); kc::strprintf(&result, "STAT set_misses %lld\r\n", (long long)ocsum[CNTSETMISS]); kc::strprintf(&result, "STAT get_hits %lld\r\n", (long long)(ocsum[CNTGET] - ocsum[CNTGETMISS])); kc::strprintf(&result, "STAT get_misses %lld\r\n", (long long)ocsum[CNTGETMISS]); kc::strprintf(&result, "STAT delete_hits %lld\r\n", (long long)(ocsum[CNTDELETE] - ocsum[CNTDELETEMISS])); kc::strprintf(&result, "STAT delete_misses %lld\r\n", (long long)ocsum[CNTDELETEMISS]); kc::strprintf(&result, "STAT incr_hits %lld\r\n", (long long)(ocsum[CNTINCR] - ocsum[CNTINCRMISS])); kc::strprintf(&result, "STAT incr_misses %lld\r\n", (long long)ocsum[CNTINCRMISS]); kc::strprintf(&result, "STAT decr_hits %lld\r\n", (long long)(ocsum[CNTDECR] - ocsum[CNTDECRMISS])); kc::strprintf(&result, "STAT decr_misses %lld\r\n", (long long)ocsum[CNTDECRMISS]); kc::strprintf(&result, "STAT cmd_set %lld\r\n", (long long)ocsum[CNTSET]); kc::strprintf(&result, "STAT cmd_get %lld\r\n", (long long)ocsum[CNTGET]); kc::strprintf(&result, "STAT cmd_delete %lld\r\n", (long long)ocsum[CNTDELETE]); kc::strprintf(&result, "STAT cmd_flush %lld\r\n", (long long)ocsum[CNTFLUSH]); kc::strprintf(&result, "END\r\n"); } else { const kc::BasicDB::Error& e = db->error(); log_db_error(serv, e); kc::strprintf(&result, "SERVER_ERROR DB::status failed\r\n"); } if (!sess->send(result.data(), result.size())) err = true; return !err; } // process the flush_all command bool do_flush_all(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 1) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); bool norep = false; for (size_t i = 1; i < tokens.size(); i++) { if (tokens[i] == "noreply") norep = true; } bool err = false; opcounts_[thid][CNTFLUSH]++; std::map status; if (db->clear()) { if (!norep && !sess->printf("OK\r\n")) err = true; } else { const kc::BasicDB::Error& e = db->error(); log_db_error(serv, e); if (!norep && !sess->printf("SERVER_ERROR DB::clear failed\r\n")) err = true; } return !err; } // process the version command bool do_version(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { if (tokens.size() < 1) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); bool err = false; if (!sess->printf("VERSION KyotoTycoon/%s\r\n", kt::VERSION)) err = true; return !err; } // process the set command for message queue bool do_queue_set(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 5) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); const std::string& key = tokens[1]; uint32_t flags = kc::atoi(tokens[2].c_str()); int64_t xt = kc::atoi(tokens[3].c_str()); int64_t vsiz = kc::atoi(tokens[4].c_str()); bool norep = false; for (size_t i = 5; i < tokens.size(); i++) { if (tokens[i] == "noreply") norep = true; } if (xt < 1) { xt = kc::INT64MAX; } else if (xt > 1 << 24) { xt *= -1; } if (vsiz < 0 || vsiz > (int64_t)kt::RemoteDB::DATAMAXSIZ) return false; std::string msgkey = key; char suffix[kc::NUMBUFSIZ*2]; size_t ssiz = std::sprintf(suffix, " %014.0f %04d", kc::time() * 1000, (int)serv_->seq_.add(1) % 10000); msgkey.append(suffix, ssiz); bool err = false; char* vbuf = new char[vsiz+sizeof(flags)]; if (sess->receive(vbuf, vsiz)) { int32_t c = sess->receive_byte(); if (c == '\r') c = sess->receive_byte(); if (c == '\n') { if (serv_->opts_ & TFLAGS) { kc::writefixnum(vbuf + vsiz, flags, sizeof(flags)); vsiz += sizeof(flags); } opcounts_[thid][CNTSET]++; if (db->set(msgkey.data(), msgkey.size(), vbuf, vsiz, xt)) { if (!norep && !sess->printf("STORED\r\n")) err = true; serv_->cond_.broadcast(key); } else { opcounts_[thid][CNTSETMISS]++; const kc::BasicDB::Error& e = db->error(); log_db_error(serv, e); if (!norep && !sess->printf("SERVER_ERROR DB::set failed\r\n")) err = true; } } else { err = true; } } else { err = true; } delete[] vbuf; return !err; } // process the get command for message queue bool do_queue_get(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 2) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); bool err = false; SLS* sls = SLS::create(db, sess); kt::TimedDB::Cursor* cur = db->cursor(); std::string result; double etime = kc::time() + serv_->qtout_; double wtime = serv_->qtout_ < 1.0 ? serv_->qtout_ : 1.0; std::vector::const_iterator it = tokens.begin(); std::vector::const_iterator itend = tokens.end(); ++it; while (it != itend) { const std::string& key = *it; const std::string& prefix = key + " "; opcounts_[thid][CNTGET]++; while (true) { if (cur->jump(prefix)) { std::string rkey; if (cur->get_key(&rkey) && kc::strfwm(rkey.c_str(), prefix.c_str())) { std::string rvalue; if (db->seize(rkey, &rvalue)) { sls->recs_[rkey] = rvalue; const char* vbuf = rvalue.data(); size_t vsiz = rvalue.size(); uint32_t flags = 0; if ((serv_->opts_ & TFLAGS) && vsiz >= sizeof(flags)) { flags = kc::readfixnum(vbuf + vsiz - sizeof(flags), sizeof(flags)); vsiz -= sizeof(flags); } kc::strprintf(&result, "VALUE %s %u %llu\r\n", key.c_str(), flags, (unsigned long long)vsiz); result.append(vbuf, vsiz); result.append("\r\n"); break; } } } if (serv->aborted() || kc::time() > etime) { opcounts_[thid][CNTGETMISS]++; break; } serv_->cond_.wait(key, wtime); } ++it; } delete cur; kc::strprintf(&result, "END\r\n"); if (!sess->send(result.data(), result.size())) err = true; return !err; } // process the delete command for message queue bool do_queue_delete(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess, const std::vector& tokens, kt::TimedDB* db) { uint32_t thid = sess->thread_id(); if (tokens.size() < 2) return sess->printf("CLIENT_ERROR invalid parameters\r\n"); bool err = false; const std::string& key = tokens[1]; bool norep = false; for (size_t i = 2; i < tokens.size(); i++) { if (tokens[i] == "noreply") norep = true; } const std::string& prefix = key + " "; opcounts_[thid][CNTDELETE]++; SLS* sls = SLS::create(db, sess); std::map::iterator rit = sls->recs_.lower_bound(prefix); if (rit == sls->recs_.end() || !kc::strfwm(rit->first.c_str(), prefix.c_str())) { opcounts_[thid][CNTDELETEMISS]++; if (!norep && !sess->printf("NOT_FOUND\r\n")) err = true; } else { sls->recs_.erase(rit); if (!norep && !sess->printf("DELETED\r\n")) err = true; } return !err; } MemcacheServer* serv_; int32_t thnum_; OpCount* opcounts_; }; // session local storage class SLS : public kt::RPCServer::Session::Data { friend class Worker; private: SLS(kt::TimedDB* db) : db_(db), recs_() {} ~SLS() { std::map::iterator it = recs_.begin(); std::map::iterator itend = recs_.end(); while (it != itend) { db_->set(it->first, it->second); ++it; } } static SLS* create(kt::TimedDB* db, kt::ThreadedServer::Session* sess) { SLS* sls = (SLS*)sess->data(); if (!sls) { sls = new SLS(db); sess->set_data(sls); } return sls; } kt::TimedDB* db_; std::map recs_; }; kt::TimedDB* dbary_; size_t dbnum_; kt::ThreadedServer::Logger* logger_; uint32_t logkinds_; std::string expr_; std::string host_; int32_t port_; double tout_; int32_t thnum_; uint8_t opts_; double qtout_; double stime_; kc::AtomicInt64 seq_; kc::CondMap cond_; kt::ThreadedServer serv_; Worker* worker_; }; // initializer called by the main server extern "C" void* ktservinit() { return new MemcacheServer; } // END OF FILE kyototycoon-0.9.56/Makefile.in0000644000175000017500000005534711611545447015311 0ustar mikiomikio# Makefile for Kyoto Tycoon #================================================================ # Setting Variables #================================================================ # Generic settings SHELL = @SHELL@ # Package information PACKAGE = @PACKAGE_NAME@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ VERSION = @PACKAGE_VERSION@ PACKAGEDIR = $(PACKAGE)-$(VERSION) PACKAGETGZ = $(PACKAGE)-$(VERSION).tar.gz LIBVER = @MYLIBVER@ LIBREV = @MYLIBREV@ # Targets HEADERFILES = @MYHEADERFILES@ LIBRARYFILES = @MYLIBRARYFILES@ LIBOBJFILES = @MYLIBOBJFILES@ SHLIBFILES = @MYSHLIBFILES@ COMMANDFILES = @MYCOMMANDFILES@ MAN1FILES = @MYMAN1FILES@ DOCUMENTFILES = @MYDOCUMENTFILES@ PCFILES = @MYPCFILES@ # Install destinations prefix = @prefix@ exec_prefix = @exec_prefix@ datarootdir = @datarootdir@ INCLUDEDIR = @includedir@ LIBDIR = @libdir@ BINDIR = @bindir@ LIBEXECDIR = @libexecdir@ DATADIR = @datadir@/$(PACKAGE) MAN1DIR = @mandir@/man1 DOCDIR = @docdir@ PCDIR = @libdir@/pkgconfig DESTDIR = # Building configuration CC = @CC@ CXX = @CXX@ CPPFLAGS = @MYCPPFLAGS@ \ -D_KT_PREFIX="\"$(prefix)\"" -D_KT_INCLUDEDIR="\"$(INCLUDEDIR)\"" \ -D_KT_LIBDIR="\"$(LIBDIR)\"" -D_KT_BINDIR="\"$(BINDIR)\"" -D_KT_LIBEXECDIR="\"$(LIBEXECDIR)\"" \ -D_KT_APPINC="\"-I$(INCLUDEDIR)\"" -D_KT_APPLIBS="\"-L$(LIBDIR) -lkyototycoon @LIBS@\"" CFLAGS = @MYCFLAGS@ CXXFLAGS = @MYCXXFLAGS@ LDFLAGS = @MYLDFLAGS@ CMDLDFLAGS = @MYCMDLDFLAGS@ CMDLIBS = @MYCMDLIBS@ LIBS = @LIBS@ RUNENV = @MYLDLIBPATHENV@=@MYLDLIBPATH@ POSTCMD = @MYPOSTCMD@ #================================================================ # Suffix rules #================================================================ .SUFFIXES : .SUFFIXES : .c .cc .o .c.o : $(CC) -c $(CPPFLAGS) $(CFLAGS) $< .cc.o : $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< #================================================================ # Actions #================================================================ all : $(LIBRARYFILES) $(SHLIBFILES) $(COMMANDFILES) @$(POSTCMD) @printf '\n' @printf '#================================================================\n' @printf '# Ready to install.\n' @printf '#================================================================\n' clean : rm -rf $(LIBRARYFILES) $(LIBOBJFILES) $(SHLIBFILES) $(COMMANDFILES) $(CGIFILES) \ *.o *.gch a.out check.in check.out gmon.out *.log *.vlog words.tsv \ casket* *.kch *.kct *.kcd *.kcf *.wal *.tmpkc* *.kcss *.ktss *.pid *-ulog *.rts \ *~ hoge moge tako ika version : sed -e 's/_KT_VERSION.*/_KT_VERSION "$(VERSION)"/' \ -e "s/_KT_LIBVER.*/_KT_LIBVER $(LIBVER)/" \ -e "s/_KT_LIBREV.*/_KT_LIBREV $(LIBREV)/" myconf.h > myconf.h~ [ -f myconf.h~ ] && mv -f myconf.h~ myconf.h untabify : ls *.cc *.h *.idl | while read name ; \ do \ sed -e 's/\t/ /g' -e 's/ *$$//' $$name > $$name~; \ [ -f $$name~ ] && mv -f $$name~ $$name ; \ done install : mkdir -p $(DESTDIR)$(INCLUDEDIR) cp -Rf $(HEADERFILES) $(DESTDIR)$(INCLUDEDIR) mkdir -p $(DESTDIR)$(LIBDIR) cp -Rf $(LIBRARYFILES) $(DESTDIR)$(LIBDIR) mkdir -p $(DESTDIR)$(LIBEXECDIR) cp -Rf $(SHLIBFILES) $(DESTDIR)$(LIBEXECDIR) mkdir -p $(DESTDIR)$(BINDIR) cp -Rf $(COMMANDFILES) $(DESTDIR)$(BINDIR) mkdir -p $(DESTDIR)$(MAN1DIR) cd man && cp -Rf $(MAN1FILES) $(DESTDIR)$(MAN1DIR) mkdir -p $(DESTDIR)$(DOCDIR) cp -Rf $(DOCUMENTFILES) $(DESTDIR)$(DOCDIR) mkdir -p $(DESTDIR)$(PCDIR) cp -Rf $(PCFILES) $(DESTDIR)$(PCDIR) @printf '\n' @printf '#================================================================\n' @printf '# Thanks for using Kyoto Tycoon.\n' @printf '#================================================================\n' install-strip : $(MAKE) DESTDIR=$(DESTDIR) install cd $(DESTDIR)$(BINDIR) && strip $(COMMANDFILES) uninstall : -cd $(DESTDIR)$(INCLUDEDIR) && rm -f $(HEADERFILES) -cd $(DESTDIR)$(LIBDIR) && rm -f $(LIBRARYFILES) -cd $(DESTDIR)$(LIBEXECDIR) && rm -f $(SHLIBFILES) -cd $(DESTDIR)$(BINDIR) && rm -f $(COMMANDFILES) -cd $(DESTDIR)$(MAN1DIR) && rm -f $(MAN1FILES) -cd $(DESTDIR)$(DOCDIR) && rm -rf $(DOCUMENTFILES) && rmdir $(DOCDIR) -cd $(DESTDIR)$(PCDIR) && rm -f $(PCFILES) dist : $(MAKE) version $(MAKE) untabify $(MAKE) distclean cd .. && tar cvf - $(PACKAGEDIR) | gzip -c > $(PACKAGETGZ) sync ; sync distclean : clean cd example && $(MAKE) clean rm -rf Makefile kyototycoon.pc \ config.cache config.log config.status config.tmp autom4te.cache check : $(MAKE) check-util $(MAKE) check-timed rm -rf casket* *-ulog @printf '\n' @printf '#================================================================\n' @printf '# Checking completed.\n' @printf '#================================================================\n' check-util : rm -rf casket* *-ulog $(RUNENV) $(RUNCMD) ./ktutilmgr version $(RUNENV) $(RUNCMD) ./ktutilmgr date -ds '1978-02-11T18:05:00+09:00' -wf $(RUNENV) $(RUNCMD) ./ktutilmgr date -ds '1977-10-07T12:00:00+09:00' -rf rm -rf *-ulog $(RUNENV) $(RUNCMD) ./ktutiltest ulog -ulim 100k 0001-ulog 50000 rm -rf *-ulog $(RUNENV) $(RUNCMD) ./ktutiltest ulog -th 4 -ulim 100k 0001-ulog 50000 $(RUNENV) $(RUNCMD) ./ktutiltest ulog -th 2 -ulim 100k 0001-ulog 50000 $(RUNENV) $(RUNCMD) ./ktutilmgr ulog -ts 1234 0001-ulog > check.out $(RUNENV) $(RUNCMD) ./ktutilmgr ulog -ts 1234 -uf 0001-ulog > check.out check-timed : rm -rf casket* *-ulog $(RUNENV) $(RUNCMD) ./kttimedmgr create -otr "casket.kch#apow=1#fpow=2#bnum=3" $(RUNENV) $(RUNCMD) ./kttimedmgr inform -st casket.kch $(RUNENV) $(RUNCMD) ./kttimedmgr set -add -xt 3600 casket.kch duffy 1231 $(RUNENV) $(RUNCMD) ./kttimedmgr set -add -xt 3600 casket.kch micky 0101 $(RUNENV) $(RUNCMD) ./kttimedmgr set -xt 3600 casket.kch fal 1007 $(RUNENV) $(RUNCMD) ./kttimedmgr set -xt 3600 casket.kch mikio 0211 $(RUNENV) $(RUNCMD) ./kttimedmgr set -xt 3600 casket.kch natsuki 0810 $(RUNENV) $(RUNCMD) ./kttimedmgr set -xt 3600 casket.kch micky "" $(RUNENV) $(RUNCMD) ./kttimedmgr set -app -xt 3600 casket.kch duffy kukuku $(RUNENV) $(RUNCMD) ./kttimedmgr remove casket.kch micky $(RUNENV) $(RUNCMD) ./kttimedmgr list -pv -pt casket.kch > check.out $(RUNENV) $(RUNCMD) ./kttimedmgr copy casket.kch casket-para $(RUNENV) $(RUNCMD) ./kttimedmgr dump casket.kch check.out $(RUNENV) $(RUNCMD) ./kttimedmgr load -otr casket.kch check.out $(RUNENV) $(RUNCMD) ./kttimedmgr set -xt -9876543210 casket.kch ryu 1 $(RUNENV) $(RUNCMD) ./kttimedmgr set -xt -9876543210 casket.kch ken 2 $(RUNENV) $(RUNCMD) ./kttimedmgr remove casket.kch duffy $(RUNENV) $(RUNCMD) ./kttimedmgr set -xt 3600 casket.kch ryu syo-ryu-ken $(RUNENV) $(RUNCMD) ./kttimedmgr set -xt 3600 casket.kch ken tatsumaki-senpu-kyaku $(RUNENV) $(RUNCMD) ./kttimedmgr set -inci -xt 3600 casket.kch int 1234 $(RUNENV) $(RUNCMD) ./kttimedmgr set -inci -xt 3600 casket.kch int 5678 $(RUNENV) $(RUNCMD) ./kttimedmgr set -incd -xt 3600 casket.kch double 1234.5678 $(RUNENV) $(RUNCMD) ./kttimedmgr set -incd -xt 3600 casket.kch double 8765.4321 $(RUNENV) $(RUNCMD) ./kttimedmgr get -pt casket.kch mikio $(RUNENV) $(RUNCMD) ./kttimedmgr get -pt casket.kch ryu $(RUNENV) $(RUNCMD) ./kttimedmgr import -xt 60 casket.kch lab/numbers.tsv $(RUNENV) $(RUNCMD) ./kttimedmgr list -pv -pt -px "casket.kch#mode=r" > check.out $(RUNENV) $(RUNCMD) ./kttimedmgr vacuum -onl casket.kch $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kch $(RUNENV) $(RUNCMD) ./kttimedmgr inform -st casket.kch $(RUNENV) $(RUNCMD) ./kttimedmgr create -otr -otl -onr \ "casket.kct#apow=1#fpow=3#opts=slc#bnum=1" $(RUNENV) $(RUNCMD) ./kttimedmgr import -xt 60 casket.kct < lab/numbers.tsv $(RUNENV) $(RUNCMD) ./kttimedmgr set casket.kct mikio kyotocabinet $(RUNENV) $(RUNCMD) ./kttimedmgr set -app casket.kct tako ikaunini $(RUNENV) $(RUNCMD) ./kttimedmgr set -app casket.kct mikio kyototyrant $(RUNENV) $(RUNCMD) ./kttimedmgr set -app casket.kct mikio kyotodystopia $(RUNENV) $(RUNCMD) ./kttimedmgr get -px casket.kct mikio > check.out $(RUNENV) $(RUNCMD) ./kttimedmgr list casket.kct > check.out $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedmgr clear casket.kct rm -rf casket* $(RUNENV) $(RUNCMD) ./kttimedtest order -set "casket.kct#bnum=5000#msiz=50000" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest order -get "casket.kct#msiz=50000" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest order -getw "casket.kct#msiz=5000" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest order -rem "casket.kct#msiz=50000" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest order "casket.kct#bnum=5000#msiz=50000" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest order -etc \ "casket.kct#bnum=5000#msiz=50000#dfunit=4" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest order -th 4 \ "casket.kct#bnum=5000#msiz=50000#dfunit=4" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest order -th 4 -rnd -etc \ "casket.kct#bnum=5000#msiz=0#dfunit=1" 1000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest order -th 4 -rnd -etc -tran \ "casket.kct#bnum=5000#msiz=0#dfunit=2" 1000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest order -th 4 -rnd -etc -oat \ "casket.kct#bnum=5000#msiz=0#dfunit=3" 1000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest order -th 4 -rnd -etc \ "casket.kct#apow=2#fpow=3#opts=slc#bnum=5000#msiz=0#dfunit=4" 1000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest queue \ "casket.kct#bnum=5000#msiz=0" 10000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest queue -rnd \ "casket.kct#bnum=5000#msiz=0" 10000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest queue -th 4 -it 4 \ "casket.kct#bnum=5000#msiz=0" 10000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest queue -th 4 -it 4 -rnd \ "casket.kct#bnum=5000#msiz=0" 10000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest wicked "casket.kct#bnum=5000#msiz=0" 1000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest wicked -th 4 -it 4 \ "casket.kct#bnum=5000#msiz=0#dfunit=1" 1000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest wicked -th 4 -it 4 -oat \ "casket.kct#bnum=5000#msiz=0#dfunit=1" 1000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest wicked -th 4 -it 4 \ "casket.kct#apow=2#fpow=3#opts=slc#bnum=10000#msiz=0#dfunit=1" 10000 $(RUNENV) $(RUNCMD) ./kttimedmgr check -onr casket.kct $(RUNENV) $(RUNCMD) ./kttimedtest tran casket.kct 10000 $(RUNENV) $(RUNCMD) ./kttimedtest tran -th 2 -it 4 casket.kct 10000 $(RUNENV) $(RUNCMD) ./kttimedtest tran -th 2 -it 4 \ "casket.kct#apow=2#fpow=3#opts=slc#bnum=10000#msiz=0#dfunit=1" 1000 $(RUNENV) $(RUNCMD) ./kttimedtest mapred -dbnum 2 -clim 10k casket.kct 10000 $(RUNENV) $(RUNCMD) ./kttimedtest mapred -tmp . -dbnum 2 -clim 10k -xnl -xnc \ casket.kct 10000 $(RUNENV) $(RUNCMD) ./kttimedtest mapred -tmp . -dbnum 2 -clim 10k -xpm -xpr -xpf -xnc \ casket.kct 10000 $(RUNENV) $(RUNCMD) ./kttimedtest mapred -rnd -dbnum 2 -clim 10k casket.kct 10000 rm -rf casket* $(RUNENV) $(RUNCMD) ./kttimedtest order -rnd "casket.kcx" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest order -th 4 -rnd "casket.kcx" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest wicked "casket.kcx" 10000 $(RUNENV) $(RUNCMD) ./kttimedtest wicked -th 4 "casket.kcx" 10000 $(RUNENV) $(RUNCMD) ./kttimedmgr list -pv "casket.kcx" > check.out $(RUNENV) $(RUNCMD) ./kttimedmgr list -max 1000 -pv "casket.kcx" > check.out $(RUNENV) $(RUNCMD) ./kttimedtest mapred casket.kcx 10000 rm -rf casket* $(RUNENV) $(RUNCMD) ./kttimedtest order -rnd "casket.kch#opts=s#bnum=256" 1000 $(RUNENV) $(RUNCMD) ./kttimedtest order -rnd "casket.kct#opts=l#psiz=256" 1000 $(RUNENV) $(RUNCMD) ./kttimedtest order -rnd "casket.kcd#opts=c#bnum=256" 1000 $(RUNENV) $(RUNCMD) ./kttimedtest order -rnd "casket.kcf#opts=c#psiz=256" 1000 $(RUNENV) $(RUNCMD) ./kttimedtest order -rnd "casket.kcx" 1000 $(RUNENV) $(RUNCMD) ./kttimedmgr merge -add "casket#type=kct" \ casket.kch casket.kct casket.kcd casket.kcf casket.kcx rm -rf casket* $(RUNENV) $(RUNCMD) ./kttimedtest misc "casket#type=-" $(RUNENV) $(RUNCMD) ./kttimedtest misc "casket#type=+" $(RUNENV) $(RUNCMD) ./kttimedtest misc "casket#type=:" $(RUNENV) $(RUNCMD) ./kttimedtest misc "casket#type=*#zcomp=def" $(RUNENV) $(RUNCMD) ./kttimedtest misc "casket#type=%#zcomp=gz" rm -rf casket* $(RUNENV) $(RUNCMD) ./kttimedtest misc \ "casket#type=kch#log=-#logkinds=debug#zcomp=lzocrc" rm -rf casket* $(RUNENV) $(RUNCMD) ./kttimedtest misc \ "casket#type=kct#log=-#logkinds=debug#zcomp=lzmacrc" rm -rf casket* $(RUNENV) $(RUNCMD) ./kttimedtest misc \ "casket#type=kcd#zcomp=arc#zkey=mikio" rm -rf casket* $(RUNENV) $(RUNCMD) ./kttimedtest misc \ "casket#type=kcf#zcomp=arc#zkey=mikio" rm -rf casket* $(RUNENV) $(RUNCMD) ./kttimedtest order -set -th 4 -rnd \ 'casket.kch#bnum=100#ktcapcnt=5000' 10000 $(RUNENV) $(RUNCMD) ./kttimedtest order -set -th 4 -rnd \ 'casket.kch#bnum=100#ktcapsiz=200000' 10000 rm -rf casket* *-ulog $(RUNENV) $(RUNCMD) ./kttimedmgr create -ulog 0001-ulog -sid 1 -dbid 0 \ casket-0001.kch $(RUNENV) $(RUNCMD) ./kttimedmgr set -ulog 0001-ulog -sid 1 -dbid 0 \ casket-0001.kch abc defg $(RUNENV) $(RUNCMD) ./kttimedmgr set -ulog 0001-ulog -sid 1 -dbid 0 \ casket-0001.kch hij klmn $(RUNENV) $(RUNCMD) ./kttimedmgr clear -ulog 0001-ulog -sid 1 -dbid 0 \ casket-0001.kch $(RUNENV) $(RUNCMD) ./kttimedmgr set -ulog 0001-ulog -sid 1 -dbid 0 \ casket-0001.kch tako ika $(RUNENV) $(RUNCMD) ./kttimedmgr set -ulog 0001-ulog -sid 1 -dbid 0 \ casket-0001.kch uni kani $(RUNENV) $(RUNCMD) ./kttimedmgr set -ulog 0001-ulog -sid 1 -dbid 0 \ casket-0001.kch ebi ikura $(RUNENV) $(RUNCMD) ./kttimedmgr remove -ulog 0001-ulog -sid 1 -dbid 0 \ casket-0001.kch uni $(RUNENV) $(RUNCMD) ./ktutilmgr ulog 0001-ulog $(RUNENV) $(RUNCMD) ./kttimedmgr create -ulog 0002-ulog -sid 2 -dbid 0 \ casket-0002.kch $(RUNENV) $(RUNCMD) ./kttimedmgr recover -ulog 0002-ulog -sid 2 -dbid 0 \ casket-0002.kch 0001-ulog $(RUNENV) $(RUNCMD) ./kttimedmgr set -ulog 0002-ulog -sid 2 -dbid 0 \ casket-0002.kch new NEWBY $(RUNENV) $(RUNCMD) ./ktutilmgr ulog 0002-ulog $(RUNENV) $(RUNCMD) ./kttimedmgr get casket-0002.kch tako $(RUNENV) $(RUNCMD) ./kttimedmgr get casket-0002.kch ebi $(RUNENV) $(RUNCMD) ./kttimedmgr get casket-0002.kch new check-remote : $(RUNENV) $(RUNCMD) ./ktremotemgr report $(RUNENV) $(RUNCMD) ./ktremotemgr inform -st $(RUNENV) $(RUNCMD) ./ktremotemgr clear $(RUNENV) $(RUNCMD) ./ktremotemgr set -add -xt 3600 duffy 1231 $(RUNENV) $(RUNCMD) ./ktremotemgr set -add -xt 3600 micky 0101 $(RUNENV) $(RUNCMD) ./ktremotemgr set -xt 3600 fal 1007 $(RUNENV) $(RUNCMD) ./ktremotemgr set -xt 3600 mikio 0211 $(RUNENV) $(RUNCMD) ./ktremotemgr set -xt 3600 natsuki 0810 $(RUNENV) $(RUNCMD) ./ktremotemgr set -xt 3600 micky "" $(RUNENV) $(RUNCMD) ./ktremotemgr set -app -xt 3600 duffy kukuku $(RUNENV) $(RUNCMD) ./ktremotemgr remove micky $(RUNENV) $(RUNCMD) ./ktremotemgr list -pv -pt > check.out $(RUNENV) $(RUNCMD) ./ktremotemgr set -xt -9876543210 ryu 1 $(RUNENV) $(RUNCMD) ./ktremotemgr set -xt -9876543210 ken 2 $(RUNENV) $(RUNCMD) ./ktremotemgr remove duffy $(RUNENV) $(RUNCMD) ./ktremotemgr set -xt 3600 ryu syo-ryu-ken $(RUNENV) $(RUNCMD) ./ktremotemgr set -xt 3600 ken tatsumaki-senpu-kyaku $(RUNENV) $(RUNCMD) ./ktremotemgr set -inci -xt 3600 int 1234 $(RUNENV) $(RUNCMD) ./ktremotemgr set -inci -xt 3600 int 5678 $(RUNENV) $(RUNCMD) ./ktremotemgr set -incd -xt 3600 double 1234.5678 $(RUNENV) $(RUNCMD) ./ktremotemgr set -incd -xt 3600 double 8765.4321 $(RUNENV) $(RUNCMD) ./ktremotemgr get -pt mikio $(RUNENV) $(RUNCMD) ./ktremotemgr get -pt ryu $(RUNENV) $(RUNCMD) ./ktremotemgr import -xt 60 lab/numbers.tsv $(RUNENV) $(RUNCMD) ./ktremotemgr vacuum -step 4 $(RUNENV) $(RUNCMD) ./ktremotemgr vacuum $(RUNENV) $(RUNCMD) ./ktremotemgr setbulk aa aaa bb bbb cc ccc dd ddd $(RUNENV) $(RUNCMD) ./ktremotemgr setbulk -bin AA AAA BB BBB CC CCC DD DDD $(RUNENV) $(RUNCMD) ./ktremotemgr removebulk aa bb zz $(RUNENV) $(RUNCMD) ./ktremotemgr removebulk -bin AA BB ZZ $(RUNENV) $(RUNCMD) ./ktremotemgr getbulk aa bb cc dd $(RUNENV) $(RUNCMD) ./ktremotemgr getbulk -bin AA BB CC DD $(RUNENV) $(RUNCMD) ./ktremotetest order 10000 $(RUNENV) $(RUNCMD) ./ktremotetest order -rnd 10000 $(RUNENV) $(RUNCMD) ./ktremotetest order -etc 10000 $(RUNENV) $(RUNCMD) ./ktremotetest order -rnd -etc 10000 $(RUNENV) $(RUNCMD) ./ktremotetest order -th 4 10000 $(RUNENV) $(RUNCMD) ./ktremotetest order -th 4 -rnd 10000 $(RUNENV) $(RUNCMD) ./ktremotetest order -th 4 -etc 10000 $(RUNENV) $(RUNCMD) ./ktremotetest order -th 4 -rnd -etc 10000 $(RUNENV) $(RUNCMD) ./ktremotetest bulk -bulk 10 10000 $(RUNENV) $(RUNCMD) ./ktremotetest bulk -rnd -bulk 10 10000 $(RUNENV) $(RUNCMD) ./ktremotetest bulk -bin -bulk 10 10000 $(RUNENV) $(RUNCMD) ./ktremotetest bulk -bin -rnd -bulk 10 -bnr 10000 $(RUNENV) $(RUNCMD) ./ktremotetest bulk -th 4 -bulk 10 10000 $(RUNENV) $(RUNCMD) ./ktremotetest bulk -th 4 -rnd -bulk 10 10000 $(RUNENV) $(RUNCMD) ./ktremotetest bulk -th 4 -bin -bulk 10 10000 $(RUNENV) $(RUNCMD) ./ktremotetest bulk -th 4 -bin -rnd -bulk 10 -bnr 10000 $(RUNENV) $(RUNCMD) ./ktremotetest wicked 10000 $(RUNENV) $(RUNCMD) ./ktremotetest wicked -it 4 10000 $(RUNENV) $(RUNCMD) ./ktremotetest wicked -th 4 -it 4 10000 $(RUNENV) $(RUNCMD) ./ktremotetest usual -th 4 10000 $(RUNENV) $(RUNCMD) ./ktremotetest usual -th 4 -kp 1000 -vs 2048 -xt -3 -iv 0.3 10000 check-heavy : $(MAKE) check-timed-heavy check-timed-heavy : rm -rf casket* *-ulog $(RUNENV) ./kttimedtest order -th 1 -rnd -set 'casket.kch' 4000000 $(RUNENV) ./kttimedtest order -th 4 -rnd -set 'casket.kch' 1000000 $(RUNENV) ./kttimedtest order -th 4 -rnd -set 'casket.kch#dfunit=8' 1000000 $(RUNENV) kcpolymgr check -onr 'casket.kch' $(RUNENV) ./kttimedtest order -th 1 -rnd -set 'casket.kct' 4000000 $(RUNENV) ./kttimedtest order -th 4 -rnd -set 'casket.kct' 1000000 $(RUNENV) ./kttimedtest order -th 4 -rnd -set 'casket.kct#dfunit=8' 1000000 $(RUNENV) kcpolymgr check -onr 'casket.kct' doc : $(MAKE) docclean mkdir -p doc/api doxygen mkdir -p doc/luadoc luadoc -d doc/luadoc --nofiles kyototycoon-doc.lua find doc/luadoc -type f -name '*.html' | \ while read name ; do \ sed -e 's/.*<\/title>/<title>Kyoto Tycoon<\/title>/' \ -e 's/.*validator\.w3\.org.*/Kyoto Tycoon Manual/' $$name > $$name~ ; \ [ -f $$name~ ] && mv -f $$name~ $$name ; \ done lua lab/docrefine.lua docclean : rm -rf doc/api doc/luadoc .PHONY : all clean install check doc #================================================================ # Building binaries #================================================================ libkyototycoon.a : $(LIBOBJFILES) $(AR) $(ARFLAGS) $@ $(LIBOBJFILES) libkyototycoon.so.$(LIBVER).$(LIBREV).0 : $(LIBOBJFILES) if uname -a | egrep -i 'SunOS' > /dev/null ; \ then \ $(CXX) $(CXXFLAGS) -shared -Wl,-G,-h,libkyototycoon.so.$(LIBVER) -o $@ \ $(LIBOBJFILES) $(LDFLAGS) $(LIBS) ; \ else \ $(CXX) $(CXXFLAGS) -shared -Wl,-soname,libkyototycoon.so.$(LIBVER) -o $@ \ $(LIBOBJFILES) $(LDFLAGS) $(LIBS) ; \ fi libkyototycoon.so.$(LIBVER) : libkyototycoon.so.$(LIBVER).$(LIBREV).0 ln -f -s libkyototycoon.so.$(LIBVER).$(LIBREV).0 $@ libkyototycoon.so : libkyototycoon.so.$(LIBVER).$(LIBREV).0 ln -f -s libkyototycoon.so.$(LIBVER).$(LIBREV).0 $@ libkyototycoon.$(LIBVER).$(LIBREV).0.dylib : $(LIBOBJFILES) $(CXX) $(CXXFLAGS) -dynamiclib -o $@ \ -install_name $(LIBDIR)/libkyototycoon.$(LIBVER).dylib \ -current_version $(LIBVER).$(LIBREV).0 -compatibility_version $(LIBVER) \ $(LIBOBJFILES) $(LDFLAGS) $(LIBS) libkyototycoon.$(LIBVER).dylib : libkyototycoon.$(LIBVER).$(LIBREV).0.dylib ln -f -s libkyototycoon.$(LIBVER).$(LIBREV).0.dylib $@ libkyototycoon.dylib : libkyototycoon.$(LIBVER).$(LIBREV).0.dylib ln -f -s libkyototycoon.$(LIBVER).$(LIBREV).0.dylib $@ ktplugservmemc.so : ktplugservmemc.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -shared -o $@ $< $(LDFLAGS) -lkyototycoon $(LIBS) ktplugservmemc.dylib : ktplugservmemc.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -dynamiclib -o $@ $< $(LDFLAGS) -lkyototycoon $(LIBS) ktplugdbvoid.so : ktplugdbvoid.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -shared -o $@ $< $(LDFLAGS) -lkyototycoon $(LIBS) ktplugdbvoid.dylib : ktplugdbvoid.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -dynamiclib -o $@ $< $(LDFLAGS) -lkyototycoon $(LIBS) ktutiltest : ktutiltest.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(CMDLDFLAGS) -lkyototycoon $(CMDLIBS) ktutilmgr : ktutilmgr.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(CMDLDFLAGS) -lkyototycoon $(CMDLIBS) ktutilserv : ktutilserv.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(CMDLDFLAGS) -lkyototycoon $(CMDLIBS) kttimedtest : kttimedtest.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(CMDLDFLAGS) -lkyototycoon $(CMDLIBS) kttimedmgr : kttimedmgr.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(CMDLDFLAGS) -lkyototycoon $(CMDLIBS) ktserver : ktserver.o myscript.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -o $@ $< myscript.o \ $(LDFLAGS) $(CMDLDFLAGS) -lkyototycoon $(CMDLIBS) ktremotetest : ktremotetest.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(CMDLDFLAGS) -lkyototycoon $(CMDLIBS) ktremotemgr : ktremotemgr.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -o $@ $< $(LDFLAGS) $(CMDLDFLAGS) -lkyototycoon $(CMDLIBS) ktutil.o : ktcommon.h ktutil.h myconf.h ktsocket.o : ktcommon.h ktutil.h ktsocket.h myconf.h ktthserv.o : ktcommon.h ktutil.h ktsocket.h ktthserv.h myconf.h kthttp.o : ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h myconf.h ktrpc.o : ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h ktrpc.h myconf.h ktulog.o : ktcommon.h ktutil.h ktulog.h myconf.h ktshlib.o : ktcommon.h ktutil.h ktshlib.h myconf.h kttimeddb.o : ktcommon.h ktutil.h ktulog.h ktshlib.h kttimeddb.h myconf.h ktdbext.o : ktcommon.h ktutil.h ktulog.h ktshlib.h kttimeddb.h ktdbext.h myconf.h ktremotedb.o : ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h ktrpc.h \ ktulog.h ktshlib.h kttimeddb.h ktdbext.h ktremotedb.h myconf.h ktplugservmemc.o : ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h ktrpc.h \ ktulog.h ktshlib.h kttimeddb.h ktdbext.h ktremotedb.h ktplugserv.h myconf.h ktplugdbvoid.o : ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h ktrpc.h \ ktulog.h ktshlib.h kttimeddb.h ktdbext.h ktremotedb.h ktplugdb.h myconf.h myscript.o : ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h ktrpc.h \ ktulog.h ktshlib.h kttimeddb.h ktdbext.h ktremotedb.h myconf.h myscript.h ktutiltest.o ktutilmgr.o ktutilserv.o kttimedtest.o kttimedmgr.o \ ktserver.o ktremotetest.o ktremotemgr.o : \ ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h ktrpc.h \ ktulog.h ktshlib.h kttimeddb.h ktdbext.h ktremotedb.h ktplugserv.h ktplugdb.h \ cmdcommon.h myconf.h myscript.h # END OF FILE �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktutil.cc������������������������������������������������������������������������0000644�0001750�0001750�00000037476�11757471602�015074� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * Utility functions * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include "ktutil.h" #include "myconf.h" namespace kyototycoon { // common namespace /** The package version. */ const char* const VERSION = _KT_VERSION; /** The library version. */ const int32_t LIBVER = _KT_LIBVER; /** The library revision. */ const int32_t LIBREV = _KT_LIBREV; /** The extra feature list. */ const char* const FEATURES = "" #if defined(_KT_EVENT_EPOLL) "(epoll)" #elif defined(_KT_EVENT_KQUEUE) "(kqueue)" #else "(select)" #endif #if _KT_LUA "(lua)" #endif ; /** * Set the signal handler for termination signals. */ bool setkillsignalhandler(void (*handler)(int)) { _assert_(handler); int32_t signals[] = { SIGHUP, SIGINT, SIGUSR1, SIGUSR2, SIGTERM }; bool err = false; for (size_t i = 0; i < sizeof(signals) / sizeof(*signals); i++) { struct ::sigaction sa; std::memset(&sa, 0, sizeof(sa)); sa.sa_flags = 0; sa.sa_handler = handler; sigfillset(&sa.sa_mask); if (::sigaction(signals[i], &sa, NULL) != 0) err = true; } return !err; } /** * Set the signal mask of the current to ignore all. */ bool maskthreadsignal() { _assert_(true); bool err = false; ::sigset_t sigmask; sigfillset(&sigmask); if (::pthread_sigmask(SIG_BLOCK, &sigmask, NULL) != 0) err = true; return !err; } /** * Switch the process into the background. */ bool daemonize() { _assert_(true); std::fflush(stdout); std::fflush(stderr); switch (::fork()) { case -1: return false; case 0: break; default: ::_exit(0); } if (::setsid() == -1) return false; switch (::fork()) { case -1: return false; case 0: break; default: ::_exit(0); } ::umask(0); if (::chdir("/") == -1) return false; ::close(0); ::close(1); ::close(2); int32_t fd = ::open("/dev/null", O_RDWR, 0); if (fd != -1) { ::dup2(fd, 0); ::dup2(fd, 1); ::dup2(fd, 2); if (fd > 2) ::close(fd); } return true; } /** * Execute a shell command. */ int32_t executecommand(const std::vector<std::string>& args) { _assert_(true); if (args.empty()) return -1; std::string phrase; for (size_t i = 0; i < args.size(); i++) { const char* rp = args[i].c_str(); char* token = new char[args[i].size() * 2 + 1]; char* wp = token; while (*rp != '\0') { switch (*rp) { case '"': case '\\': case '$': case '`': case '!': { *(wp++) = '\\'; *(wp++) = *rp; break; } default: { *(wp++) = *rp; break; } } rp++; } *wp = '\0'; if (!phrase.empty()) phrase.append(" "); kc::strprintf(&phrase, "\"%s\"", token); delete[] token; } int32_t rv = std::system(phrase.c_str()); if (WIFEXITED(rv)) { rv = WEXITSTATUS(rv); } else { rv = kc::INT32MAX; } return rv; } /** * Get the Gregorian calendar of a time. */ void getcalendar(int64_t t, int32_t jl, int32_t* yearp, int32_t* monp, int32_t* dayp, int32_t* hourp, int32_t* minp, int32_t* secp) { _assert_(true); if (t == kc::INT64MAX) t = std::time(NULL); if (jl == kc::INT32MAX) jl = jetlag(); time_t tt = (time_t)t + jl; struct std::tm ts; if (!getgmtime(tt, &ts)) { if (yearp) *yearp = 0; if (monp) *monp = 0; if (dayp) *dayp = 0; if (hourp) *hourp = 0; if (minp) *minp = 0; if (secp) *secp = 0; } if (yearp) *yearp = ts.tm_year + 1900; if (monp) *monp = ts.tm_mon + 1; if (dayp) *dayp = ts.tm_mday; if (hourp) *hourp = ts.tm_hour; if (minp) *minp = ts.tm_min; if (secp) *secp = ts.tm_sec; } /** * Format a date as a string in W3CDTF. */ void datestrwww(int64_t t, int32_t jl, char* buf) { _assert_(buf); if (t == kc::INT64MAX) t = std::time(NULL); if (jl == kc::INT32MAX) jl = jetlag(); time_t tt = (time_t)t + jl; struct std::tm ts; if (!getgmtime(tt, &ts)) std::memset(&ts, 0, sizeof(ts)); ts.tm_year += 1900; ts.tm_mon += 1; jl /= 60; char tzone[16]; if (jl == 0) { std::sprintf(tzone, "Z"); } else if (jl < 0) { jl *= -1; std::sprintf(tzone, "-%02d:%02d", jl / 60, jl % 60); } else { std::sprintf(tzone, "+%02d:%02d", jl / 60, jl % 60); } std::sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%s", ts.tm_year, ts.tm_mon, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec, tzone); } /** * Format a date as a string in W3CDTF with the fraction part. */ void datestrwww(double t, int32_t jl, int32_t acr, char* buf) { _assert_(acr >= 0 && buf); if (kc::chknan(t)) t = kc::time(); double tinteg, tfract; tfract = std::fabs(std::modf(t, &tinteg)); if (jl == kc::INT32MAX) jl = jetlag(); if (acr > 12) acr = 12; time_t tt = (time_t)tinteg + jl; struct std::tm ts; if (!getgmtime(tt, &ts)) std::memset(&ts, 0, sizeof(ts)); ts.tm_year += 1900; ts.tm_mon += 1; jl /= 60; char tzone[16]; if (jl == 0) { std::sprintf(tzone, "Z"); } else if (jl < 0) { jl *= -1; std::sprintf(tzone, "-%02d:%02d", jl / 60, jl % 60); } else { std::sprintf(tzone, "+%02d:%02d", jl / 60, jl % 60); } if (acr < 1) { std::sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%s", ts.tm_year, ts.tm_mon, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec, tzone); } else { char dec[16]; std::sprintf(dec, "%.12f", tfract); char* wp = dec; if (*wp == '0') wp++; wp[acr+1] = '\0'; std::sprintf(buf, "%04d-%02d-%02dT%02d:%02d:%02d%s%s", ts.tm_year, ts.tm_mon, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec, wp, tzone); } } /** * Format a date as a string in RFC 1123 format. */ void datestrhttp(int64_t t, int32_t jl, char* buf) { _assert_(buf); if (t == kc::INT64MAX) t = std::time(NULL); if (jl == kc::INT32MAX) jl = jetlag(); time_t tt = (time_t)t + jl; struct std::tm ts; if (!getgmtime(tt, &ts)) std::memset(&ts, 0, sizeof(ts)); ts.tm_year += 1900; ts.tm_mon += 1; jl /= 60; char* wp = buf; switch (dayofweek(ts.tm_year, ts.tm_mon, ts.tm_mday)) { case 0: wp += std::sprintf(wp, "Sun, "); break; case 1: wp += std::sprintf(wp, "Mon, "); break; case 2: wp += std::sprintf(wp, "Tue, "); break; case 3: wp += std::sprintf(wp, "Wed, "); break; case 4: wp += std::sprintf(wp, "Thu, "); break; case 5: wp += std::sprintf(wp, "Fri, "); break; case 6: wp += std::sprintf(wp, "Sat, "); break; } wp += std::sprintf(wp, "%02d ", ts.tm_mday); switch (ts.tm_mon) { case 1: wp += std::sprintf(wp, "Jan "); break; case 2: wp += std::sprintf(wp, "Feb "); break; case 3: wp += std::sprintf(wp, "Mar "); break; case 4: wp += std::sprintf(wp, "Apr "); break; case 5: wp += std::sprintf(wp, "May "); break; case 6: wp += std::sprintf(wp, "Jun "); break; case 7: wp += std::sprintf(wp, "Jul "); break; case 8: wp += std::sprintf(wp, "Aug "); break; case 9: wp += std::sprintf(wp, "Sep "); break; case 10: wp += std::sprintf(wp, "Oct "); break; case 11: wp += std::sprintf(wp, "Nov "); break; case 12: wp += std::sprintf(wp, "Dec "); break; } wp += std::sprintf(wp, "%04d %02d:%02d:%02d ", ts.tm_year, ts.tm_hour, ts.tm_min, ts.tm_sec); if (jl == 0) { std::sprintf(wp, "GMT"); } else if (jl < 0) { jl *= -1; std::sprintf(wp, "-%02d%02d", jl / 60, jl % 60); } else { std::sprintf(wp, "+%02d%02d", jl / 60, jl % 60); } } /** * Get the time value of a date string. */ int64_t strmktime(const char* str) { _assert_(str); while (*str > '\0' && *str <= ' ') { str++; } if (*str == '\0') return kc::INT64MIN; if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X')) return kc::atoih(str + 2); struct std::tm ts; std::memset(&ts, 0, sizeof(ts)); ts.tm_year = 70; ts.tm_mon = 0; ts.tm_mday = 1; ts.tm_hour = 0; ts.tm_min = 0; ts.tm_sec = 0; ts.tm_isdst = 0; int32_t len = std::strlen(str); time_t t = (time_t)kc::atoi(str); const char* pv = str; while (*pv >= '0' && *pv <= '9') { pv++; } while (*pv > '\0' && *pv <= ' ') { pv++; } if (*pv == '\0') return t; if ((pv[0] == 's' || pv[0] == 'S') && pv[1] >= '\0' && pv[1] <= ' ') return t; if ((pv[0] == 'm' || pv[0] == 'M') && pv[1] >= '\0' && pv[1] <= ' ') return t * 60; if ((pv[0] == 'h' || pv[0] == 'H') && pv[1] >= '\0' && pv[1] <= ' ') return t * 60 * 60; if ((pv[0] == 'd' || pv[0] == 'D') && pv[1] >= '\0' && pv[1] <= ' ') return t * 60 * 60 * 24; if (len > 4 && str[4] == '-') { ts.tm_year = kc::atoi(str) - 1900; if ((pv = std::strchr(str, '-')) != NULL && pv - str == 4) { const char* rp = pv + 1; ts.tm_mon = kc::atoi(rp) - 1; if ((pv = std::strchr(rp, '-')) != NULL && pv - str == 7) { rp = pv + 1; ts.tm_mday = kc::atoi(rp); if ((pv = std::strchr(rp, 'T')) != NULL && pv - str == 10) { rp = pv + 1; ts.tm_hour = kc::atoi(rp); if ((pv = std::strchr(rp, ':')) != NULL && pv - str == 13) { rp = pv + 1; ts.tm_min = kc::atoi(rp); } if ((pv = std::strchr(rp, ':')) != NULL && pv - str == 16) { rp = pv + 1; ts.tm_sec = kc::atoi(rp); } if ((pv = std::strchr(rp, '.')) != NULL && pv - str >= 19) rp = pv + 1; pv = rp; while (*pv >= '0' && *pv <= '9') { pv++; } if ((*pv == '+' || *pv == '-') && std::strlen(pv) >= 6 && pv[3] == ':') ts.tm_sec -= (kc::atoi(pv + 1) * 3600 + kc::atoi(pv + 4) * 60) * (pv[0] == '+' ? 1 : -1); } } } return mkgmtime(&ts); } if (len > 4 && str[4] == '/') { ts.tm_year = kc::atoi(str) - 1900; if ((pv = std::strchr(str, '/')) != NULL && pv - str == 4) { const char* rp = pv + 1; ts.tm_mon = kc::atoi(rp) - 1; if ((pv = std::strchr(rp, '/')) != NULL && pv - str == 7) { rp = pv + 1; ts.tm_mday = kc::atoi(rp); if ((pv = std::strchr(rp, ' ')) != NULL && pv - str == 10) { rp = pv + 1; ts.tm_hour = kc::atoi(rp); if ((pv = std::strchr(rp, ':')) != NULL && pv - str == 13) { rp = pv + 1; ts.tm_min = kc::atoi(rp); } if ((pv = std::strchr(rp, ':')) != NULL && pv - str == 16) { rp = pv + 1; ts.tm_sec = kc::atoi(rp); } if ((pv = std::strchr(rp, '.')) != NULL && pv - str >= 19) rp = pv + 1; pv = rp; while (*pv >= '0' && *pv <= '9') { pv++; } if ((*pv == '+' || *pv == '-') && std::strlen(pv) >= 6 && pv[3] == ':') ts.tm_sec -= (kc::atoi(pv + 1) * 3600 + kc::atoi(pv + 4) * 60) * (pv[0] == '+' ? 1 : -1); } } } return mkgmtime(&ts); } const char* crp = str; if (len >= 4 && str[3] == ',') crp = str + 4; while (*crp == ' ') { crp++; } ts.tm_mday = kc::atoi(crp); while ((*crp >= '0' && *crp <= '9') || *crp == ' ') { crp++; } if (kc::strifwm(crp, "Jan")) { ts.tm_mon = 0; } else if (kc::strifwm(crp, "Feb")) { ts.tm_mon = 1; } else if (kc::strifwm(crp, "Mar")) { ts.tm_mon = 2; } else if (kc::strifwm(crp, "Apr")) { ts.tm_mon = 3; } else if (kc::strifwm(crp, "May")) { ts.tm_mon = 4; } else if (kc::strifwm(crp, "Jun")) { ts.tm_mon = 5; } else if (kc::strifwm(crp, "Jul")) { ts.tm_mon = 6; } else if (kc::strifwm(crp, "Aug")) { ts.tm_mon = 7; } else if (kc::strifwm(crp, "Sep")) { ts.tm_mon = 8; } else if (kc::strifwm(crp, "Oct")) { ts.tm_mon = 9; } else if (kc::strifwm(crp, "Nov")) { ts.tm_mon = 10; } else if (kc::strifwm(crp, "Dec")) { ts.tm_mon = 11; } else { ts.tm_mon = -1; } if (ts.tm_mon >= 0) crp += 3; while (*crp == ' ') { crp++; } ts.tm_year = kc::atoi(crp); if (ts.tm_year >= 1969) ts.tm_year -= 1900; while (*crp >= '0' && *crp <= '9') { crp++; } while (*crp == ' ') { crp++; } if (ts.tm_mday > 0 && ts.tm_mon >= 0 && ts.tm_year >= 0) { int32_t clen = std::strlen(crp); if (clen >= 8 && crp[2] == ':' && crp[5] == ':') { ts.tm_hour = kc::atoi(crp + 0); ts.tm_min = kc::atoi(crp + 3); ts.tm_sec = kc::atoi(crp + 6); if (clen >= 14 && crp[8] == ' ' && (crp[9] == '+' || crp[9] == '-')) { ts.tm_sec -= ((crp[10] - '0') * 36000 + (crp[11] - '0') * 3600 + (crp[12] - '0') * 600 + (crp[13] - '0') * 60) * (crp[9] == '+' ? 1 : -1); } else if (clen > 9) { if (!std::strcmp(crp + 9, "JST")) { ts.tm_sec -= 9 * 3600; } else if (!std::strcmp(crp + 9, "CCT")) { ts.tm_sec -= 8 * 3600; } else if (!std::strcmp(crp + 9, "KST")) { ts.tm_sec -= 9 * 3600; } else if (!std::strcmp(crp + 9, "EDT")) { ts.tm_sec -= -4 * 3600; } else if (!std::strcmp(crp + 9, "EST")) { ts.tm_sec -= -5 * 3600; } else if (!std::strcmp(crp + 9, "CDT")) { ts.tm_sec -= -5 * 3600; } else if (!std::strcmp(crp + 9, "CST")) { ts.tm_sec -= -6 * 3600; } else if (!std::strcmp(crp + 9, "MDT")) { ts.tm_sec -= -6 * 3600; } else if (!std::strcmp(crp + 9, "MST")) { ts.tm_sec -= -7 * 3600; } else if (!std::strcmp(crp + 9, "PDT")) { ts.tm_sec -= -7 * 3600; } else if (!std::strcmp(crp + 9, "PST")) { ts.tm_sec -= -8 * 3600; } else if (!std::strcmp(crp + 9, "HDT")) { ts.tm_sec -= -9 * 3600; } else if (!std::strcmp(crp + 9, "HST")) { ts.tm_sec -= -10 * 3600; } } } return mkgmtime(&ts); } return kc::INT64MIN; } /** * Get the jet lag of the local time. */ int32_t jetlag() { #if defined(_SYS_LINUX_) _assert_(true); ::tzset(); return -timezone; #else _assert_(true); time_t t = 86400; struct std::tm gts; if (!getgmtime(t, >s)) return 0; struct std::tm lts; t = 86400; if (!getlocaltime(t, <s)) return 0; return std::mktime(<s) - std::mktime(>s); #endif } /** * Get the day of week of a date. */ int32_t dayofweek(int32_t year, int32_t mon, int32_t day) { _assert_(true); if (mon < 3) { year--; mon += 12; } return (day + ((8 + (13 * mon)) / 5) + (year + (year / 4) - (year / 100) + (year / 400))) % 7; } /** * Get the local time of a time. */ bool getlocaltime(time_t time, struct std::tm* result) { #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) _assert_(result); return ::localtime_s(result, &time) == 0; #else _assert_(result); return ::localtime_r(&time, result) != NULL; #endif } /** * Get the GMT local time of a time. */ bool getgmtime(time_t time, struct std::tm* result) { #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) _assert_(result); return ::gmtime_s(result, &time) == 0; #else _assert_(result); return ::gmtime_r(&time, result)!= NULL; #endif } /** * Make the GMT from a time structure. */ time_t mkgmtime(struct std::tm *tm) { #if defined(_SYS_LINUX_) _assert_(tm); return ::timegm(tm); #else _assert_(tm); return std::mktime(tm) + jetlag(); #endif } } // common namespace // END OF FILE ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/�����������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11757471566�013777� 5����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/leveldb/���������������������������������������������������������������������0000755�0001750�0001750�00000000000�11757471566�015414� 5����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/leveldb/Makefile�������������������������������������������������������������0000644�0001750�0001750�00000001323�11602634161�017030� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������SHLIBFILES = ktplugdblevel.so CXX = g++ CPPFLAGS = -I. -I.. -I../.. -I/usr/local/include -D_GNU_SOURCE=1 -D_FILE_OFFSET_BITS=64 -D_REENTRANT -D__EXTENSIONS__ CXXFLAGS = -O2 -Wall -fPIC -fsigned-char LDFLAGS = -L. -L.. -L../.. -L/usr/local/lib -Wl,-rpath-link,.:..:../..:/usr/local/lib:.:/usr/local/lib:/usr/local/lib:. -Wl,--as-needed LIBS = -lleveldb -lkyototycoon -lkyotocabinet all : $(SHLIBFILES) clean : rm -rf $(SHLIBFILES) *.exe *.o a.out check.out gmon.out leak.log casket* *~ .SUFFIXES : .SUFFIXES : .cc .o .c.o : $(CC) -c $(CPPFLAGS) $(CFLAGS) $< .cc.o : $(CXX) -c $(CPPFLAGS) $(CXXFLAGS) $< ktplugdblevel.so : ktplugdblevel.o $(LIBRARYFILES) $(CXX) $(CXXFLAGS) -shared -o $@ $< $(LDFLAGS) $(LIBS) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/leveldb/ktplugdblevel.cc�����������������������������������������������������0000644�0001750�0001750�00000053231�11757471566�020573� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * A pluggable database for LevelDB * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include <ktplugdb.h> #include <leveldb/db.h> #include <leveldb/options.h> #include <leveldb/comparator.h> #include <leveldb/iterator.h> #include <leveldb/write_batch.h> #include <leveldb/slice.h> #include <leveldb/status.h> #include <leveldb/env.h> namespace kc = kyotocabinet; namespace kt = kyototycoon; namespace lv = leveldb; // pluggable database for LevelDB class LevelDB : public kt::PluggableDB { public: class Cursor; private: class ScopedVisitor; typedef std::list<Cursor*> CursorList; public: // cursor to indicate a record class Cursor : public BasicDB::Cursor { friend class LevelDB; public: // constructor explicit Cursor(LevelDB* db) : db_(db), it_(NULL) { _assert_(db); kc::ScopedRWLock lock(&db_->mlock_, true); db_ = db; it_ = db_->db_->NewIterator(lv::ReadOptions()); db_->curs_.push_back(this); } // destructor virtual ~Cursor() { _assert_(true); if (!db_) return; kc::ScopedRWLock lock(&db_->mlock_, true); db_->curs_.remove(this); delete it_; } // accept a visitor to the current record bool accept(Visitor* visitor, bool writable = true, bool step = false) { _assert_(visitor); kc::ScopedRWLock lock(&db_->mlock_, writable); if (!db_->db_) { db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } bool err = false; if (!accept_impl(visitor, step)) err = true; return !err; } // jump the cursor to the first record for forward scan bool jump() { _assert_(true); kc::ScopedRWLock lock(&db_->mlock_, false); if (!db_->db_) { db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } bool err = false; it_->SeekToFirst(); if (it_->status().ok()) { if (!it_->Valid()) { db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); err = true; } } else { db_->set_error(_KCCODELINE_, Error::SYSTEM, "Iterator failed"); err = true; } return !err; } // jump the cursor to a record for forward scan bool jump(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); kc::ScopedRWLock lock(&db_->mlock_, false); if (!db_->db_) { db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } bool err = false; std::string key(kbuf, ksiz); it_->Seek(key); if (!it_->status().ok()) { db_->set_error(_KCCODELINE_, Error::SYSTEM, "Iterator failed"); err = true; } if (!it_->Valid()) { db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); err = true; } return !err; } // jump the cursor to a record for forward scan bool jump(const std::string& key) { _assert_(true); return jump(key.data(), key.size()); } // jump the cursor to the last record for backward scan bool jump_back() { _assert_(true); kc::ScopedRWLock lock(&db_->mlock_, false); if (!db_->db_) { db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); return false; } // jump the cursor to a record for backward scan bool jump_back(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); kc::ScopedRWLock lock(&db_->mlock_, false); if (!db_->db_) { db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); return false; } // jump the cursor to a record for backward scan bool jump_back(const std::string& key) { _assert_(true); return jump_back(key.data(), key.size()); } // step the cursor to the next record bool step() { _assert_(true); kc::ScopedRWLock lock(&db_->mlock_, false); if (!db_->db_) { db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } bool err = true; if (it_->Valid()) { it_->Next(); if (it_->status().ok()) { if (!it_->Valid()) { db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); err = true; } } else { db_->set_error(_KCCODELINE_, Error::SYSTEM, "Iterator failed"); err = true; } } else { db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); err = true; } return !err; } // step the cursor to the previous record bool step_back() { _assert_(true); kc::ScopedRWLock lock(&db_->mlock_, false); if (!db_->db_) { db_->set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } db_->set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); return false; } // get the database object LevelDB* db() { _assert_(true); return db_; } private: // accept a visitor to the current record bool accept_impl(Visitor* visitor, bool step) { bool err = false; if (it_->Valid()) { const std::string& key = it_->key().ToString(); const std::string& value = it_->value().ToString(); size_t rsiz; const char* rbuf = visitor->visit_full(key.data(), key.size(), value.data(), value.size(), &rsiz); if (rbuf == kc::BasicDB::Visitor::REMOVE) { lv::WriteOptions wopts; if (db_->autosync_) wopts.sync = true; lv::Status status = db_->db_->Delete(wopts, key); if (!status.ok()) { db_->set_error(_KCCODELINE_, Error::SYSTEM, "DB::Delete failed"); err = true; } } else if (rbuf != kc::BasicDB::Visitor::NOP) { lv::WriteOptions wopts; if (db_->autosync_) wopts.sync = true; std::string rvalue(rbuf, rsiz); lv::Status status = db_->db_->Put(wopts, key, rvalue); if (!status.ok()) { db_->set_error(_KCCODELINE_, Error::SYSTEM, "DB::Put failed"); err = true; } } if (step && it_->Valid()) it_->Next(); } else { db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); err = true; } return !err; } Cursor(const Cursor&); Cursor& operator =(const Cursor&); LevelDB* db_; lv::Iterator* it_; }; // default constructor explicit LevelDB() : mlock_(), rlock_(RLOCKSLOT), error_(), logger_(NULL), logkinds_(0), mtrigger_(NULL), path_(""), db_(NULL), autosync_(false) { _assert_(true); } // destructor ~LevelDB() { _assert_(true); if (db_) close(); } // get the last happened error Error error() const { _assert_(true); return error_; } // set the error information void set_error(const char* file, int32_t line, const char* func, Error::Code code, const char* message) { _assert_(file && line > 0 && func && message); error_->set(code, message); if (logger_) { Logger::Kind kind = code == Error::BROKEN || code == Error::SYSTEM ? Logger::ERROR : Logger::INFO; if (kind & logkinds_) report(file, line, func, kind, "%d: %s: %s", code, Error::codename(code), message); } } // open a database file bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); if (db_) { set_error(_KCCODELINE_, Error::INVALID, "already opened"); return false; } std::vector<std::string> elems; kc::strsplit(path, '#', &elems); std::string fpath; std::vector<std::string>::iterator it = elems.begin(); std::vector<std::string>::iterator itend = elems.end(); if (it != itend) { fpath = *it; ++it; } if (fpath.empty()) { set_error(_KCCODELINE_, Error::INVALID, "invalid path"); return false; } if ((mode & OWRITER) && (mode & OTRUNCATE)) lv::DestroyDB(path, lv::Options()); lv::Options options; if ((mode & OWRITER) && (mode & OCREATE)) options.create_if_missing = true; lv::Status status = lv::DB::Open(options, fpath, &db_); if (!status.ok()) { set_error(_KCCODELINE_, Error::SYSTEM, "DB::Open failed"); return false; } path_.append(fpath); if ((mode & OWRITER) && ((mode & OAUTOTRAN) || (mode & OAUTOSYNC))) autosync_ = true; trigger_meta(MetaTrigger::OPEN, "open"); return true; } // close the database file bool close() { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } if (!curs_.empty()) { CursorList::const_iterator cit = curs_.begin(); CursorList::const_iterator citend = curs_.end(); while (cit != citend) { Cursor* cur = *cit; cur->db_ = NULL; delete cur->it_; ++cit; } } delete db_; db_ = NULL; path_.clear(); trigger_meta(MetaTrigger::CLOSE, "close"); return true; } // accept a visitor to a record bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && visitor); kc::ScopedRWLock lock(&mlock_, false); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } return accept_impl(kbuf, ksiz, visitor, writable); } // accept a visitor to multiple records at once bool accept_bulk(const std::vector<std::string>& keys, Visitor* visitor, bool writable = true) { _assert_(visitor); kc::ScopedRWLock lock(&mlock_, writable); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } ScopedVisitor svis(visitor); bool err = false; std::vector<std::string>::const_iterator kit = keys.begin(); std::vector<std::string>::const_iterator kitend = keys.end(); while (kit != kitend) { if (!accept_impl(kit->data(), kit->size(), visitor, writable)) err = true; ++kit; } return !err; } // iterate to accept a visitor for each record bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* checker = NULL) { _assert_(visitor); kc::ScopedRWLock lock(&mlock_, true); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } ScopedVisitor svis(visitor); bool err = false; if (!iterate_impl(visitor, checker)) err = true; trigger_meta(MetaTrigger::ITERATE, "iterate"); return !err; } // scan each record in parallel bool scan_parallel(Visitor *visitor, size_t thnum, ProgressChecker* checker = NULL) { _assert_(visitor); kc::ScopedRWLock lock(&mlock_, false); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } ScopedVisitor svis(visitor); bool err = true; if (!scan_parallel_impl(visitor, thnum, checker)) err = true; trigger_meta(MetaTrigger::ITERATE, "scan_parallel"); return !err; } // synchronize updated contents with the file and the device bool synchronize(bool hard = false, FileProcessor* proc = NULL, ProgressChecker* checker = NULL) { _assert_(true); kc::ScopedRWLock lock(&mlock_, false); bool err = false; if (proc && !proc->process(path_, 0, 0)) { set_error(_KCCODELINE_, Error::LOGIC, "postprocessing failed"); err = true; } trigger_meta(MetaTrigger::SYNCHRONIZE, "synchronize"); return !err; } // occupy database by locking and do something meanwhile bool occupy(bool writable = true, FileProcessor* proc = NULL) { _assert_(true); kc::ScopedRWLock lock(&mlock_, writable); bool err = false; if (proc && !proc->process(path_, 0, 0)) { set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); err = true; } trigger_meta(MetaTrigger::OCCUPY, "occupy"); return !err; } // begin transaction bool begin_transaction(bool hard = false) { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); return false; } // try to begin transaction bool begin_transaction_try(bool hard = false) { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); return false; } // end transaction bool end_transaction(bool commit = true) { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); return false; } // remove all records bool clear() { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } if (!curs_.empty()) { CursorList::const_iterator cit = curs_.begin(); CursorList::const_iterator citend = curs_.end(); while (cit != citend) { Cursor* cur = *cit; cur->db_ = NULL; delete cur->it_; cur->it_ = NULL; ++cit; } } delete db_; bool err = false; lv::DestroyDB(path_, lv::Options()); lv::Options options; options.create_if_missing = true; lv::Status status = lv::DB::Open(options, path_, &db_); if (status.ok()) { if (!curs_.empty()) { CursorList::const_iterator cit = curs_.begin(); CursorList::const_iterator citend = curs_.end(); while (cit != citend) { Cursor* cur = *cit; cur->db_ = this; cur->it_ = db_->NewIterator(lv::ReadOptions()); ++cit; } } } else { set_error(_KCCODELINE_, Error::SYSTEM, "DB::Open failed"); db_ = NULL; err = true; } trigger_meta(MetaTrigger::CLEAR, "clear"); return true; } // get the number of records int64_t count() { _assert_(true); kc::ScopedRWLock lock(&mlock_, false); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); return -1; } // get the size of the database file int64_t size() { _assert_(true); kc::ScopedRWLock lock(&mlock_, false); if (!db_) { set_error(_KCCODELINE_, Error::INVALID, "not opened"); return false; } set_error(_KCCODELINE_, Error::NOIMPL, "not implemented"); return -1; } // get the path of the database file std::string path() { _assert_(true); kc::ScopedRWLock lock(&mlock_, false); return path_; } // get the miscellaneous status information bool status(std::map<std::string, std::string>* strmap) { _assert_(strmap); kc::ScopedRWLock lock(&mlock_, true); (*strmap)["type"] = kc::strprintf("%u", (unsigned)TYPEMISC); (*strmap)["path"] = path_; return true; } // create a cursor object Cursor* cursor() { _assert_(true); return new Cursor(this); } // write a log message void log(const char* file, int32_t line, const char* func, Logger::Kind kind, const char* message) { _assert_(file && line > 0 && func && message); kc::ScopedRWLock lock(&mlock_, false); if (!logger_) return; logger_->log(file, line, func, kind, message); } // set the internal logger bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger::ERROR) { _assert_(logger); kc::ScopedRWLock lock(&mlock_, true); logger_ = logger; logkinds_ = kinds; return true; } // set the internal meta operation trigger bool tune_meta_trigger(MetaTrigger* trigger) { _assert_(trigger); kc::ScopedRWLock lock(&mlock_, true); mtrigger_ = trigger; return true; } protected: // report a message for debugging void report(const char* file, int32_t line, const char* func, Logger::Kind kind, const char* format, ...) { _assert_(file && line > 0 && func && format); if (!logger_ || !(kind & logkinds_)) return; std::string message; kc::strprintf(&message, "%s: ", path_.empty() ? "-" : path_.c_str()); va_list ap; va_start(ap, format); kc::vstrprintf(&message, format, ap); va_end(ap); logger_->log(file, line, func, kind, message.c_str()); } // trigger a meta database operation void trigger_meta(MetaTrigger::Kind kind, const char* message) { _assert_(message); if (mtrigger_) mtrigger_->trigger(kind, message); } private: // scoped visitor class ScopedVisitor { public: explicit ScopedVisitor(Visitor* visitor) : visitor_(visitor) { _assert_(visitor); visitor_->visit_before(); } ~ScopedVisitor() { _assert_(true); visitor_->visit_after(); } private: Visitor* visitor_; }; // accept a visitor to a record bool accept_impl(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable) { size_t lidx = kc::hashmurmur(kbuf, ksiz) % RLOCKSLOT; if (writable) { rlock_.lock_writer(lidx); } else { rlock_.lock_reader(lidx); } std::string key(kbuf, ksiz); std::string value; lv::Status status = db_->Get(lv::ReadOptions(), key, &value); const char* rbuf; size_t rsiz; if (status.ok()) { rbuf = visitor->visit_full(kbuf, ksiz, value.data(), value.size(), &rsiz); } else { rbuf = visitor->visit_empty(kbuf, ksiz, &rsiz); } bool err = false; if (rbuf == kc::BasicDB::Visitor::REMOVE) { lv::WriteOptions wopts; if (autosync_) wopts.sync = true; status = db_->Delete(wopts, key); if (!status.ok()) { set_error(_KCCODELINE_, Error::SYSTEM, "DB::Delete failed"); err = true; } } else if (rbuf != kc::BasicDB::Visitor::NOP) { lv::WriteOptions wopts; if (autosync_) wopts.sync = true; std::string rvalue(rbuf, rsiz); status = db_->Put(wopts, key, rvalue); if (!status.ok()) { set_error(_KCCODELINE_, Error::SYSTEM, "DB::Put failed"); err = true; } } rlock_.unlock(lidx); return !err; } // iterate to accept a visitor for each record. bool iterate_impl(Visitor* visitor, ProgressChecker* checker) { bool err = false; lv::Iterator* it = db_->NewIterator(lv::ReadOptions()); for (it->SeekToFirst(); it->Valid(); it->Next()) { const std::string& key = it->key().ToString(); const std::string& value = it->value().ToString(); size_t rsiz; const char* rbuf = visitor->visit_full(key.data(), key.size(), value.data(), value.size(), &rsiz); if (rbuf == kc::BasicDB::Visitor::REMOVE) { lv::WriteOptions wopts; if (autosync_) wopts.sync = true; lv::Status status = db_->Delete(wopts, key); if (!status.ok()) { set_error(_KCCODELINE_, Error::SYSTEM, "DB::Delete failed"); err = true; } if (!it->Valid()) break; } else if (rbuf != kc::BasicDB::Visitor::NOP) { lv::WriteOptions wopts; if (autosync_) wopts.sync = true; std::string rvalue(rbuf, rsiz); lv::Status status = db_->Put(wopts, key, rvalue); if (!status.ok()) { set_error(_KCCODELINE_, Error::SYSTEM, "DB::Put failed"); err = true; } if (!it->Valid()) break; } } if (!it->status().ok()) { set_error(_KCCODELINE_, Error::SYSTEM, "Iterator failed"); err = true; } return !err; } // scan each record in parallel bool scan_parallel_impl(Visitor *visitor, size_t thnum, ProgressChecker* checker) { bool err = false; lv::Iterator* it = db_->NewIterator(lv::ReadOptions()); for (it->SeekToFirst(); it->Valid(); it->Next()) { const std::string& key = it->key().ToString(); const std::string& value = it->value().ToString(); size_t rsiz; visitor->visit_full(key.data(), key.size(), value.data(), value.size(), &rsiz); } if (!it->status().ok()) { set_error(_KCCODELINE_, Error::SYSTEM, "Iterator failed"); err = true; } return !err; } static const int32_t RLOCKSLOT = 1024; LevelDB(const LevelDB&); LevelDB& operator =(const LevelDB&); kc::RWLock mlock_; kc::SlottedRWLock rlock_; kc::TSD<kc::BasicDB::Error> error_; kc::BasicDB::Logger* logger_; uint32_t logkinds_; MetaTrigger* mtrigger_; CursorList curs_; std::string path_; lv::DB* db_; bool autosync_; }; // initializer called by the main server extern "C" void* ktdbinit() { return new LevelDB; } // END OF FILE �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/dbbackup���������������������������������������������������������������������0000755�0001750�0001750�00000000556�11473137037�015471� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh #================================================================ # backupdb # Make a back up file of a database file #================================================================ # set variables LANG=C LC_ALL=C export LANG LC_ALL # count steps srcfile="$1" destfile="$1.$2" cp -f "$srcfile" "$destfile" # exit normally exit 0 # END OF FILE ��������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/docrefine.lua����������������������������������������������������������������0000644�0001750�0001750�00000002102�11757471566�016433� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������-- -- refine the documents -- INDEXFILE = "doc/luadoc/index.html" MODULEFILE = "doc/luadoc/modules/kyototycoon.html" CSSFILE = "doc/luadoc/luadoc.css" TMPFILE = INDEXFILE .. "~" OVERVIEWFILE = "luaoverview.html" ofd = io.open(TMPFILE, "wb") first = true for line in io.lines(INDEXFILE) do if first and string.match(line, "<h2> *Modules *</h2>") then for tline in io.lines(OVERVIEWFILE) do ofd:write(tline .. "\n") end first = false end ofd:write(line .. "\n") end ofd:close() os.remove(INDEXFILE) os.rename(TMPFILE, INDEXFILE) ofd = io.open(TMPFILE, "wb") first = true for line in io.lines(MODULEFILE) do if string.match(line, "<em>Fields</em>") then ofd:write("<br/>\n") end ofd:write(line .. "\n") end ofd:close() os.remove(MODULEFILE) os.rename(TMPFILE, MODULEFILE) ofd = io.open(TMPFILE, "wb") for line in io.lines(CSSFILE) do if not string.match(line, "#TODO:") then ofd:write(line .. "\n") end end ofd:write("table.function_list td.name { width: 20em; }\n") ofd:close() os.remove(CSSFILE) os.rename(TMPFILE, CSSFILE) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/ktservctl��������������������������������������������������������������������0000755�0001750�0001750�00000006111�11473077537�015740� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh #---------------------------------------------------------------- # Startup script for the server of Kyoto Tycoon #---------------------------------------------------------------- # configuration variables prog="ktservctl" cmd="ktserver" basedir="/var/ktserver" port="1978" tout="30" thnum="8" pidfile="$basedir/pid" logfile="$basedir/log" #miscopts="-oat" #ulogdir="$basedir/ulog" #ulim=1g #sid=1 #mhost="anotherhost.localdomain" #mport="1978" #rtsfile="$basedir/rts" dbname="$basedir/casket.kch#bnum=2000000#msiz=128m#dfunit=8" retval=0 # setting environment variables LANG=C LC_ALL=C PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin" LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib" export LANG LC_ALL PATH LD_LIBRARY_PATH # start the server start(){ printf 'Starting the server of Kyoto Tycoon\n' mkdir -p "$basedir" if [ -z "$basedir" ] || [ -z "$port" ] || [ -z "$pidfile" ] || [ -z "$dbname" ] ; then printf 'Invalid configuration\n' retval=1 elif ! [ -d "$basedir" ] ; then printf 'No such directory: %s\n' "$basedir" retval=1 else if [ -f "$pidfile" ] ; then pid=`cat "$pidfile"` printf 'Killing existing process: %d\n' "$pid" kill -TERM "$pid" sleep 1 fi cmd="$cmd -port $port -tout $tout -th $thnum -dmn -pid $pidfile" if [ -n "$logfile" ] ; then cmd="$cmd -log $logfile -ls" fi if [ -n "$ulogdir" ] ; then cmd="$cmd -ulog $ulogdir -ulim $ulim -sid $sid" fi if [ -n "$miscopts" ] ; then cmd="$cmd $miscopts" fi if [ -n "$mhost" ] ; then cmd="$cmd -mhost $mhost -mport $mport -rts $rtsfile" fi cmd="$cmd $dbname" printf "Executing: %s\n" "$cmd" $cmd if [ "$?" -eq 0 ] ; then printf 'Done\n' else printf 'The server could not started\n' retval=1 fi fi } # stop the server stop(){ printf 'Stopping the server of Kyoto Tycoon\n' if [ -f "$pidfile" ] ; then pid=`cat "$pidfile"` printf "Sending the terminal signal to the process: %s\n" "$pid" kill -TERM "$pid" c=0 while true ; do sleep 0.1 if [ -f "$pidfile" ] ; then c=`expr $c + 1` if [ "$c" -ge 100 ] ; then printf 'Hanging process: %d\n' "$pid" retval=1 break fi else printf 'Done\n' break fi done else printf 'No process found\n' retval=1 fi } # send HUP to the server for log rotation hup(){ printf 'Sending HUP signal to the server of Kyoto Tycoon\n' if [ -f "$pidfile" ] ; then pid=`cat "$pidfile"` printf "Sending the hangup signal to the process: %s\n" "$pid" kill -HUP "$pid" printf 'Done\n' else printf 'No process found\n' retval=1 fi } # check permission if [ -d "$basedir" ] && ! touch "$basedir/$$" >/dev/null 2>&1 then printf 'Permission denied\n' exit 1 fi rm -f "$basedir/$$" # dispatch the command case "$1" in start) start ;; stop) stop ;; restart) stop start ;; hup) hup ;; *) printf 'Usage: %s {start|stop|restart|hup}\n' "$prog" exit 1 ;; esac # exit exit "$retval" # END OF FILE �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/diffcheck��������������������������������������������������������������������0000755�0001750�0001750�00000001500�11441471557�015615� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh #================================================================ # diffcheck # List files different from ones of another version #================================================================ # set variables LANG=C LC_ALL=C export LANG LC_ALL regex='\.(h|c|cc|cpp|cxx|java|pl|pm|pod|rb|rd|lua|[1-9]|html|txt)$' vregex='/api/' # check arguments if [ $# != 1 ] then printf 'diffcheck: usage: diffcheck directory_of_oldversion\n' 1>&2 exit 1 fi # diff files find . -type f | egrep $regex | egrep -v $vregex | while read file do old=`printf '%s\n' "$file" | sed 's/^\.\///'` printf 'Checking %s and %s ... ' "$file" "$1/$old" res=`diff -q "$file" "$1/$old"` if [ -z "$res" ] then printf 'same\n' else printf '### !!! DIFFERENT !!! ###\n' fi done # exit normally exit 0 # END OF FILE ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/memo.txt���������������������������������������������������������������������0000644�0001750�0001750�00000004170�11737574137�015473� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������================================================================ Easy way to check replication functionality ================================================================ [clean-up] ---------------------------------------------------------------- $ killall ktserver $ rm -rf *-ulog *.pid *.rts casket* ---------------------------------------------------------------- [Server 1] ---------------------------------------------------------------- - start the server $ ./ktserver -port 2001 -ulog 2001-ulog -ulim 5m -sid 2001 -pid 2001.pid -mhost localhost -mport 2002 -rts 2001.rts -cmd ./lab casket-2001.kch ---------------------------------------------------------------- [Server 2] ---------------------------------------------------------------- - start the server $ ./ktserver -port 2002 -ulog 2002-ulog -ulim 5m -sid 2002 -pid 2002.pid -mhost localhost -mport 2001 -rts 2002.rts -cmd ./lab casket-2002.kch ---------------------------------------------------------------- [Client 1] ---------------------------------------------------------------- - make a million records and their update logs on server 1 $ ./ktremotetest bulk -bulk 100 -bin -set -port 2001 1000000 - wait until the server 2 has about 0.5 million records checking the number of records $ ./ktremotemgr inform -port 2002 - create the backup file $ ./ktremotemgr sync -cmd dbbackup -port 2002 - kill the server 2 immediately - copy the backup file (casket-2002.kch.*) as the original database $ cp casket-2002.kch.* casket-2002.kch - write the timestamp file from the timestamp of the backup file $ ls casket-2002.kch.* $ echo 0123xxxxxxx > 2002.rts - restart the server 2 - check if the number of records becomes 1000000 - kill the server 2 - check the update log files on the server 1 $ ./ktremotemgr slave -port 2001 -uf - remove update log files older than the timestamp of the backup $ ls casket-2002.kch.* $ ./ktremotemgr slave -port 2001 -ur -ts 0123xxxx - check again $ ./ktremotemgr slave -port 2001 -uf - do the above recovery process again - check if the number of records becomes 1000000 ---------------------------------------------------------------- ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/ktdualtest�������������������������������������������������������������������0000755�0001750�0001750�00000003436�11611542106�016071� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh #---------------------------------------------------------------- # Startup script to test of dual master settings of Kyoto Tycoon #---------------------------------------------------------------- # configuration variables prog="ktservctl" basedir=`pwd` kchopts="#bnum=10m#msiz=1g" kctopts="#bnum=1m#msiz=1g" retval=0 # setting environment variables LANG=C LC_ALL=C PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin:." LD_LIBRARY_PATH="$LD_LIBRARY_PATH:." export LANG LC_ALL PATH LD_LIBRARY_PATH # start the server start(){ rm -rf *.kch *.kct *.log *-ulog *.rts ktserver -port 1978 -log "$basedir/0001.log" -ls \ -ulog "$basedir/0001-ulog" -ulim 10m -sid 1 \ -dmn -pid "$basedir/0001.pid" \ -mhost localhost -mport 1979 -rts "$basedir/0001.rts" -riv 0 \ -cmd "$basedir/lab" "$basedir/0001-01.kch$kchopts" "$basedir/0001-02.kct$kctopts" ktserver -port 1979 -log "$basedir/0002.log" -ls \ -ulog "$basedir/0002-ulog" -ulim 10m -sid 2 \ -dmn -pid "$basedir/0002.pid" \ -mhost localhost -mport 1978 -rts "$basedir/0002.rts" -riv 0 \ -cmd "$basedir/lab" "$basedir/0002-01.kch$kchopts" "$basedir/0002-02.kct$kctopts" sleep 1 printf "0001: %s\n" "`cat 0001.pid`" printf "0002: %s\n" "`cat 0002.pid`" } # stop the server stop(){ pid=`cat 0001.pid` [ -n "$pid" ] && kill -TERM "$pid" pid=`cat 0002.pid` [ -n "$pid" ] && kill -TERM "$pid" sleep 3 } # send HUP to the server for log rotation hup(){ pid=`cat 0001.pid` [ -n "$pid" ] && kill -HUP "$pid" pid=`cat 0002.pid` [ -n "$pid" ] && kill -HUP "$pid" sleep 3 } # dispatch the command case "$1" in start) start ;; stop) stop ;; restart) stop start ;; hup) hup ;; *) printf 'Usage: %s {start|stop|restart|hup}\n' "$prog" exit 1 ;; esac # exit exit "$retval" # END OF FILE ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/stepcount��������������������������������������������������������������������0000755�0001750�0001750�00000000662�11441471602�015732� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh #================================================================ # stepcount # Find files including dispensable tab characters #================================================================ # set variables LANG=C LC_ALL=C export LANG LC_ALL regex='(\.h|\.c|\.cc|\.java|\.pl|\.pm|\.xs|\.rb|\.js)$' # count steps files=`find . -type f | egrep $regex` wc -l $files | sort -n # exit normally exit 0 # END OF FILE ������������������������������������������������������������������������������kyototycoon-0.9.56/lab/numbers.tsv������������������������������������������������������������������0000644�0001750�0001750�00000000420�11446065023�016162� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������zero zeroth one first two second - fizz one three third four fourth - buzz one five fifth - fizz two six sixth seven seventh eight eighth - fizz three nine ninth - buzz two ten tenth eleven eleventh - fizz four twelve twelfth zero - ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/datechange�������������������������������������������������������������������0000755�0001750�0001750�00000002407�11441471564�015777� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh #================================================================ # datechange # Replace date expressions #================================================================ # set variables LANG=C LC_ALL=C export LANG LC_ALL year=`date '+%Y'` date=`date '+%Y-%m-%d'` fulldate=`date -R` regexsrc='\.(h|c|cc|cpp|cxx|java|pl|pm|pod|xs|rb|rd|py|lua|idl)$' regexman='\.[0-9]$' regexhtml='\.html$' # edit source files find . -type f | egrep "$regexsrc" | while read file do echo "$file" sed "/opyright/ s/\\(20[0-9][0-9]\\)-\\(20[0-9][0-9]\\)/\\1-$year/" "$file" > "$file.tmp" mv -f "$file.tmp" "$file" done # edit manual files find . -type f | egrep "$regexman" | while read file do echo "$file" sed "/\\.TH/ s/\\(20[0-9][0-9]\\)-\\([0-9][0-9]\\)-\\([0-9][0-9]\\)/$date/" "$file" > "$file.tmp" mv -f "$file.tmp" "$file" done # edit HTML files find . -type f | egrep "$regexhtml" | while read file do echo "$file" sed -e "/opyright/ s/\\(20[0-9][0-9]\\)-\\(20[0-9][0-9]\\)/\\1-$year/" -e "/<div class=\"note\">/ s/Last Update: *\\([A-Z][a-z][a-z], [0-9][0-9] [A-Z][a-z][a-z] 20[0-9][0-9] [0-9][0-9]:[0-9][0-9]:[0-9][0-9] +[0-9][0-9]*\\)/Last Update: $fulldate/" "$file" > "$file.tmp" mv -f "$file.tmp" "$file" done # exit normally exit 0 # END OF FILE ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/lab/codecheck��������������������������������������������������������������������0000755�0001750�0001750�00000004466�11455061047�015627� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /usr/bin/ruby -w #================================================================ # codecheck # Check files about compliance of the coding policy #================================================================ SUFFIXES = /\.(h|cc)$/ IGNORES = /(ktcommon\.h)/ BADOPEN = /[^\w](if|while|for|switch)\(/ BADCLOSE = /\)\{/ BADTYPE = /[^\w](u)*(void|char|int|double|size_t|std::string)[0-9]*(_t)* +\*/ BADFUNCS = [ /[^:.>\w](malloc|calloc|realloc|free|rand|srand|qsort|strtoll|llabs|div|lldiv) *\(/, /[^:.>\w](memset|memcpy|memmove|memcmp|memchr) *\(/, /[^:.>\w](strcpy|strncpy|strcat|strncat|strcmp|strchr|strrchr|strstr|strlen) *\(/, /[^:.>\w](sprintf|snprintf|vsprintf|vsnprintf) *\(/, /[^:.>\w](isnan|isinf|pow|fabs|sqrt|floor|ceil|modf|modfl) *\(/, ] LIMITWIDTH = 97 def checkfile(path) printf("Checking: %s\n", path) ok = true open(path, "r") do |file| num = 0 file.each do |line| num += 1 line.chomp! if line =~ /\s$/ printf("TRAINING SPACE: %s: %d: %s\n", path, num, line) ok = false end if line =~ /\t/ printf("TAB CODE: %s: %d: %s\n", path, num, line) ok = false end if line =~ BADOPEN printf("BAD OPEN: %s: %d: %s\n", path, num, line) ok = false end if line =~ BADCLOSE printf("BAD CLOSE: %s: %d: %s\n", path, num, line) ok = false end if line =~ BADTYPE printf("BAD TYPE: %s: %d: %s\n", path, num, line) ok = false end BADFUNCS.each do |badfunc| if line =~ badfunc printf("BAD FUNC: %s: %d: %s\n", path, num, line) ok = false end end if line.length > LIMITWIDTH && !line.index("/*") && !line.index("*/") printf("BAD WIDTH: %s: %d: %s\n", path, num, line) ok = false end end end return ok end ok = true list = Array::new(ARGV) list.push(".") if list.empty? while !list.empty? path = list.shift begin if File::ftype(path) == "directory" Dir.entries(path).each do |cpath| if cpath =~ SUFFIXES && cpath !~ /[#~]/ && cpath !~ IGNORES list.push(path + "/" + cpath) end end else ok = false if !checkfile(path) end rescue end end if ok printf("ALL OK\n") exit(0) else printf("ERROR\n") exit(1) end # END OF FILE ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/luaoverview.html�����������������������������������������������������������������0000644�0001750�0001750�00000020350�11757471566�016477� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<style type="text/css"> p { margin: 0.5ex 0.5ex; text-indent: 1.2ex; } div { margin: 0.5ex 0.5ex; } h1, h2, h3 { margin: 15px 0px 10px 3px; padding: 0px 0px; } pre { margin: 0.8ex 1.0ex; padding: 0.3ex 0.3ex; background: none #eeeeee; border: solid 1px #ccdddd; font-size: 95%; } </style> <h1>Scripting Extension of Kyoto Tycoon.</h1> <p>This module is imported by the server program (ktserver) of Kyoto Tycoon. The server must be built enabling the scripting extension by Lua.</p> <p>The start-up command has the option "-scr" to specify a script file defining functions in Lua.</p> <pre>$ ktserver -scr myscript.lua </pre> <p>You can define your own functions in the global name space so that clients can call them by specifying the name of each function. The function name must be composed of ASCII alphabets and numbers because of security reasons. Each function receives two tables as arguments. The first table contains the input data specified by clients. The second table is to contain the output data to send to clients.</p> <p>In the scripting environment, the global variable "__kyototycoon__" is defined by default. It contains objects to access server resources. The most important one is "__kyototycoon__.db", which is the primary database managed by the server. "__kyototycoon__.dbs" is an array of databases managed by the server. The return value of each function must be "__kyototycoon__.RVSUCCESS" for success or a related code for error.</p> <p>Because the server uses respective instances of the Lua processor for each native thread, you cannot use global variables to share data among sessions. Use a cache database managed by the server for that purpose.</p> <p>The following is an example code.</p> <pre>kt = __kyototycoon__ db = kt.db -- log the start-up message if kt.thid == 0 then kt.log("system", "the Lua script has been loaded") end -- echo back the input data as the output data function echo(inmap, outmap) for key, value in pairs(inmap) do outmap[key] = value end return kt.RVSUCCESS end -- report the internal state of the server function report(inmap, outmap) outmap["__kyototycoon__.VERSION"] = kt.VERSION outmap["__kyototycoon__.thid"] = kt.thid outmap["__kyototycoon__.db"] = tostring(kt.db) for i = 1, #kt.dbs do local key = "__kyototycoon__.dbs[" .. i .. "]" outmap[key] = tostring(kt.dbs[i]) end local names = "" for name, value in pairs(kt.dbs) do if #names > 0 then names = names .. "," end names = names .. name end outmap["names"] = names return kt.RVSUCCESS end -- log a message function log(inmap, outmap) local kind = inmap.kind local message = inmap.message if not message then return kt.RVEINVALID end if not kind then kind = "info" end kt.log(kind, message) return kt.RVSUCCESS end -- store a record function set(inmap, outmap) local key = inmap.key local value = inmap.value if not key or not value then return kt.RVEINVALID end local xt = inmap.xt if not db:set(key, value, xt) then return kt.RVEINTERNAL end return kt.RVSUCCESS end -- remove a record function remove(inmap, outmap) local key = inmap.key if not key then return kt.RVEINVALID end if not db:remove(key) then local err = db:error() if err:code() == kt.Error.NOREC then return kt.RVELOGIC end return kt.RVEINTERNAL end return kt.RVSUCCESS end -- increment the numeric string value function increment(inmap, outmap) local key = inmap.key local num = inmap.num if not key or not num then return kt.RVEINVALID end local function visit(rkey, rvalue, rxt) rvalue = tonumber(rvalue) if not rvalue then rvalue = 0 end num = rvalue + num return num end if not db:accept(key, visit) then return kt.REINTERNAL end outmap.num = num return kt.RVSUCCESS end -- retrieve the value of a record function get(inmap, outmap) local key = inmap.key if not key then return kt.RVEINVALID end local value, xt = db:get(key) if value then outmap.value = value outmap.xt = xt else local err = db:error() if err:code() == kt.Error.NOREC then return kt.RVELOGIC end return kt.RVEINTERNAL end return kt.RVSUCCESS end -- store records at once function setbulk(inmap, outmap) local num = db:set_bulk(inmap) if num < 0 then return kt.RVEINTERNAL end outmap["num"] = num return kt.RVSUCCESS end -- remove records at once function removebulk(inmap, outmap) local keys = {} for key, value in pairs(inmap) do table.insert(keys, key) end local num = db:remove_bulk(keys) if num < 0 then return kt.RVEINTERNAL end outmap["num"] = num return kt.RVSUCCESS end -- retrieve records at once function getbulk(inmap, outmap) local keys = {} for key, value in pairs(inmap) do table.insert(keys, key) end local res = db:get_bulk(keys) if not res then return kt.RVEINTERNAL end for key, value in pairs(res) do outmap[key] = value end return kt.RVSUCCESS end -- move the value of a record to another function move(inmap, outmap) local srckey = inmap.src local destkey = inmap.dest if not srckey or not destkey then return kt.RVEINVALID end local keys = { srckey, destkey } local first = true local srcval = nil local srcxt = nil local function visit(key, value, xt) if first then srcval = value srcxt = xt first = false return kt.Visitor.REMOVE end if srcval then return srcval, srcxt end return kt.Visitor.NOP end if not db:accept_bulk(keys, visit) then return kt.REINTERNAL end if not srcval then return kt.RVELOGIC end return kt.RVSUCCESS end -- list all records function list(inmap, outmap) local cur = db:cursor() cur:jump() while true do local key, value, xt = cur:get(true) if not key then break end outmap[key] = value end return kt.RVSUCCESS end -- upcate all characters in the value of a record function upcase(inmap, outmap) local key = inmap.key if not key then return kt.RVEINVALID end local function visit(key, value, xt) if not value then return kt.Visitor.NOP end return string.upper(value) end if not db:accept(key, visit) then return kt.RVEINTERNAL end return kt.RVSUCCESS end -- prolong the expiration time of a record function survive(inmap, outmap) local key = inmap.key if not key then return kt.RVEINVALID end local function visit(key, value, xt) if not value then return kt.Visitor.NOP end outmap.old_xt = xt if xt > kt.time() + 3600 then return kt.Visitor.NOP end return value, 3600 end if not db:accept(key, visit) then return kt.RVEINTERNAL end return kt.RVSUCCESS end -- count words with the MapReduce framework function countwords(inmap, outmap) local function map(key, value, emit) local values = kt.split(value, " ") for i = 1, #values do local word = kt.regex(values[i], "[ .?!:;]", "") word = string.lower(word) if #word > 0 then if not emit(word, "") then return false end end end return true end local function reduce(key, iter) local count = 0 while true do local value = iter() if not value then break end count = count + 1 end outmap[key] = count return true end if not db:mapreduce(map, reduce, nil, kt.DB.XNOLOCK) then return kt.RVEINTERNAL end return kt.RVSUCCESS end </pre> <p>To call the above functions, execute the following commands.</p> <pre>$ ktremotemgr script -arg key1 value1 -arg key2 value2 echo $ ktremotemgr script report $ ktremotemgr script -arg kind info -arg message hello log $ ktremotemgr script -arg key one -arg value first set $ ktremotemgr script -arg key two -arg value second set $ ktremotemgr script -arg key three -arg value third set $ ktremotemgr script -arg key three remove $ ktremotemgr script -arg key two get $ ktremotemgr script list </pre> ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktrpc.cc�������������������������������������������������������������������������0000644�0001750�0001750�00000002242�11757471602�014662� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * RPC utilities * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include "ktrpc.h" #include "myconf.h" namespace kyototycoon { // common namespace // There is no implementation now. } // common namespace // END OF FILE ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktthserv.cc����������������������������������������������������������������������0000644�0001750�0001750�00000002617�11757471602�015417� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * Threaded Server * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include "ktthserv.h" #include "myconf.h" namespace kyototycoon { // common namespace /** The magic pointer of an idle session. */ ThreadedServer::Session* const ThreadedServer::SESSIDLE = (ThreadedServer::Session*)0; /** The magic pointer of a timer session. */ ThreadedServer::Session* const ThreadedServer::SESSTIMER = (ThreadedServer::Session*)1; } // common namespace // END OF FILE �����������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktremotemgr.cc�������������������������������������������������������������������0000644�0001750�0001750�00000173565�11757471602�016120� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * The command line utility of the remote database * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include <ktremotedb.h> #include "cmdcommon.h" // global variables const char* g_progname; // program name // function prototypes int main(int argc, char** argv); static void usage(); static void dberrprint(kt::RemoteDB* db, const char* info); static int32_t runreport(int argc, char** argv); static int32_t runscript(int argc, char** argv); static int32_t runtunerepl(int argc, char** argv); static int32_t runinform(int argc, char** argv); static int32_t runclear(int argc, char** argv); static int32_t runsync(int argc, char** argv); static int32_t runset(int argc, char** argv); static int32_t runremove(int argc, char** argv); static int32_t runget(int argc, char** argv); static int32_t runlist(int argc, char** argv); static int32_t runimport(int argc, char** argv); static int32_t runvacuum(int argc, char** argv); static int32_t runslave(int argc, char** argv); static int32_t runsetbulk(int argc, char** argv); static int32_t runremovebulk(int argc, char** argv); static int32_t rungetbulk(int argc, char** argv); static int32_t procreport(const char* host, int32_t port, double tout); static int32_t procscript(const char* proc, const char* host, int32_t port, double tout, bool bin, const char* swname, double swtime, const char* ssname, bool ssbrd, const std::map<std::string, std::string>& params); static int32_t proctunerepl(const char* mhost, const char* host, int32_t port, double tout, int32_t mport, uint64_t ts, double iv); static int32_t procinform(const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool st); static int32_t procclear(const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr); static int32_t procsync(const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool hard, const char* cmd); static int32_t procset(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, int32_t mode, int64_t xt); static int32_t procremove(const char* kbuf, size_t ksiz, const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr); static int32_t procget(const char* kbuf, size_t ksiz, const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool rm, bool px, bool pt, bool pz); static int32_t proclist(const char* kbuf, size_t ksiz, const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool des, int64_t max, bool rm, bool pv, bool px, bool pt); static int32_t procimport(const char* file, const char* host, int32_t port, double tout, const char* dbexpr, bool sx, int64_t xt); static int32_t procvacuum(const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, int64_t step); static int32_t procslave(const char* host, int32_t port, double tout, uint64_t ts, int32_t sid, int32_t opts, bool uw, bool uf, bool ur); static int32_t procsetbulk(const std::map<std::string, std::string>& recs, const char* host, int32_t port, double tout, bool bin, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, int64_t xt); static int32_t procremovebulk(const std::vector<std::string>& keys, const char* host, int32_t port, double tout, bool bin, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr); static int32_t procgetbulk(const std::vector<std::string>& keys, const char* host, int32_t port, double tout, bool bin, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool px); // print the usage and exit int main(int argc, char** argv) { g_progname = argv[0]; kc::setstdiobin(); if (argc < 2) usage(); int32_t rv = 0; if (!std::strcmp(argv[1], "report")) { rv = runreport(argc, argv); } else if (!std::strcmp(argv[1], "script")) { rv = runscript(argc, argv); } else if (!std::strcmp(argv[1], "tunerepl")) { rv = runtunerepl(argc, argv); } else if (!std::strcmp(argv[1], "inform")) { rv = runinform(argc, argv); } else if (!std::strcmp(argv[1], "clear")) { rv = runclear(argc, argv); } else if (!std::strcmp(argv[1], "sync")) { rv = runsync(argc, argv); } else if (!std::strcmp(argv[1], "set")) { rv = runset(argc, argv); } else if (!std::strcmp(argv[1], "remove")) { rv = runremove(argc, argv); } else if (!std::strcmp(argv[1], "get")) { rv = runget(argc, argv); } else if (!std::strcmp(argv[1], "list")) { rv = runlist(argc, argv); } else if (!std::strcmp(argv[1], "import")) { rv = runimport(argc, argv); } else if (!std::strcmp(argv[1], "vacuum")) { rv = runvacuum(argc, argv); } else if (!std::strcmp(argv[1], "slave")) { rv = runslave(argc, argv); } else if (!std::strcmp(argv[1], "setbulk")) { rv = runsetbulk(argc, argv); } else if (!std::strcmp(argv[1], "removebulk")) { rv = runremovebulk(argc, argv); } else if (!std::strcmp(argv[1], "getbulk")) { rv = rungetbulk(argc, argv); } else if (!std::strcmp(argv[1], "version") || !std::strcmp(argv[1], "--version")) { printversion(); } else { usage(); } return rv; } // print the usage and exit static void usage() { eprintf("%s: the command line utility of the remote database of Kyoto Tycoon\n", g_progname); eprintf("\n"); eprintf("usage:\n"); eprintf(" %s report [-host str] [-port num] [-tout num]\n", g_progname); eprintf(" %s script [-host str] [-port num] [-tout num] [-bin]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] proc [args...]\n", g_progname); eprintf(" %s tunerepl [-host str] [-port num] [-tout num] [-mport num] [-ts num] [-iv num]" " [mhost]\n", g_progname); eprintf(" %s inform [-host str] [-port num] [-tout num]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-st]\n", g_progname); eprintf(" %s clear [-host str] [-port num] [-tout num]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str]\n", g_progname); eprintf(" %s sync [-host str] [-port num] [-tout num]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-hard] [-cmd str]\n", g_progname); eprintf(" %s set [-host str] [-port num] [-tout num]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str]" " [-add|-rep|-app|-inci|-incd] [-sx] [-xt num] key value\n", g_progname); eprintf(" %s remove [-host str] [-port num] [-tout num]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-sx] key\n", g_progname); eprintf(" %s get [-host str] [-port num] [-tout num]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str]" " [-rm] [-sx] [-px] [-pt] [-pz] key\n", g_progname); eprintf(" %s list [-host str] [-port num] [-tout num]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str]" " [-des] [-max num] [-rm] [-sx] [-pv] [-px] [-pt] [key]\n", g_progname); eprintf(" %s import [-host str] [-port num] [-tout num] [-db str] [-sx] [-xt num] [file]\n", g_progname); eprintf(" %s vacuum [-host str] [-port num] [-tout num]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-step num]\n", g_progname); eprintf(" %s slave [-host str] [-port num] [-tout num] [-ts num] [-sid num]" " [-ux] [-uw] [-uf] [-ur]\n", g_progname); eprintf(" %s setbulk [-host str] [-port num] [-tout num] [-bin]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-sx] [-xt num]" " key value ...\n", g_progname); eprintf(" %s removebulk [-host str] [-port num] [-tout num] [-bin]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-sx]" " key ...\n", g_progname); eprintf(" %s getbulk [-host str] [-port num] [-tout num] [-bin]" " [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-sx] [-px]" " key ...\n", g_progname); eprintf("\n"); std::exit(1); } // print error message of database static void dberrprint(kt::RemoteDB* db, const char* info) { const kt::RemoteDB::Error& err = db->error(); eprintf("%s: %s: %s: %d: %s: %s\n", g_progname, info, db->expression().c_str(), err.code(), err.name(), err.message()); } // parse arguments of report command static int32_t runreport(int argc, char** argv) { bool argbrk = false; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else { usage(); } } else { argbrk = true; usage(); } } if (port < 1) usage(); int32_t rv = procreport(host, port, tout); return rv; } // parse arguments of script command static int32_t runscript(int argc, char** argv) { bool argbrk = false; const char* proc = NULL; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; bool bin = false; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; std::map<std::string, std::string> params; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-bin")) { bin = true; } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else { usage(); } } else if (!proc) { argbrk = true; proc = argv[i]; } else { if (++i >= argc) usage(); params[argv[i-1]] = argv[i]; } } if (!proc || port < 1) usage(); int32_t rv = procscript(proc, host, port, tout, bin, swname, swtime, ssname, ssbrd, params); return rv; } // parse arguments of tunerepl command static int32_t runtunerepl(int argc, char** argv) { bool argbrk = false; const char* mhost = NULL; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; int32_t mport = kt::DEFPORT; uint64_t ts = kc::UINT64MAX; double iv = -1; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-mport")) { if (++i >= argc) usage(); mport = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-ts")) { if (++i >= argc) usage(); if (!std::strcmp(argv[i], "now") || !std::strcmp(argv[i], "-")) { ts = kc::UINT64MAX - 1; } else { ts = kc::atoix(argv[i]); } } else if (!std::strcmp(argv[i], "-iv")) { if (++i >= argc) usage(); iv = kc::atof(argv[i]); } else { usage(); } } else if (!mhost) { argbrk = true; mhost = argv[i]; } else { usage(); } } if (port < 1 || mport < 1) usage(); int32_t rv = proctunerepl(mhost, host, port, tout, mport, ts, iv); return rv; } // parse arguments of inform command static int32_t runinform(int argc, char** argv) { bool argbrk = false; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; bool st = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-st")) { st = true; } else { usage(); } } else { argbrk = true; usage(); } } if (port < 1) usage(); int32_t rv = procinform(host, port, tout, swname, swtime, ssname, ssbrd, dbexpr, st); return rv; } // parse arguments of clear command static int32_t runclear(int argc, char** argv) { bool argbrk = false; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else { usage(); } } else { argbrk = true; usage(); } } if (port < 1) usage(); int32_t rv = procclear(host, port, tout, swname, swtime, ssname, ssbrd, dbexpr); return rv; } // parse arguments of sync command static int32_t runsync(int argc, char** argv) { bool argbrk = false; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; bool hard = false; const char* cmd = ""; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-hard")) { hard = true; } else if (!std::strcmp(argv[i], "-cmd")) { if (++i >= argc) usage(); cmd = argv[i]; } else { usage(); } } else { argbrk = true; usage(); } } if (port < 1) usage(); int32_t rv = procsync(host, port, tout, swname, swtime, ssname, ssbrd, dbexpr, hard, cmd); return rv; } // parse arguments of set command static int32_t runset(int argc, char** argv) { bool argbrk = false; const char* kstr = NULL; const char* vstr = NULL; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; int32_t mode = 0; bool sx = false; int64_t xt = kc::INT64MAX; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-add")) { mode = 'a'; } else if (!std::strcmp(argv[i], "-rep")) { mode = 'r'; } else if (!std::strcmp(argv[i], "-app")) { mode = 'c'; } else if (!std::strcmp(argv[i], "-inci")) { mode = 'i'; } else if (!std::strcmp(argv[i], "-incd")) { mode = 'd'; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-xt")) { if (++i >= argc) usage(); xt = kc::atoix(argv[i]); } else { usage(); } } else if (!kstr) { argbrk = true; kstr = argv[i]; } else if (!vstr) { vstr = argv[i]; } else { usage(); } } if (!kstr || !vstr) usage(); char* kbuf; size_t ksiz; char* vbuf; size_t vsiz; if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; vbuf = kc::hexdecode(vstr, &vsiz); vstr = vbuf; } else { ksiz = std::strlen(kstr); kbuf = NULL; vsiz = std::strlen(vstr); vbuf = NULL; } if (port < 1) { delete[] kbuf; delete[] vbuf; usage(); } int32_t rv = procset(kstr, ksiz, vstr, vsiz, host, port, tout, swname, swtime, ssname, ssbrd, dbexpr, mode, xt); delete[] kbuf; delete[] vbuf; return rv; } // parse arguments of remove command static int32_t runremove(int argc, char** argv) { bool argbrk = false; const char* kstr = NULL; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; bool sx = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else { usage(); } } else if (!kstr) { argbrk = true; kstr = argv[i]; } else { usage(); } } if (!kstr) usage(); char* kbuf; size_t ksiz; if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; } else { ksiz = std::strlen(kstr); kbuf = NULL; } if (port < 1) { delete[] kbuf; usage(); } int32_t rv = procremove(kstr, ksiz, host, port, tout, swname, swtime, ssname, ssbrd, dbexpr); delete[] kbuf; return rv; } // parse arguments of get command static int32_t runget(int argc, char** argv) { bool argbrk = false; const char* kstr = NULL; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; bool rm = false; bool sx = false; bool px = false; bool pt = false; bool pz = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-rm")) { rm = true; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-px")) { px = true; } else if (!std::strcmp(argv[i], "-pt")) { pt = true; } else if (!std::strcmp(argv[i], "-pz")) { pz = true; } else { usage(); } } else if (!kstr) { argbrk = true; kstr = argv[i]; } else { usage(); } } if (!kstr) usage(); char* kbuf; size_t ksiz; if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; } else { ksiz = std::strlen(kstr); kbuf = NULL; } if (port < 1) { delete[] kbuf; usage(); } int32_t rv = procget(kstr, ksiz, host, port, tout, swname, swtime, ssname, ssbrd, dbexpr, rm, px, pt, pz); delete[] kbuf; return rv; } // parse arguments of list command static int32_t runlist(int argc, char** argv) { bool argbrk = false; const char* kstr = NULL; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; bool des = false; int64_t max = -1; bool rm = false; bool sx = false; bool pv = false; bool px = false; bool pt = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-des")) { des = true; } else if (!std::strcmp(argv[i], "-max")) { if (++i >= argc) usage(); max = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-rm")) { rm = true; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-pv")) { pv = true; } else if (!std::strcmp(argv[i], "-px")) { px = true; } else if (!std::strcmp(argv[i], "-pt")) { pt = true; } else { usage(); } } else if (!kstr) { argbrk = true; kstr = argv[i]; } else { usage(); } } char* kbuf = NULL; size_t ksiz = 0; if (kstr) { if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; } else { ksiz = std::strlen(kstr); kbuf = new char[ksiz+1]; std::memcpy(kbuf, kstr, ksiz); kbuf[ksiz] = '\0'; } } if (port < 1) { delete[] kbuf; usage(); } int32_t rv = proclist(kbuf, ksiz, host, port, tout, swname, swtime, ssname, ssbrd, dbexpr, des, max, rm, pv, px, pt); delete[] kbuf; return rv; } // parse arguments of import command static int32_t runimport(int argc, char** argv) { bool argbrk = false; const char* file = NULL; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; const char* dbexpr = NULL; bool sx = false; int64_t xt = kc::INT64MAX; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-xt")) { if (++i >= argc) usage(); xt = kc::atoix(argv[i]); } else { usage(); } } else if (!file) { argbrk = true; file = argv[i]; } else { usage(); } } if (port < 1) usage(); int32_t rv = procimport(file, host, port, tout, dbexpr, sx, xt); return rv; } // parse arguments of vacuum command static int32_t runvacuum(int argc, char** argv) { bool argbrk = false; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; int64_t step = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-step")) { if (++i >= argc) usage(); step = kc::atoix(argv[i]); } else { usage(); } } else { argbrk = true; usage(); } } if (port < 1) usage(); int32_t rv = procvacuum(host, port, tout, swname, swtime, ssname, ssbrd, dbexpr, step); return rv; } // parse arguments of slave command static int32_t runslave(int argc, char** argv) { bool argbrk = false; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; uint64_t ts = 0; int32_t sid = 0; bool uw = false; int32_t opts = 0; bool uf = false; bool ur = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ts")) { if (++i >= argc) usage(); if (!std::strcmp(argv[i], "now") || !std::strcmp(argv[i], "-")) { ts = kt::UpdateLogger::clock_pure(); } else { ts = kc::atoix(argv[i]); } } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-ux")) { opts |= kt::ReplicationClient::WHITESID; } else if (!std::strcmp(argv[i], "-uw")) { uw = true; } else if (!std::strcmp(argv[i], "-uf")) { uf = true; } else if (!std::strcmp(argv[i], "-ur")) { ur = true; } else { usage(); } } else { argbrk = true; usage(); } } if (port < 1) usage(); int32_t rv = procslave(host, port, tout, ts, sid, opts, uw, uf, ur); return rv; } // parse arguments of setbulk command static int32_t runsetbulk(int argc, char** argv) { bool argbrk = false; std::map<std::string, std::string> recs; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; bool bin = false; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; bool sx = false; int64_t xt = kc::INT64MAX; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-bin")) { bin = true; } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-xt")) { if (++i >= argc) usage(); xt = kc::atoix(argv[i]); } else { usage(); } } else { argbrk = true; const char* kstr = argv[i]; if (++i >= argc) usage(); const char* vstr = argv[i]; char* kbuf; size_t ksiz; char* vbuf; size_t vsiz; if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; vbuf = kc::hexdecode(vstr, &vsiz); vstr = vbuf; } else { ksiz = std::strlen(kstr); kbuf = NULL; vsiz = std::strlen(vstr); vbuf = NULL; } std::string key(kstr, ksiz); std::string value(vstr, vsiz); recs[key] = value; delete[] kbuf; delete[] vbuf; } } int32_t rv = procsetbulk(recs, host, port, tout, bin, swname, swtime, ssname, ssbrd, dbexpr, xt); return rv; } // parse arguments of removebulk command static int32_t runremovebulk(int argc, char** argv) { bool argbrk = false; std::vector<std::string> keys; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; bool bin = false; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; bool sx = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-bin")) { bin = true; } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else { usage(); } } else { argbrk = true; const char* kstr = argv[i]; char* kbuf; size_t ksiz; if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; } else { ksiz = std::strlen(kstr); kbuf = NULL; } std::string key(kstr, ksiz); keys.push_back(key); delete[] kbuf; } } int32_t rv = procremovebulk(keys, host, port, tout, bin, swname, swtime, ssname, ssbrd, dbexpr); return rv; } // parse arguments of getbulk command static int32_t rungetbulk(int argc, char** argv) { bool argbrk = false; std::vector<std::string> keys; const char* host = ""; int32_t port = kt::DEFPORT; double tout = 0; bool bin = false; const char* swname = NULL; double swtime = 0; const char* ssname = NULL; bool ssbrd = false; const char* dbexpr = NULL; bool sx = false; bool px = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-bin")) { bin = true; } else if (!std::strcmp(argv[i], "-swname")) { if (++i >= argc) usage(); swname = argv[i]; } else if (!std::strcmp(argv[i], "-swtime")) { if (++i >= argc) usage(); swtime = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ssname")) { if (++i >= argc) usage(); ssname = argv[i]; } else if (!std::strcmp(argv[i], "-ssbrd")) { ssbrd = false; } else if (!std::strcmp(argv[i], "-db")) { if (++i >= argc) usage(); dbexpr = argv[i]; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-px")) { px = true; } else { usage(); } } else { argbrk = true; const char* kstr = argv[i]; char* kbuf; size_t ksiz; if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; } else { ksiz = std::strlen(kstr); kbuf = NULL; } std::string key(kstr, ksiz); keys.push_back(key); delete[] kbuf; } } int32_t rv = procgetbulk(keys, host, port, tout, bin, swname, swtime, ssname, ssbrd, dbexpr, px); return rv; } // perform report command static int32_t procreport(const char* host, int32_t port, double tout) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; std::map<std::string, std::string> status; if (db.report(&status)) { std::map<std::string, std::string>::iterator it = status.begin(); std::map<std::string, std::string>::iterator itend = status.end(); while (it != itend) { oprintf("%s: %s\n", it->first.c_str(), it->second.c_str()); ++it; } } else { dberrprint(&db, "DB::status failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform script command static int32_t procscript(const char* proc, const char* host, int32_t port, double tout, bool bin, const char* swname, double swtime, const char* ssname, bool ssbrd, const std::map<std::string, std::string>& params) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); bool err = false; if (bin) { std::map<std::string, std::string> result; if (db.play_script_binary(proc, params, &result)) { std::map<std::string, std::string>::iterator it = result.begin(); std::map<std::string, std::string>::iterator itend = result.end(); while (it != itend) { oprintf("%s\t%s\n", it->first.c_str(), it->second.c_str()); ++it; } } else { dberrprint(&db, "DB::play_script_binary failed"); err = true; } } else { std::map<std::string, std::string> result; if (db.play_script(proc, params, &result)) { std::map<std::string, std::string>::iterator it = result.begin(); std::map<std::string, std::string>::iterator itend = result.end(); while (it != itend) { oprintf("%s\t%s\n", it->first.c_str(), it->second.c_str()); ++it; } } else { dberrprint(&db, "DB::play_script failed"); err = true; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform tunerepl command static int32_t proctunerepl(const char* mhost, const char* host, int32_t port, double tout, int32_t mport, uint64_t ts, double iv) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; if (!db.tune_replication(mhost ? mhost : "", mport, ts, iv)) { dberrprint(&db, "DB::tune_replication failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform inform command static int32_t procinform(const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool st) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); if (dbexpr) db.set_target(dbexpr); bool err = false; std::map<std::string, std::string> status; if (db.status(&status)) { if (st) { std::map<std::string, std::string>::iterator it = status.begin(); std::map<std::string, std::string>::iterator itend = status.end(); while (it != itend) { oprintf("%s: %s\n", it->first.c_str(), it->second.c_str()); ++it; } } else { oprintf("count: %s\n", status["count"].c_str()); oprintf("size: %s\n", status["size"].c_str()); } } else { dberrprint(&db, "DB::status failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform clear command static int32_t procclear(const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); if (dbexpr) db.set_target(dbexpr); bool err = false; if (!db.clear()) { dberrprint(&db, "DB::clear failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform sync command static int32_t procsync(const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool hard, const char* cmd) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); if (dbexpr) db.set_target(dbexpr); bool err = false; if (!db.synchronize(hard, cmd)) { dberrprint(&db, "DB::synchronize failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform set command static int32_t procset(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, int32_t mode, int64_t xt) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); if (dbexpr) db.set_target(dbexpr); bool err = false; switch (mode) { default: { if (!db.set(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(&db, "DB::set failed"); err = true; } break; } case 'a': { if (!db.add(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(&db, "DB::add failed"); err = true; } break; } case 'r': { if (!db.replace(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(&db, "DB::replace failed"); err = true; } break; } case 'c': { if (!db.append(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(&db, "DB::append failed"); err = true; } break; } case 'i': { int64_t onum = db.increment(kbuf, ksiz, kc::atoi(vbuf), 0, xt); if (onum == kc::INT64MIN) { dberrprint(&db, "DB::increment failed"); err = true; } else { oprintf("%lld\n", (long long)onum); } break; } case 'd': { double onum = db.increment_double(kbuf, ksiz, kc::atof(vbuf), 0, xt); if (kc::chknan(onum)) { dberrprint(&db, "DB::increment_double failed"); err = true; } else { oprintf("%f\n", onum); } break; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform remove command static int32_t procremove(const char* kbuf, size_t ksiz, const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); if (dbexpr) db.set_target(dbexpr); bool err = false; if (!db.remove(kbuf, ksiz)) { dberrprint(&db, "DB::remove failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform get command static int32_t procget(const char* kbuf, size_t ksiz, const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool rm, bool px, bool pt, bool pz) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); if (dbexpr) db.set_target(dbexpr); bool err = false; char* vbuf; size_t vsiz; int64_t xt; if (rm) { vbuf = db.seize(kbuf, ksiz, &vsiz, &xt); } else { vbuf = db.get(kbuf, ksiz, &vsiz, &xt); } if (vbuf) { printdata(vbuf, vsiz, px); if (pt) oprintf("\t%lld", (long long)xt); if (!pz) oprintf("\n"); delete[] vbuf; } else { dberrprint(&db, "DB::get failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform list command static int32_t proclist(const char* kbuf, size_t ksiz, const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool des, int64_t max, bool rm, bool pv, bool px, bool pt) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); if (dbexpr) db.set_target(dbexpr); bool err = false; if (max < 0) max = kc::INT64MAX; kt::RemoteDB::Cursor cur(&db); if (des) { if (kbuf) { if (!cur.jump_back(kbuf, ksiz) && db.error() != kt::RemoteDB::Error::LOGIC) { dberrprint(&db, "Cursor::jump failed"); err = true; } } else { if (!cur.jump_back() && db.error() != kt::RemoteDB::Error::LOGIC) { dberrprint(&db, "Cursor::jump failed"); err = true; } } while (!err && max > 0) { char* kbuf; size_t ksiz, vsiz; const char* vbuf; int64_t xt; if (rm) { kbuf = cur.seize(&ksiz, &vbuf, &vsiz, &xt); } else { kbuf = cur.get(&ksiz, &vbuf, &vsiz, &xt); } if (kbuf) { printdata(kbuf, ksiz, px); if (pv) { oprintf("\t"); printdata(vbuf, vsiz, px); } if (pt) oprintf("\t%lld", (long long)xt); oprintf("\n"); delete[] kbuf; } else { if (db.error() != kt::RemoteDB::Error::LOGIC) { dberrprint(&db, "Cursor::get failed"); err = true; } break; } cur.step_back(); max--; } } else { if (kbuf) { if (!cur.jump(kbuf, ksiz) && db.error() != kt::RemoteDB::Error::LOGIC) { dberrprint(&db, "Cursor::jump failed"); err = true; } } else { if (!cur.jump() && db.error() != kt::RemoteDB::Error::LOGIC) { dberrprint(&db, "Cursor::jump failed"); err = true; } } while (!err && max > 0) { char* kbuf; size_t ksiz, vsiz; const char* vbuf; int64_t xt; if (rm) { kbuf = cur.seize(&ksiz, &vbuf, &vsiz, &xt); } else { kbuf = cur.get(&ksiz, &vbuf, &vsiz, &xt, true); } if (kbuf) { printdata(kbuf, ksiz, px); if (pv) { oprintf("\t"); printdata(vbuf, vsiz, px); } if (pt) oprintf("\t%lld", (long long)xt); oprintf("\n"); delete[] kbuf; } else { if (db.error() != kt::RemoteDB::Error::LOGIC) { dberrprint(&db, "Cursor::get failed"); err = true; } break; } max--; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform import command static int32_t procimport(const char* file, const char* host, int32_t port, double tout, const char* dbexpr, bool sx, int64_t xt) { std::istream *is = &std::cin; std::ifstream ifs; if (file) { ifs.open(file, std::ios_base::in | std::ios_base::binary); if (!ifs) { eprintf("%s: %s: open error\n", g_progname, file); return 1; } is = &ifs; } kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (dbexpr) db.set_target(dbexpr); bool err = false; int64_t cnt = 0; std::string line; std::vector<std::string> fields; while (!err && mygetline(is, &line)) { cnt++; kc::strsplit(line, '\t', &fields); if (sx) { std::vector<std::string>::iterator it = fields.begin(); std::vector<std::string>::iterator itend = fields.end(); while (it != itend) { size_t esiz; char* ebuf = kc::hexdecode(it->c_str(), &esiz); it->clear(); it->append(ebuf, esiz); delete[] ebuf; ++it; } } switch (fields.size()) { case 2: { if (!db.set(fields[0], fields[1], xt)) { dberrprint(&db, "DB::set failed"); err = true; } break; } case 1: { if (!db.remove(fields[0]) && db.error() != kt::RemoteDB::Error::LOGIC) { dberrprint(&db, "DB::remove failed"); err = true; } break; } } oputchar('.'); if (cnt % 50 == 0) oprintf(" (%d)\n", cnt); } if (cnt % 50 > 0) oprintf(" (%d)\n", cnt); if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform vacuum command static int32_t procvacuum(const char* host, int32_t port, double tout, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, int64_t step) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); if (dbexpr) db.set_target(dbexpr); bool err = false; if (!db.vacuum(step)) { dberrprint(&db, "DB::vacuum failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform slave command static int32_t procslave(const char* host, int32_t port, double tout, uint64_t ts, int32_t sid, int32_t opts, bool uw, bool uf, bool ur) { bool err = false; if (uf || ur) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (ur) { if (ts < 1) ts = kc::UINT64MAX; if (!db.ulog_remove(ts)) { dberrprint(&db, "DB::ulog_remove failed"); err = true; } } else { std::vector<kt::UpdateLogger::FileStatus> files; if (db.ulog_list(&files)) { std::vector<kt::UpdateLogger::FileStatus>::iterator it = files.begin(); std::vector<kt::UpdateLogger::FileStatus>::iterator itend = files.end(); while (it != itend) { oprintf("%s\t%llu\t%llu\n", it->path.c_str(), (unsigned long long)it->size, (unsigned long long)it->ts); ++it; } } else { dberrprint(&db, "DB::ulog_list failed"); err = true; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } } else { kt::ReplicationClient rc; if (!rc.open(host, port, tout, ts, sid, opts)) { eprintf("%s: %s:%d: open error\n", g_progname, host, port); return 1; } while (true) { size_t msiz; uint64_t mts; char* mbuf = rc.read(&msiz, &mts); if (mbuf) { if (msiz > 0) { size_t rsiz; uint16_t rsid, rdbid; const char* rbuf = DBUpdateLogger::parse(mbuf, msiz, &rsiz, &rsid, &rdbid); if (rbuf) { std::vector<std::string> tokens; kt::TimedDB::tokenize_update_log(rbuf, rsiz, &tokens); if (!tokens.empty()) { const std::string& name = tokens.front(); oprintf("%llu\t%u\t%u\t%s", (unsigned long long)mts, rsid, rdbid, name.c_str()); std::vector<std::string>::iterator it = tokens.begin() + 1; std::vector<std::string>::iterator itend = tokens.end(); while (it != itend) { char* str = kc::baseencode(it->data(), it->size()); oprintf("\t%s", str); delete[] str; ++it; } oprintf("\n"); } } else { eprintf("%s: parsing a message failed\n", g_progname); err = true; } } delete[] mbuf; } else if (!rc.alive() || !uw) { break; } } if (!rc.close()) { eprintf("%s: close error\n", g_progname); err = true; } } return err ? 1 : 0; } // perform setbulk command static int32_t procsetbulk(const std::map<std::string, std::string>& recs, const char* host, int32_t port, double tout, bool bin, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, int64_t xt) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); bool err = false; if (bin) { std::vector<kt::RemoteDB::BulkRecord> bulkrecs; uint16_t dbidx = dbexpr ? kc::atoi(dbexpr) : 0; std::map<std::string, std::string>::const_iterator it = recs.begin(); std::map<std::string, std::string>::const_iterator itend = recs.end(); while (it != itend) { kt::RemoteDB::BulkRecord rec = { dbidx, it->first, it->second, xt }; bulkrecs.push_back(rec); ++it; } if (db.set_bulk_binary(bulkrecs) != (int64_t)recs.size()) { dberrprint(&db, "DB::set_bulk_binary failed"); err = true; } } else { if (dbexpr) db.set_target(dbexpr); if (db.set_bulk(recs, xt) != (int64_t)recs.size()) { dberrprint(&db, "DB::set_bulk failed"); err = true; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform removebulk command static int32_t procremovebulk(const std::vector<std::string>& keys, const char* host, int32_t port, double tout, bool bin, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); bool err = false; if (bin) { std::vector<kt::RemoteDB::BulkRecord> bulkrecs; uint16_t dbidx = dbexpr ? kc::atoi(dbexpr) : 0; std::vector<std::string>::const_iterator it = keys.begin(); std::vector<std::string>::const_iterator itend = keys.end(); while (it != itend) { kt::RemoteDB::BulkRecord rec = { dbidx, *it, "", 0 }; bulkrecs.push_back(rec); ++it; } if (db.remove_bulk_binary(bulkrecs) < 0) { dberrprint(&db, "DB::remove_bulk_binary failed"); err = true; } } else { if (dbexpr) db.set_target(dbexpr); if (db.remove_bulk(keys) < 0) { dberrprint(&db, "DB::remove_bulk failed"); err = true; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // perform getbulk command static int32_t procgetbulk(const std::vector<std::string>& keys, const char* host, int32_t port, double tout, bool bin, const char* swname, double swtime, const char* ssname, bool ssbrd, const char* dbexpr, bool px) { kt::RemoteDB db; if (!db.open(host, port, tout)) { dberrprint(&db, "DB::open failed"); return 1; } if (swname) db.set_signal_waiting(swname, swtime); if (ssname) db.set_signal_sending(ssname, ssbrd); bool err = false; if (bin) { std::vector<kt::RemoteDB::BulkRecord> bulkrecs; uint16_t dbidx = dbexpr ? kc::atoi(dbexpr) : 0; std::vector<std::string>::const_iterator it = keys.begin(); std::vector<std::string>::const_iterator itend = keys.end(); while (it != itend) { kt::RemoteDB::BulkRecord rec = { dbidx, *it, "", 0 }; bulkrecs.push_back(rec); ++it; } if (db.get_bulk_binary(&bulkrecs) >= 0) { std::vector<kt::RemoteDB::BulkRecord>::iterator rit = bulkrecs.begin(); std::vector<kt::RemoteDB::BulkRecord>::iterator ritend = bulkrecs.end(); while (rit != ritend) { if (rit->xt > 0) { printdata(rit->key.data(), rit->key.size(), px); oprintf("\t"); printdata(rit->value.data(), rit->value.size(), px); oprintf("\n"); } ++rit; } } else { dberrprint(&db, "DB::get_bulk_binary failed"); err = true; } } else { if (dbexpr) db.set_target(dbexpr); std::map<std::string, std::string> recs; if (db.get_bulk(keys, &recs) >= 0) { std::map<std::string, std::string>::iterator it = recs.begin(); std::map<std::string, std::string>::iterator itend = recs.end(); while (it != itend) { printdata(it->first.data(), it->first.size(), px); oprintf("\t"); printdata(it->second.data(), it->second.size(), px); oprintf("\n"); ++it; } } else { dberrprint(&db, "DB::get_bulk failed"); err = true; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } return err ? 1 : 0; } // END OF FILE �������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/overview�������������������������������������������������������������������������0000644�0001750�0001750�00000012462�11561102644�015014� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/** @mainpage Kyoto Tycoon: a handy cache/storage server @section Introduction Kyoto Tycoon is a lightweight database server with auto expiration mechanism, which is useful to handle cache data and persistent data of various applications. Kyoto Tycoon is also a package of network interface to the DBM called Kyoto Cabinet. Though the DBM has high performance and high concurrency, you might bother in case that multiple processes share the same database, or remote processes access the database. Thus, Kyoto Tycoon is provided for concurrent and remote connections to Kyoto Cabinet. Kyoto Tycoon is composed of the server process managing multiple databases and its access library for client applications. The network protocol between the server and clients is HTTP so that you can write client applications and client libraries in almost all popular languages. Both of RESTful-style interface by the GET, HEAD, PUT, DELETE methods and RPC-style inteface by the POST method are supported. The server can handle more than 10 thousand connections at the same time because it uses modern I/O event notification facilities such as "epoll" and "kqueue" of underlying systems. The server can embed Lua, a lightweight script language so that you can define arbitrary operations of the database. The following classes are the most important. If you are interested in writing applications of Kyoto Tycoon, all you have to learn is how to use the remote database interface. @li kyototycoon::RemoteDB -- remote database interface @li kyototycoon::TimedDB -- database implementation with record expiration mechanism @li kyototycoon::RPCClient -- utilities to implement your own RPC client @li kyototycoon::RPCServer -- utilities to implement your own RPC server @li kyototycoon::HTTPClient -- utilities to implement your own HTTP client @li kyototycoon::HTTPServer -- utilities to implement your own HTTP server @li kyototycoon::ThreadedServer -- utilities to implement your own TCP server @li kyototycoon::Poller -- abstraction of system-independent event notification mechanism @li kyototycoon::Socket -- abstraction of system-independent client socket mechanism @li kyototycoon::ServerSocket -- abstraction of system-independent server socket mechanism @li kyototycoon::PluggableServer -- pluggable server interface @li kyototycoon::PluggableDB -- pluggable database interface @section Example The following code is an example to use a remote database. @code #include <ktremotedb.h> using namespace std; using namespace kyototycoon; // main routine int main(int argc, char** argv) { // create the database object RemoteDB db; // open the database if (!db.open()) { cerr << "open error: " << db.error().name() << endl; } // store records if (!db.set("foo", "hop") || !db.set("bar", "step") || !db.set("baz", "jump")) { cerr << "set error: " << db.error().name() << endl; } // retrieve a record string value; if (db.get("foo", &value)) { cout << value << endl; } else { cerr << "get error: " << db.error().name() << endl; } // traverse records RemoteDB::Cursor* cur = db.cursor(); cur->jump(); string ckey, cvalue; while (cur->get(&ckey, &cvalue, NULL, true)) { cout << ckey << ":" << cvalue << endl; } delete cur; // close the database if (!db.close()) { cerr << "close error: " << db.error().name() << endl; } return 0; } @endcode The following code is an example to use the TCP server framework. @code #include <ktthserv.h> using namespace std; using namespace kyototycoon; // the flag whether the server is alive ThreadedServer* g_serv = NULL; // stop the running server static void stopserver(int signum) { if (g_serv) g_serv->stop(); g_serv = NULL; } // main routine int main(int argc, char** argv) { // set the signal handler to stop the server setkillsignalhandler(stopserver); // prepare the worker class Worker : public ThreadedServer::Worker { bool process(ThreadedServer* serv, ThreadedServer::Session* sess) { bool keep = false; // read a line from the client socket char line[1024]; if (sess->receive_line(line, sizeof(line))) { if (!kc::stricmp(line, "/quit")) { // process the quit command sess->printf("> Bye!\n"); } else { // echo back the message sess->printf("> %s\n", line); keep = true; } } return keep; } }; Worker worker; // prepare the server ThreadedServer serv; serv.set_network("127.0.0.1:1978", 1.0); serv.set_worker(&worker, 4); g_serv = &serv; // start the server and block until its stop serv.start(); // clean up connections and other resources serv.finish(); return 0; } @endcode */ /** * Common namespace of Kyoto Tycoon. */ namespace kyototycoon {} /** * @file ktcommon.h common symbols for the library * @file ktutil.h utility functions * @file ktsocket.h network functions * @file ktthserv.h threaded server * @file kthttp.h HTTP utilities * @file ktrpc.h RPC utilities * @file ktulog.h update logger * @file ktshlib.h shared library * @file kttimeddb.h timed database * @file ktdbext.h database extension * @file ktremotedb.h remote database * @file ktplugserv.h pluggable server interface * @file ktplugdb.h pluggable database interface */ ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/configure.in���������������������������������������������������������������������0000644�0001750�0001750�00000026427�11750230304�015535� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Source of configuration for Kyoto Tycoon #================================================================ # Generic Settings #================================================================ # Package name AC_INIT(kyototycoon, 0.9.56) # Package information MYLIBVER=2 MYLIBREV=19 # Targets MYHEADERFILES="ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h ktrpc.h ktulog.h ktshlib.h" MYHEADERFILES="$MYHEADERFILES kttimeddb.h ktdbext.h ktremotedb.h ktplugserv.h ktplugdb.h" MYLIBRARYFILES="libkyototycoon.a" MYLIBOBJFILES="ktutil.o ktsocket.o ktthserv.o kthttp.o ktrpc.o ktulog.o ktshlib.o" MYLIBOBJFILES="$MYLIBOBJFILES kttimeddb.o ktdbext.o ktremotedb.o ktplugserv.o ktplugdb.o" MYSHLIBFILES="ktplugservmemc.so ktplugdbvoid.so" MYCOMMANDFILES="ktutiltest ktutilmgr ktutilserv kttimedtest kttimedmgr" MYCOMMANDFILES="$MYCOMMANDFILES ktserver ktremotetest ktremotemgr" MYMAN1FILES="ktutiltest.1 ktutilmgr.1 ktutilserv.1 kttimedtest.1 kttimedmgr.1" MYMAN1FILES="$MYMAN1FILES ktserver.1 ktremotetest.1 ktremotemgr.1" MYDOCUMENTFILES="COPYING ChangeLog doc kyototycoon.idl" MYPCFILES="kyototycoon.pc" # Building flags MYCFLAGS="-Wall -ansi -pedantic -fPIC -fsigned-char -g0 -O2" MYCXXFLAGS="-Wall -fPIC -fsigned-char -g0 -O2" MYCPPFLAGS="-I. -I\$(INCLUDEDIR) -I/usr/local/include" MYCPPFLAGS="$MYCPPFLAGS -DNDEBUG -D_GNU_SOURCE=1" MYCPPFLAGS="$MYCPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT -D__EXTENSIONS__" MYLDFLAGS="-L. -L\$(LIBDIR) -L/usr/local/lib" MYCMDLDFLAGS="" MYCMDLIBS="" MYLDLIBPATH="" MYLDLIBPATHENV="LD_LIBRARY_PATH" MYPOSTCMD="true" # Building paths PATH=".:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:$PATH" CPATH=".:/usr/local/include:$CPATH" LIBRARY_PATH=".:/usr/local/lib:$LIBRARY_PATH" LD_LIBRARY_PATH=".:/usr/local/lib:$LD_LIBRARY_PATH" PKG_CONFIG_PATH=".:/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH" export PATH CPATH LIBRARY_PATH LD_LIBRARY_PATH PKG_CONFIG_PATH #================================================================ # Options #================================================================ # Internal variables enables="" is_static="" # Debug mode AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [build for debugging])) if test "$enable_debug" = "yes" then MYCFLAGS="-Wall -ansi -pedantic -fPIC -fsigned-char -g -O0" MYCXXFLAGS="-Wall -fPIC -fsigned-char -g -O0" MYCPPFLAGS="$MYCPPFLAGS -UNDEBUG -D_KCDEBUG" is_static="yes" enables="$enables (debug)" fi # Developping mode AC_ARG_ENABLE(devel, AC_HELP_STRING([--enable-devel], [build for development])) if test "$enable_devel" = "yes" then MYCFLAGS="-Wall -Wextra -Wno-unused-parameter" MYCFLAGS="$MYCFLAGS -ansi -pedantic -fPIC -fsigned-char -O2 -fno-inline -pipe" MYCXXFLAGS="-Wall -Wextra -Wno-unused-parameter -Wnon-virtual-dtor" MYCXXFLAGS="$MYCXXFLAGS -fPIC -fsigned-char -g -O2 -fno-inline -pipe" MYCPPFLAGS="$MYCPPFLAGS -UNDEBUG -D_KCDEBUG" enables="$enables (devel)" fi # Disable optimization AC_ARG_ENABLE(opt, AC_HELP_STRING([--disable-opt], [build without optimization])) if test "$enable_opt" = "no" then MYCFLAGS="$MYCFLAGS -O0" MYCXXFLAGS="$MYCXXFLAGS -O0" enables="$enables (no-opt)" fi # Profiling mode AC_ARG_ENABLE(profile, AC_HELP_STRING([--enable-profile], [build for profiling])) if test "$enable_profile" = "yes" then MYCXXFLAGS="-Wall -fPIC -fsigned-char -g -pg -O2 -fno-inline -pipe" enables="$enables (profile)" fi # Micro yield mode AC_ARG_ENABLE(uyield, AC_HELP_STRING([--enable-uyield], [build for detecting race conditions])) if test "$enable_uyield" = "yes" then MYCPPFLAGS="$MYCPPFLAGS -UNDEBUG -D_KCUYIELD" enables="$enables (uyield)" fi # Static mode AC_ARG_ENABLE(static, AC_HELP_STRING([--enable-static], [build by static linking])) if test "$enable_static" = "yes" then is_static="yes" enables="$enables (static)" fi # Disable shared object AC_ARG_ENABLE(shared, AC_HELP_STRING([--disable-shared], [avoid to build shared libraries])) if test "$enable_shared" = "no" then enables="$enables (no-shared)" fi # Disable specific event notifiers AC_ARG_ENABLE(event, AC_HELP_STRING([--disable-event], [avoid to use system-specific event notifiers])) if test "$enable_event" = "no" then MYCPPFLAGS="$MYCPPFLAGS -D_MYNOEVENT" enables="$enables (no-event)" fi # Enable Lua extension AC_ARG_ENABLE(lua, AC_HELP_STRING([--enable-lua], [build with Lua extension])) if test "$enable_lua" = "yes" then luaver=`lua -e 'v = string.gsub(_VERSION, ".* ", ""); print(v)'` MYCPPFLAGS="$MYCPPFLAGS -D_MYLUA" MYCPPFLAGS="$MYCPPFLAGS -I/usr/include/lua$luaver -I/usr/local/include/lua$luaver" MYCPPFLAGS="$MYCPPFLAGS -I/usr/include/lua -I/usr/local/include/lua" MYLDFLAGS="$MYLDFLAGS -L/usr/lib/lua$luaver -L/usr/local/lib/lua$luaver" MYLDFLAGS="$MYLDFLAGS -L/usr/lib/lua -L/usr/local/lib/lua" LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib/lua$luaver:/usr/local/lib/lua$luaver" LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib/lua:/usr/local/lib/lua" LIBRARY_PATH="$LIBRARY_PATH:/usr/lib/lua$luaver:/usr/local/lib/lua$luaver" LIBRARY_PATH="$LIBRARY_PATH:/usr/lib/lua:/usr/local/lib/lua" CPATH="$CPATH:/usr/include/lua$luaver:/usr/local/include/lua$luaver" CPATH="$CPATH:/usr/include/lua:/usr/local/include/lua" enables="$enables (lua)" fi # Specify the installation path of Kyoto Cabinet AC_ARG_WITH(kc, AC_HELP_STRING([--with-kc=DIR], [search DIR/include and DIR/lib for Kyoto Cabinet])) if test -n "$with_kc" then MYCPPFLAGS="$MYCPPFLAGS -I$with_kc/include" MYLDFLAGS="$MYLDFLAGS -L$with_kc/lib" CPATH="$CPATH:$with_kc/include" LIBRARY_PATH="$LIBRARY_PATH:$with_kc/lib" LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$with_kc/lib" PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$with_kc/lib/pkgconfig" fi # Specify the installation path of Lua AC_ARG_WITH(lua, AC_HELP_STRING([--with-lua=DIR], [search DIR/include and DIR/lib for Lua])) if test -n "$with_lua" then MYCPPFLAGS="$MYCPPFLAGS -I$with_lua/include" MYLDFLAGS="$MYLDFLAGS -L$with_lua/lib" CPATH="$CPATH:$with_lua/include" LIBRARY_PATH="$LIBRARY_PATH:$with_lua/lib" LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$with_lua/lib" PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$with_lua/lib/pkgconfig" fi # Messages printf '#================================================================\n' printf '# Configuring Kyoto Tycoon version %s%s.\n' "$PACKAGE_VERSION" "$enables" printf '#================================================================\n' #================================================================ # Checking Commands and Libraries #================================================================ # C and C++ compilers AC_PROG_CC AC_PROG_CXX AC_LANG(C++) # Reset variables if test "$GCC" != "yes" then AC_MSG_WARN([another compiler except for GCC was detected]) MYCFLAGS="" MYCXXFLAGS="" fi test -n "$CFLAGS" && MYCFLAGS="$CFLAGS $MYCFLAGS" test -n "$CXXFLAGS" && MYCXXFLAGS="$CXXFLAGS $MYCXXFLAGS" test -n "$CPPFLAGS" && MYCPPFLAGS="$CPPFLAGS $MYCPPFLAGS" test -n "$LDFLAGS" && MYLDFLAGS="$LDFLAGS $MYLDFLAGS" # System-depending optimization printf 'checking for 64-bit availability... ' if printf 'main() {}' | $CC -xc -m64 -o config.tmp - >config.tmp 2>&1 then MYCFLAGS="-m64 $MYCFLAGS" MYCXXFLAGS="-m64 $MYCXXFLAGS" printf 'yes\n' else printf 'no\n' fi if test "$enable_opt" != "no" then printf 'checking for CPU optimization availability... ' if printf 'main() {}' | $CC -xc -march=native -o config.tmp - >config.tmp 2>&1 then MYCFLAGS="-march=native $MYCFLAGS" MYCXXFLAGS="-march=native $MYCXXFLAGS" printf 'yes\n' else printf 'no\n' fi fi printf 'checking for useless warnings... ' if printf 'main() {}' | $CC -xc \ -Wno-unused-but-set-variable -Wno-unused-but-set-parameter -o config.tmp - >config.tmp 2>&1 then MYCFLAGS="$MYCFLAGS -Wno-unused-but-set-variable -Wno-unused-but-set-parameter" MYCXXFLAGS="$MYCXXFLAGS -Wno-unused-but-set-variable -Wno-unused-but-set-parameter" printf 'yes\n' else printf 'no\n' fi # Underlying libraries AC_CHECK_LIB(c, main) AC_CHECK_LIB(m, main) AC_CHECK_LIB(pthread, main) AC_CHECK_LIB(rt, main) AC_CHECK_LIB(dl, main) AC_CHECK_LIB(nsl, main) AC_CHECK_LIB(socket, main) AC_CHECK_LIB(resolv, main) AC_CHECK_LIB(stdc++, main) AC_CHECK_LIB(regex, main) AC_CHECK_LIB(z, main) AC_CHECK_LIB(lzo2, main) AC_CHECK_LIB(lzma, main) AC_CHECK_LIB(kyotocabinet, main) AC_CHECK_LIB(kyotocabinet, main, MYCMDLIBS="$MYCMDLIBS -lkyotocabinet") if test "$enable_lua" = "yes" then AC_CHECK_LIB(lua, main, MYCMDLIBS="$MYCMDLIBS -llua") AC_CHECK_LIB(lua$luaver, main, MYCMDLIBS="$MYCMDLIBS -llua$luaver") fi AC_CHECK_LIB(kyototycoon, main, AC_MSG_WARN([old version of Kyoto Tycoon was detected])) MYLDLIBPATH="$LD_LIBRARY_PATH" # Necessary headers AC_CHECK_HEADER(stdlib.h, true, AC_MSG_ERROR([stdlib.h is required])) AC_CHECK_HEADER(stdint.h, true, AC_MSG_ERROR([stdint.h is required])) AC_CHECK_HEADER(unistd.h, true, AC_MSG_ERROR([unistd.h is required])) AC_CHECK_HEADER(sys/socket.h, true, AC_MSG_ERROR([sys/socket.h is required])) AC_CHECK_HEADER(kccommon.h, true, AC_MSG_ERROR([kccommon.h is required])) if test "$enable_lua" = "yes" then AC_CHECK_HEADER(lua.h, true, AC_MSG_ERROR([lua.h is required])) fi # Static linking if test "$is_static" = "yes" then MYCMDLDFLAGS="$MYCMDLDFLAGS -static" MYCMDLIBS="$MYCMDLIBS $LIBS" fi # As-needed linking if uname | grep Linux >config.tmp then MYLDFLAGS="$MYLDFLAGS -Wl,-rpath-link,.:/usr/local/lib:$MYLDLIBPATH" MYLDFLAGS="$MYLDFLAGS -Wl,--as-needed" else MYCMDLIBS="$MYCMDLIBS $LIBS" fi # Checking the version of Kyoto Cabinet with pkg-config if type pkg-config >config.tmp 2>&1 then printf 'checking Kyoto Cabinet by pkg-config... ' if pkg-config --atleast-version=1.2.65 kyotocabinet then printf 'yes\n' else printf 'no\n' AC_MSG_ERROR([required version of Kyoto Cabinet was not detected]) fi fi # Shared libraries if test "$enable_shared" != "no" && test "$enable_profile" != "yes" then if uname | grep Darwin >config.tmp then MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.$MYLIBVER.$MYLIBREV.0.dylib" MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.$MYLIBVER.dylib" MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.dylib" MYLDLIBPATHENV="DYLD_LIBRARY_PATH" else MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.so.$MYLIBVER.$MYLIBREV.0" MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.so.$MYLIBVER" MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.so" fi fi if uname | grep Darwin >config.tmp then MYSHLIBFILES="ktplugservmemc.dylib" fi # Work around of bugs of some environments if uname | grep Darwin >config.tmp then MYCFLAGS="$MYCFLAGS -Os" MYCXXFLAGS="$MYCXXFLAGS -Os" fi #================================================================ # Generic Settings #================================================================ # Export variables AC_SUBST(MYLIBVER) AC_SUBST(MYLIBREV) AC_SUBST(MYFORMATVER) AC_SUBST(MYHEADERFILES) AC_SUBST(MYLIBRARYFILES) AC_SUBST(MYLIBOBJFILES) AC_SUBST(MYSHLIBFILES) AC_SUBST(MYCOMMANDFILES) AC_SUBST(MYMAN1FILES) AC_SUBST(MYDOCUMENTFILES) AC_SUBST(MYPCFILES) AC_SUBST(MYCFLAGS) AC_SUBST(MYCXXFLAGS) AC_SUBST(MYCPPFLAGS) AC_SUBST(MYLDFLAGS) AC_SUBST(MYCMDLDFLAGS) AC_SUBST(MYCMDLIBS) AC_SUBST(MYLDLIBPATH) AC_SUBST(MYLDLIBPATHENV) AC_SUBST(MYPOSTCMD) # Targets AC_OUTPUT(Makefile kyototycoon.pc) # Messages printf '#================================================================\n' printf '# Ready to make.\n' printf '#================================================================\n' # END OF FILE �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/configure������������������������������������������������������������������������0000755�0001750�0001750�00000477312�11750230313�015136� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /bin/sh # Guess values for system-dependent variables and create Makefiles. # Generated by GNU Autoconf 2.68 for kyototycoon 0.9.56. # # # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, # 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software # Foundation, Inc. # # # This configure script is free software; the Free Software Foundation # gives unlimited permission to copy, distribute and modify it. ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH if test "x$CONFIG_SHELL" = x; then as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which # is contrary to our usage. Disable this feature. alias -g '\${1+\"\$@\"}'='\"\$@\"' setopt NO_GLOB_SUBST else case \`(set -o) 2>/dev/null\` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi " as_required="as_fn_return () { (exit \$1); } as_fn_success () { as_fn_return 0; } as_fn_failure () { as_fn_return 1; } as_fn_ret_success () { return 0; } as_fn_ret_failure () { return 1; } exitcode=0 as_fn_success || { exitcode=1; echo as_fn_success failed.; } as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : else exitcode=1; echo positional parameters were not saved. fi test x\$exitcode = x0 || exit 1" as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1 test \$(( 1 + 1 )) = 2 || exit 1" if (eval "$as_required") 2>/dev/null; then : as_have_required=yes else as_have_required=no fi if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR as_found=false for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. as_found=: case $as_dir in #( /*) for as_base in sh bash ksh sh5; do # Try only shells that exist, to save several forks. as_shell=$as_dir/$as_base if { test -f "$as_shell" || test -f "$as_shell.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : CONFIG_SHELL=$as_shell as_have_required=yes if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : break 2 fi fi done;; esac as_found=false done $as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : CONFIG_SHELL=$SHELL as_have_required=yes fi; } IFS=$as_save_IFS if test "x$CONFIG_SHELL" != x; then : # We cannot yet assume a decent shell, so we have to provide a # neutralization value for shells without unset; and this also # works around shells that cannot unset nonexistent variables. # Preserve -v and -x to the replacement shell. BASH_ENV=/dev/null ENV=/dev/null (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV export CONFIG_SHELL case $- in # (((( *v*x* | *x*v* ) as_opts=-vx ;; *v* ) as_opts=-v ;; *x* ) as_opts=-x ;; * ) as_opts= ;; esac exec "$CONFIG_SHELL" $as_opts "$as_myself" ${1+"$@"} fi if test x$as_have_required = xno; then : $as_echo "$0: This script requires a shell more modern than all" $as_echo "$0: the shells that I found on your system." if test x${ZSH_VERSION+set} = xset ; then $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" $as_echo "$0: be upgraded to zsh 4.3.4 or later." else $as_echo "$0: Please tell bug-autoconf@gnu.org about your system, $0: including any error possibly output before this $0: message. Then install a modern shell, or manually run $0: the script under such a shell if you do have one." fi exit 1 fi fi fi SHELL=${CONFIG_SHELL-/bin/sh} export SHELL # Unset more variables known to interfere with behavior of common tools. CLICOLOR_FORCE= GREP_OPTIONS= unset CLICOLOR_FORCE GREP_OPTIONS ## --------------------- ## ## M4sh Shell Functions. ## ## --------------------- ## # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits as_lineno_1=$LINENO as_lineno_1a=$LINENO as_lineno_2=$LINENO as_lineno_2a=$LINENO eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) sed -n ' p /[$]LINENO/= ' <$as_myself | sed ' s/[$]LINENO.*/&-/ t lineno b :lineno N :loop s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ t loop s/-\n.*// ' >$as_me.lineno && chmod +x "$as_me.lineno" || { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } # Don't try to exec as it changes $[0], causing all sort of problems # (the dirname of $[0] is not the place where we might find the # original and so on. Autoconf is especially sensitive to this). . "./$as_me.lineno" # Exit status is that of the last command. exit } ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" test -n "$DJDIR" || exec 7<&0 </dev/null exec 6>&1 # Name of the host. # hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status, # so uname gets run too. ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` # # Initializations. # ac_default_prefix=/usr/local ac_clean_files= ac_config_libobj_dir=. LIBOBJS= cross_compiling=no subdirs= MFLAGS= MAKEFLAGS= # Identity of this package. PACKAGE_NAME='kyototycoon' PACKAGE_TARNAME='kyototycoon' PACKAGE_VERSION='0.9.56' PACKAGE_STRING='kyototycoon 0.9.56' PACKAGE_BUGREPORT='' PACKAGE_URL='' # Factoring default headers for most tests. ac_includes_default="\ #include <stdio.h> #ifdef HAVE_SYS_TYPES_H # include <sys/types.h> #endif #ifdef HAVE_SYS_STAT_H # include <sys/stat.h> #endif #ifdef STDC_HEADERS # include <stdlib.h> # include <stddef.h> #else # ifdef HAVE_STDLIB_H # include <stdlib.h> # endif #endif #ifdef HAVE_STRING_H # if !defined STDC_HEADERS && defined HAVE_MEMORY_H # include <memory.h> # endif # include <string.h> #endif #ifdef HAVE_STRINGS_H # include <strings.h> #endif #ifdef HAVE_INTTYPES_H # include <inttypes.h> #endif #ifdef HAVE_STDINT_H # include <stdint.h> #endif #ifdef HAVE_UNISTD_H # include <unistd.h> #endif" ac_subst_vars='LTLIBOBJS LIBOBJS MYPOSTCMD MYLDLIBPATHENV MYLDLIBPATH MYCMDLIBS MYCMDLDFLAGS MYLDFLAGS MYCPPFLAGS MYCXXFLAGS MYCFLAGS MYPCFILES MYDOCUMENTFILES MYMAN1FILES MYCOMMANDFILES MYSHLIBFILES MYLIBOBJFILES MYLIBRARYFILES MYHEADERFILES MYFORMATVER MYLIBREV MYLIBVER EGREP GREP CXXCPP ac_ct_CXX CXXFLAGS CXX OBJEXT EXEEXT ac_ct_CC CPPFLAGS LDFLAGS CFLAGS CC target_alias host_alias build_alias LIBS ECHO_T ECHO_N ECHO_C DEFS mandir localedir libdir psdir pdfdir dvidir htmldir infodir docdir oldincludedir includedir localstatedir sharedstatedir sysconfdir datadir datarootdir libexecdir sbindir bindir program_transform_name prefix exec_prefix PACKAGE_URL PACKAGE_BUGREPORT PACKAGE_STRING PACKAGE_VERSION PACKAGE_TARNAME PACKAGE_NAME PATH_SEPARATOR SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking enable_debug enable_devel enable_opt enable_profile enable_uyield enable_static enable_shared enable_event enable_lua with_kc with_lua ' ac_precious_vars='build_alias host_alias target_alias CC CFLAGS LDFLAGS LIBS CPPFLAGS CXX CXXFLAGS CCC CXXCPP' # Initialize some variables set by options. ac_init_help= ac_init_version=false ac_unrecognized_opts= ac_unrecognized_sep= # The variables have the same names as the options, with # dashes changed to underlines. cache_file=/dev/null exec_prefix=NONE no_create= no_recursion= prefix=NONE program_prefix=NONE program_suffix=NONE program_transform_name=s,x,x, silent= site= srcdir= verbose= x_includes=NONE x_libraries=NONE # Installation directory options. # These are left unexpanded so users can "make install exec_prefix=/foo" # and all the variables that are supposed to be based on exec_prefix # by default will actually change. # Use braces instead of parens because sh, perl, etc. also accept them. # (The list follows the same order as the GNU Coding Standards.) bindir='${exec_prefix}/bin' sbindir='${exec_prefix}/sbin' libexecdir='${exec_prefix}/libexec' datarootdir='${prefix}/share' datadir='${datarootdir}' sysconfdir='${prefix}/etc' sharedstatedir='${prefix}/com' localstatedir='${prefix}/var' includedir='${prefix}/include' oldincludedir='/usr/include' docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' infodir='${datarootdir}/info' htmldir='${docdir}' dvidir='${docdir}' pdfdir='${docdir}' psdir='${docdir}' libdir='${exec_prefix}/lib' localedir='${datarootdir}/locale' mandir='${datarootdir}/man' ac_prev= ac_dashdash= for ac_option do # If the previous option needs an argument, assign it. if test -n "$ac_prev"; then eval $ac_prev=\$ac_option ac_prev= continue fi case $ac_option in *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; *=) ac_optarg= ;; *) ac_optarg=yes ;; esac # Accept the important Cygnus configure options, so we can diagnose typos. case $ac_dashdash$ac_option in --) ac_dashdash=yes ;; -bindir | --bindir | --bindi | --bind | --bin | --bi) ac_prev=bindir ;; -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) bindir=$ac_optarg ;; -build | --build | --buil | --bui | --bu) ac_prev=build_alias ;; -build=* | --build=* | --buil=* | --bui=* | --bu=*) build_alias=$ac_optarg ;; -cache-file | --cache-file | --cache-fil | --cache-fi \ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) ac_prev=cache_file ;; -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) cache_file=$ac_optarg ;; --config-cache | -C) cache_file=config.cache ;; -datadir | --datadir | --datadi | --datad) ac_prev=datadir ;; -datadir=* | --datadir=* | --datadi=* | --datad=*) datadir=$ac_optarg ;; -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ | --dataroo | --dataro | --datar) ac_prev=datarootdir ;; -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) datarootdir=$ac_optarg ;; -disable-* | --disable-*) ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=no ;; -docdir | --docdir | --docdi | --doc | --do) ac_prev=docdir ;; -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) docdir=$ac_optarg ;; -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) ac_prev=dvidir ;; -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) dvidir=$ac_optarg ;; -enable-* | --enable-*) ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid feature name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "enable_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval enable_$ac_useropt=\$ac_optarg ;; -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ | --exec | --exe | --ex) ac_prev=exec_prefix ;; -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ | --exec=* | --exe=* | --ex=*) exec_prefix=$ac_optarg ;; -gas | --gas | --ga | --g) # Obsolete; use --with-gas. with_gas=yes ;; -help | --help | --hel | --he | -h) ac_init_help=long ;; -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) ac_init_help=recursive ;; -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) ac_init_help=short ;; -host | --host | --hos | --ho) ac_prev=host_alias ;; -host=* | --host=* | --hos=* | --ho=*) host_alias=$ac_optarg ;; -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) ac_prev=htmldir ;; -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ | --ht=*) htmldir=$ac_optarg ;; -includedir | --includedir | --includedi | --included | --include \ | --includ | --inclu | --incl | --inc) ac_prev=includedir ;; -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ | --includ=* | --inclu=* | --incl=* | --inc=*) includedir=$ac_optarg ;; -infodir | --infodir | --infodi | --infod | --info | --inf) ac_prev=infodir ;; -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) infodir=$ac_optarg ;; -libdir | --libdir | --libdi | --libd) ac_prev=libdir ;; -libdir=* | --libdir=* | --libdi=* | --libd=*) libdir=$ac_optarg ;; -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ | --libexe | --libex | --libe) ac_prev=libexecdir ;; -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ | --libexe=* | --libex=* | --libe=*) libexecdir=$ac_optarg ;; -localedir | --localedir | --localedi | --localed | --locale) ac_prev=localedir ;; -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) localedir=$ac_optarg ;; -localstatedir | --localstatedir | --localstatedi | --localstated \ | --localstate | --localstat | --localsta | --localst | --locals) ac_prev=localstatedir ;; -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) localstatedir=$ac_optarg ;; -mandir | --mandir | --mandi | --mand | --man | --ma | --m) ac_prev=mandir ;; -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) mandir=$ac_optarg ;; -nfp | --nfp | --nf) # Obsolete; use --without-fp. with_fp=no ;; -no-create | --no-create | --no-creat | --no-crea | --no-cre \ | --no-cr | --no-c | -n) no_create=yes ;; -no-recursion | --no-recursion | --no-recursio | --no-recursi \ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) no_recursion=yes ;; -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ | --oldin | --oldi | --old | --ol | --o) ac_prev=oldincludedir ;; -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) oldincludedir=$ac_optarg ;; -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) ac_prev=prefix ;; -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) prefix=$ac_optarg ;; -program-prefix | --program-prefix | --program-prefi | --program-pref \ | --program-pre | --program-pr | --program-p) ac_prev=program_prefix ;; -program-prefix=* | --program-prefix=* | --program-prefi=* \ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) program_prefix=$ac_optarg ;; -program-suffix | --program-suffix | --program-suffi | --program-suff \ | --program-suf | --program-su | --program-s) ac_prev=program_suffix ;; -program-suffix=* | --program-suffix=* | --program-suffi=* \ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) program_suffix=$ac_optarg ;; -program-transform-name | --program-transform-name \ | --program-transform-nam | --program-transform-na \ | --program-transform-n | --program-transform- \ | --program-transform | --program-transfor \ | --program-transfo | --program-transf \ | --program-trans | --program-tran \ | --progr-tra | --program-tr | --program-t) ac_prev=program_transform_name ;; -program-transform-name=* | --program-transform-name=* \ | --program-transform-nam=* | --program-transform-na=* \ | --program-transform-n=* | --program-transform-=* \ | --program-transform=* | --program-transfor=* \ | --program-transfo=* | --program-transf=* \ | --program-trans=* | --program-tran=* \ | --progr-tra=* | --program-tr=* | --program-t=*) program_transform_name=$ac_optarg ;; -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) ac_prev=pdfdir ;; -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) pdfdir=$ac_optarg ;; -psdir | --psdir | --psdi | --psd | --ps) ac_prev=psdir ;; -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) psdir=$ac_optarg ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) silent=yes ;; -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) ac_prev=sbindir ;; -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ | --sbi=* | --sb=*) sbindir=$ac_optarg ;; -sharedstatedir | --sharedstatedir | --sharedstatedi \ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ | --sharedst | --shareds | --shared | --share | --shar \ | --sha | --sh) ac_prev=sharedstatedir ;; -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ | --sha=* | --sh=*) sharedstatedir=$ac_optarg ;; -site | --site | --sit) ac_prev=site ;; -site=* | --site=* | --sit=*) site=$ac_optarg ;; -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) ac_prev=srcdir ;; -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) srcdir=$ac_optarg ;; -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ | --syscon | --sysco | --sysc | --sys | --sy) ac_prev=sysconfdir ;; -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) sysconfdir=$ac_optarg ;; -target | --target | --targe | --targ | --tar | --ta | --t) ac_prev=target_alias ;; -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) target_alias=$ac_optarg ;; -v | -verbose | --verbose | --verbos | --verbo | --verb) verbose=yes ;; -version | --version | --versio | --versi | --vers | -V) ac_init_version=: ;; -with-* | --with-*) ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=\$ac_optarg ;; -without-* | --without-*) ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` # Reject names that are not valid shell variable names. expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && as_fn_error $? "invalid package name: $ac_useropt" ac_useropt_orig=$ac_useropt ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` case $ac_user_opts in *" "with_$ac_useropt" "*) ;; *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" ac_unrecognized_sep=', ';; esac eval with_$ac_useropt=no ;; --x) # Obsolete; use --with-x. with_x=yes ;; -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ | --x-incl | --x-inc | --x-in | --x-i) ac_prev=x_includes ;; -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) x_includes=$ac_optarg ;; -x-libraries | --x-libraries | --x-librarie | --x-librari \ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) ac_prev=x_libraries ;; -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) x_libraries=$ac_optarg ;; -*) as_fn_error $? "unrecognized option: \`$ac_option' Try \`$0 --help' for more information" ;; *=*) ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` # Reject names that are not valid shell variable names. case $ac_envvar in #( '' | [0-9]* | *[!_$as_cr_alnum]* ) as_fn_error $? "invalid variable name: \`$ac_envvar'" ;; esac eval $ac_envvar=\$ac_optarg export $ac_envvar ;; *) # FIXME: should be removed in autoconf 3.0. $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}" ;; esac done if test -n "$ac_prev"; then ac_option=--`echo $ac_prev | sed 's/_/-/g'` as_fn_error $? "missing argument to $ac_option" fi if test -n "$ac_unrecognized_opts"; then case $enable_option_checking in no) ;; fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;; *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; esac fi # Check all directory arguments for consistency. for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ datadir sysconfdir sharedstatedir localstatedir includedir \ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ libdir localedir mandir do eval ac_val=\$$ac_var # Remove trailing slashes. case $ac_val in */ ) ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` eval $ac_var=\$ac_val;; esac # Be sure to have absolute directory names. case $ac_val in [\\/$]* | ?:[\\/]* ) continue;; NONE | '' ) case $ac_var in *prefix ) continue;; esac;; esac as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val" done # There might be people who depend on the old broken behavior: `$host' # used to hold the argument of --host etc. # FIXME: To remove some day. build=$build_alias host=$host_alias target=$target_alias # FIXME: To remove some day. if test "x$host_alias" != x; then if test "x$build_alias" = x; then cross_compiling=maybe $as_echo "$as_me: WARNING: if you wanted to set the --build type, don't use --host. If a cross compiler is detected then cross compile mode will be used" >&2 elif test "x$build_alias" != "x$host_alias"; then cross_compiling=yes fi fi ac_tool_prefix= test -n "$host_alias" && ac_tool_prefix=$host_alias- test "$silent" = yes && exec 6>/dev/null ac_pwd=`pwd` && test -n "$ac_pwd" && ac_ls_di=`ls -di .` && ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || as_fn_error $? "working directory cannot be determined" test "X$ac_ls_di" = "X$ac_pwd_ls_di" || as_fn_error $? "pwd does not report name of working directory" # Find the source files, if location was not specified. if test -z "$srcdir"; then ac_srcdir_defaulted=yes # Try the directory containing this script, then the parent directory. ac_confdir=`$as_dirname -- "$as_myself" || $as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_myself" : 'X\(//\)[^/]' \| \ X"$as_myself" : 'X\(//\)$' \| \ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_myself" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` srcdir=$ac_confdir if test ! -r "$srcdir/$ac_unique_file"; then srcdir=.. fi else ac_srcdir_defaulted=no fi if test ! -r "$srcdir/$ac_unique_file"; then test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir" fi ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" ac_abs_confdir=`( cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg" pwd)` # When building in place, set srcdir=. if test "$ac_abs_confdir" = "$ac_pwd"; then srcdir=. fi # Remove unnecessary trailing slashes from srcdir. # Double slashes in file names in object file debugging info # mess up M-x gdb in Emacs. case $srcdir in */) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; esac for ac_var in $ac_precious_vars; do eval ac_env_${ac_var}_set=\${${ac_var}+set} eval ac_env_${ac_var}_value=\$${ac_var} eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} eval ac_cv_env_${ac_var}_value=\$${ac_var} done # # Report the --help message. # if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF \`configure' configures kyototycoon 0.9.56 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... To assign environment variables (e.g., CC, CFLAGS...), specify them as VAR=VALUE. See below for descriptions of some of the useful variables. Defaults for the options are specified in brackets. Configuration: -h, --help display this help and exit --help=short display options specific to this package --help=recursive display the short help of all the included packages -V, --version display version information and exit -q, --quiet, --silent do not print \`checking ...' messages --cache-file=FILE cache test results in FILE [disabled] -C, --config-cache alias for \`--cache-file=config.cache' -n, --no-create do not create output files --srcdir=DIR find the sources in DIR [configure dir or \`..'] Installation directories: --prefix=PREFIX install architecture-independent files in PREFIX [$ac_default_prefix] --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX [PREFIX] By default, \`make install' will install all the files in \`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify an installation prefix other than \`$ac_default_prefix' using \`--prefix', for instance \`--prefix=\$HOME'. For better control, use the options below. Fine tuning of the installation directories: --bindir=DIR user executables [EPREFIX/bin] --sbindir=DIR system admin executables [EPREFIX/sbin] --libexecdir=DIR program executables [EPREFIX/libexec] --sysconfdir=DIR read-only single-machine data [PREFIX/etc] --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] --localstatedir=DIR modifiable single-machine data [PREFIX/var] --libdir=DIR object code libraries [EPREFIX/lib] --includedir=DIR C header files [PREFIX/include] --oldincludedir=DIR C header files for non-gcc [/usr/include] --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] --datadir=DIR read-only architecture-independent data [DATAROOTDIR] --infodir=DIR info documentation [DATAROOTDIR/info] --localedir=DIR locale-dependent data [DATAROOTDIR/locale] --mandir=DIR man documentation [DATAROOTDIR/man] --docdir=DIR documentation root [DATAROOTDIR/doc/kyototycoon] --htmldir=DIR html documentation [DOCDIR] --dvidir=DIR dvi documentation [DOCDIR] --pdfdir=DIR pdf documentation [DOCDIR] --psdir=DIR ps documentation [DOCDIR] _ACEOF cat <<\_ACEOF _ACEOF fi if test -n "$ac_init_help"; then case $ac_init_help in short | recursive ) echo "Configuration of kyototycoon 0.9.56:";; esac cat <<\_ACEOF Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] --enable-debug build for debugging --enable-devel build for development --disable-opt build without optimization --enable-profile build for profiling --enable-uyield build for detecting race conditions --enable-static build by static linking --disable-shared avoid to build shared libraries --disable-event avoid to use system-specific event notifiers --enable-lua build with Lua extension Optional Packages: --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) --with-kc=DIR search DIR/include and DIR/lib for Kyoto Cabinet --with-lua=DIR search DIR/include and DIR/lib for Lua Some influential environment variables: CC C compiler command CFLAGS C compiler flags LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a nonstandard directory <lib dir> LIBS libraries to pass to the linker, e.g. -l<library> CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if you have headers in a nonstandard directory <include dir> CXX C++ compiler command CXXFLAGS C++ compiler flags CXXCPP C++ preprocessor Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. Report bugs to the package provider. _ACEOF ac_status=$? fi if test "$ac_init_help" = "recursive"; then # If there are subdirs, report their specific --help. for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue test -d "$ac_dir" || { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || continue ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix cd "$ac_dir" || { ac_status=$?; continue; } # Check for guested configure. if test -f "$ac_srcdir/configure.gnu"; then echo && $SHELL "$ac_srcdir/configure.gnu" --help=recursive elif test -f "$ac_srcdir/configure"; then echo && $SHELL "$ac_srcdir/configure" --help=recursive else $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 fi || ac_status=$? cd "$ac_pwd" || { ac_status=$?; break; } done fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF kyototycoon configure 0.9.56 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. This configure script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. _ACEOF exit fi ## ------------------------ ## ## Autoconf initialization. ## ## ------------------------ ## # ac_fn_c_try_compile LINENO # -------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_c_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_c_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_c_try_compile # ac_fn_cxx_try_compile LINENO # ---------------------------- # Try to compile conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest.$ac_objext; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_compile # ac_fn_cxx_try_link LINENO # ------------------------- # Try to link conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_link () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack rm -f conftest.$ac_objext conftest$ac_exeext if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { test -z "$ac_cxx_werror_flag" || test ! -s conftest.err } && test -s conftest$ac_exeext && { test "$cross_compiling" = yes || $as_test_x conftest$ac_exeext }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would # interfere with the next link command; also delete a directory that is # left behind by Apple's compiler. We do this before executing the actions. rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_link # ac_fn_cxx_try_cpp LINENO # ------------------------ # Try to preprocess conftest.$ac_ext, and return whether this succeeded. ac_fn_cxx_try_cpp () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_cpp conftest.$ac_ext" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err ac_status=$? if test -s conftest.err; then grep -v '^ *+' conftest.err >conftest.er1 cat conftest.er1 >&5 mv -f conftest.er1 conftest.err fi $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } > conftest.i && { test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || test ! -s conftest.err }; then : ac_retval=0 else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=1 fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_cpp # ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES # --------------------------------------------------------- # Tests whether HEADER exists, giving a warning if it cannot be compiled using # the include files in INCLUDES and setting the cache variable VAR # accordingly. ac_fn_cxx_check_header_mongrel () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if eval \${$3+:} false; then : { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } else # Is the header compilable? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5 $as_echo_n "checking $2 usability... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_header_compiler=yes else ac_header_compiler=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5 $as_echo "$ac_header_compiler" >&6; } # Is the header present? { $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5 $as_echo_n "checking $2 presence... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <$2> _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : ac_header_preproc=yes else ac_header_preproc=no fi rm -f conftest.err conftest.i conftest.$ac_ext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5 $as_echo "$ac_header_preproc" >&6; } # So? What about this header? case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #(( yes:no: ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5 $as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; no:yes:* ) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5 $as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5 $as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5 $as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5 $as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5 $as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;} ;; esac { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else eval "$3=\$ac_header_compiler" fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } fi eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_header_mongrel # ac_fn_cxx_try_run LINENO # ------------------------ # Try to link conftest.$ac_ext, and return whether this succeeded. Assumes # that executables *can* be run. ac_fn_cxx_try_run () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then : ac_retval=0 else $as_echo "$as_me: program exited with status $ac_status" >&5 $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 ac_retval=$ac_status fi rm -rf conftest.dSYM conftest_ipa8_conftest.oo eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno as_fn_set_status $ac_retval } # ac_fn_cxx_try_run # ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES # --------------------------------------------------------- # Tests whether HEADER exists and can be compiled using the include files in # INCLUDES, setting the cache variable VAR accordingly. ac_fn_cxx_check_header_compile () { as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5 $as_echo_n "checking for $2... " >&6; } if eval \${$3+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ $4 #include <$2> _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : eval "$3=yes" else eval "$3=no" fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi eval ac_res=\$$3 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno } # ac_fn_cxx_check_header_compile cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. It was created by kyototycoon $as_me 0.9.56, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ _ACEOF exec 5>>config.log { cat <<_ASUNAME ## --------- ## ## Platform. ## ## --------- ## hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` /bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` /bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` /usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` /bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` /bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` _ASUNAME as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. $as_echo "PATH: $as_dir" done IFS=$as_save_IFS } >&5 cat >&5 <<_ACEOF ## ----------- ## ## Core tests. ## ## ----------- ## _ACEOF # Keep a trace of the command line. # Strip out --no-create and --no-recursion so they do not pile up. # Strip out --silent because we don't want to record it for future runs. # Also quote any args containing shell meta-characters. # Make two passes to allow for proper duplicate-argument suppression. ac_configure_args= ac_configure_args0= ac_configure_args1= ac_must_keep_next=false for ac_pass in 1 2 do for ac_arg do case $ac_arg in -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil) continue ;; *\'*) ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; esac case $ac_pass in 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; 2) as_fn_append ac_configure_args1 " '$ac_arg'" if test $ac_must_keep_next = true; then ac_must_keep_next=false # Got value, back to normal. else case $ac_arg in *=* | --config-cache | -C | -disable-* | --disable-* \ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ | -with-* | --with-* | -without-* | --without-* | --x) case "$ac_configure_args0 " in "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; esac ;; -* ) ac_must_keep_next=true ;; esac fi as_fn_append ac_configure_args " '$ac_arg'" ;; esac done done { ac_configure_args0=; unset ac_configure_args0;} { ac_configure_args1=; unset ac_configure_args1;} # When interrupted or exit'd, cleanup temporary files, and complete # config.log. We remove comments because anyway the quotes in there # would cause problems or look ugly. # WARNING: Use '\'' to represent an apostrophe within the trap. # WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. trap 'exit_status=$? # Save into config.log some information that might help in debugging. { echo $as_echo "## ---------------- ## ## Cache variables. ## ## ---------------- ##" echo # The following way of writing the cache mishandles newlines in values, ( for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( *${as_nl}ac_space=\ *) sed -n \ "s/'\''/'\''\\\\'\'''\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" ;; #( *) sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) echo $as_echo "## ----------------- ## ## Output variables. ## ## ----------------- ##" echo for ac_var in $ac_subst_vars do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo if test -n "$ac_subst_files"; then $as_echo "## ------------------- ## ## File substitutions. ## ## ------------------- ##" echo for ac_var in $ac_subst_files do eval ac_val=\$$ac_var case $ac_val in *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; esac $as_echo "$ac_var='\''$ac_val'\''" done | sort echo fi if test -s confdefs.h; then $as_echo "## ----------- ## ## confdefs.h. ## ## ----------- ##" echo cat confdefs.h echo fi test "$ac_signal" != 0 && $as_echo "$as_me: caught signal $ac_signal" $as_echo "$as_me: exit $exit_status" } >&5 rm -f core *.core core.conftest.* && rm -f -r conftest* confdefs* conf$$* $ac_clean_files && exit $exit_status ' 0 for ac_signal in 1 2 13 15; do trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal done ac_signal=0 # confdefs.h avoids OS command line length limits that DEFS can exceed. rm -f -r conftest* confdefs.h $as_echo "/* confdefs.h */" > confdefs.h # Predefined preprocessor variables. cat >>confdefs.h <<_ACEOF #define PACKAGE_NAME "$PACKAGE_NAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_TARNAME "$PACKAGE_TARNAME" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_VERSION "$PACKAGE_VERSION" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_STRING "$PACKAGE_STRING" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" _ACEOF cat >>confdefs.h <<_ACEOF #define PACKAGE_URL "$PACKAGE_URL" _ACEOF # Let the site file select an alternate cache file if it wants to. # Prefer an explicitly selected file to automatically selected ones. ac_site_file1=NONE ac_site_file2=NONE if test -n "$CONFIG_SITE"; then # We do not want a PATH search for config.site. case $CONFIG_SITE in #(( -*) ac_site_file1=./$CONFIG_SITE;; */*) ac_site_file1=$CONFIG_SITE;; *) ac_site_file1=./$CONFIG_SITE;; esac elif test "x$prefix" != xNONE; then ac_site_file1=$prefix/share/config.site ac_site_file2=$prefix/etc/config.site else ac_site_file1=$ac_default_prefix/share/config.site ac_site_file2=$ac_default_prefix/etc/config.site fi for ac_site_file in "$ac_site_file1" "$ac_site_file2" do test "x$ac_site_file" = xNONE && continue if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 $as_echo "$as_me: loading site script $ac_site_file" >&6;} sed 's/^/| /' "$ac_site_file" >&5 . "$ac_site_file" \ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "failed to load site script $ac_site_file See \`config.log' for more details" "$LINENO" 5; } fi done if test -r "$cache_file"; then # Some versions of bash will fail to source /dev/null (special files # actually), so we avoid doing that. DJGPP emulates it as a regular file. if test /dev/null != "$cache_file" && test -f "$cache_file"; then { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 $as_echo "$as_me: loading cache $cache_file" >&6;} case $cache_file in [\\/]* | ?:[\\/]* ) . "$cache_file";; *) . "./$cache_file";; esac fi else { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 $as_echo "$as_me: creating cache $cache_file" >&6;} >$cache_file fi # Check that the precious variables saved in the cache have kept the same # value. ac_cache_corrupted=false for ac_var in $ac_precious_vars; do eval ac_old_set=\$ac_cv_env_${ac_var}_set eval ac_new_set=\$ac_env_${ac_var}_set eval ac_old_val=\$ac_cv_env_${ac_var}_value eval ac_new_val=\$ac_env_${ac_var}_value case $ac_old_set,$ac_new_set in set,) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} ac_cache_corrupted=: ;; ,set) { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 $as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} ac_cache_corrupted=: ;; ,);; *) if test "x$ac_old_val" != "x$ac_new_val"; then # differences in whitespace do not lead to failure. ac_old_val_w=`echo x $ac_old_val` ac_new_val_w=`echo x $ac_new_val` if test "$ac_old_val_w" != "$ac_new_val_w"; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 $as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} ac_cache_corrupted=: else { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 $as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} eval $ac_var=\$ac_old_val fi { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 $as_echo "$as_me: former value: \`$ac_old_val'" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 $as_echo "$as_me: current value: \`$ac_new_val'" >&2;} fi;; esac # Pass precious variables to config.status. if test "$ac_new_set" = set; then case $ac_new_val in *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; *) ac_arg=$ac_var=$ac_new_val ;; esac case " $ac_configure_args " in *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. *) as_fn_append ac_configure_args " '$ac_arg'" ;; esac fi done if $ac_cache_corrupted; then { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 $as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 fi ## -------------------- ## ## Main body of script. ## ## -------------------- ## ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu # Package information MYLIBVER=2 MYLIBREV=19 # Targets MYHEADERFILES="ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h ktrpc.h ktulog.h ktshlib.h" MYHEADERFILES="$MYHEADERFILES kttimeddb.h ktdbext.h ktremotedb.h ktplugserv.h ktplugdb.h" MYLIBRARYFILES="libkyototycoon.a" MYLIBOBJFILES="ktutil.o ktsocket.o ktthserv.o kthttp.o ktrpc.o ktulog.o ktshlib.o" MYLIBOBJFILES="$MYLIBOBJFILES kttimeddb.o ktdbext.o ktremotedb.o ktplugserv.o ktplugdb.o" MYSHLIBFILES="ktplugservmemc.so ktplugdbvoid.so" MYCOMMANDFILES="ktutiltest ktutilmgr ktutilserv kttimedtest kttimedmgr" MYCOMMANDFILES="$MYCOMMANDFILES ktserver ktremotetest ktremotemgr" MYMAN1FILES="ktutiltest.1 ktutilmgr.1 ktutilserv.1 kttimedtest.1 kttimedmgr.1" MYMAN1FILES="$MYMAN1FILES ktserver.1 ktremotetest.1 ktremotemgr.1" MYDOCUMENTFILES="COPYING ChangeLog doc kyototycoon.idl" MYPCFILES="kyototycoon.pc" # Building flags MYCFLAGS="-Wall -ansi -pedantic -fPIC -fsigned-char -g0 -O2" MYCXXFLAGS="-Wall -fPIC -fsigned-char -g0 -O2" MYCPPFLAGS="-I. -I\$(INCLUDEDIR) -I/usr/local/include" MYCPPFLAGS="$MYCPPFLAGS -DNDEBUG -D_GNU_SOURCE=1" MYCPPFLAGS="$MYCPPFLAGS -D_FILE_OFFSET_BITS=64 -D_REENTRANT -D__EXTENSIONS__" MYLDFLAGS="-L. -L\$(LIBDIR) -L/usr/local/lib" MYCMDLDFLAGS="" MYCMDLIBS="" MYLDLIBPATH="" MYLDLIBPATHENV="LD_LIBRARY_PATH" MYPOSTCMD="true" # Building paths PATH=".:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:$PATH" CPATH=".:/usr/local/include:$CPATH" LIBRARY_PATH=".:/usr/local/lib:$LIBRARY_PATH" LD_LIBRARY_PATH=".:/usr/local/lib:$LD_LIBRARY_PATH" PKG_CONFIG_PATH=".:/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH" export PATH CPATH LIBRARY_PATH LD_LIBRARY_PATH PKG_CONFIG_PATH #================================================================ # Options #================================================================ # Internal variables enables="" is_static="" # Debug mode # Check whether --enable-debug was given. if test "${enable_debug+set}" = set; then : enableval=$enable_debug; fi if test "$enable_debug" = "yes" then MYCFLAGS="-Wall -ansi -pedantic -fPIC -fsigned-char -g -O0" MYCXXFLAGS="-Wall -fPIC -fsigned-char -g -O0" MYCPPFLAGS="$MYCPPFLAGS -UNDEBUG -D_KCDEBUG" is_static="yes" enables="$enables (debug)" fi # Developping mode # Check whether --enable-devel was given. if test "${enable_devel+set}" = set; then : enableval=$enable_devel; fi if test "$enable_devel" = "yes" then MYCFLAGS="-Wall -Wextra -Wno-unused-parameter" MYCFLAGS="$MYCFLAGS -ansi -pedantic -fPIC -fsigned-char -O2 -fno-inline -pipe" MYCXXFLAGS="-Wall -Wextra -Wno-unused-parameter -Wnon-virtual-dtor" MYCXXFLAGS="$MYCXXFLAGS -fPIC -fsigned-char -g -O2 -fno-inline -pipe" MYCPPFLAGS="$MYCPPFLAGS -UNDEBUG -D_KCDEBUG" enables="$enables (devel)" fi # Disable optimization # Check whether --enable-opt was given. if test "${enable_opt+set}" = set; then : enableval=$enable_opt; fi if test "$enable_opt" = "no" then MYCFLAGS="$MYCFLAGS -O0" MYCXXFLAGS="$MYCXXFLAGS -O0" enables="$enables (no-opt)" fi # Profiling mode # Check whether --enable-profile was given. if test "${enable_profile+set}" = set; then : enableval=$enable_profile; fi if test "$enable_profile" = "yes" then MYCXXFLAGS="-Wall -fPIC -fsigned-char -g -pg -O2 -fno-inline -pipe" enables="$enables (profile)" fi # Micro yield mode # Check whether --enable-uyield was given. if test "${enable_uyield+set}" = set; then : enableval=$enable_uyield; fi if test "$enable_uyield" = "yes" then MYCPPFLAGS="$MYCPPFLAGS -UNDEBUG -D_KCUYIELD" enables="$enables (uyield)" fi # Static mode # Check whether --enable-static was given. if test "${enable_static+set}" = set; then : enableval=$enable_static; fi if test "$enable_static" = "yes" then is_static="yes" enables="$enables (static)" fi # Disable shared object # Check whether --enable-shared was given. if test "${enable_shared+set}" = set; then : enableval=$enable_shared; fi if test "$enable_shared" = "no" then enables="$enables (no-shared)" fi # Disable specific event notifiers # Check whether --enable-event was given. if test "${enable_event+set}" = set; then : enableval=$enable_event; fi if test "$enable_event" = "no" then MYCPPFLAGS="$MYCPPFLAGS -D_MYNOEVENT" enables="$enables (no-event)" fi # Enable Lua extension # Check whether --enable-lua was given. if test "${enable_lua+set}" = set; then : enableval=$enable_lua; fi if test "$enable_lua" = "yes" then luaver=`lua -e 'v = string.gsub(_VERSION, ".* ", ""); print(v)'` MYCPPFLAGS="$MYCPPFLAGS -D_MYLUA" MYCPPFLAGS="$MYCPPFLAGS -I/usr/include/lua$luaver -I/usr/local/include/lua$luaver" MYCPPFLAGS="$MYCPPFLAGS -I/usr/include/lua -I/usr/local/include/lua" MYLDFLAGS="$MYLDFLAGS -L/usr/lib/lua$luaver -L/usr/local/lib/lua$luaver" MYLDFLAGS="$MYLDFLAGS -L/usr/lib/lua -L/usr/local/lib/lua" LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib/lua$luaver:/usr/local/lib/lua$luaver" LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib/lua:/usr/local/lib/lua" LIBRARY_PATH="$LIBRARY_PATH:/usr/lib/lua$luaver:/usr/local/lib/lua$luaver" LIBRARY_PATH="$LIBRARY_PATH:/usr/lib/lua:/usr/local/lib/lua" CPATH="$CPATH:/usr/include/lua$luaver:/usr/local/include/lua$luaver" CPATH="$CPATH:/usr/include/lua:/usr/local/include/lua" enables="$enables (lua)" fi # Specify the installation path of Kyoto Cabinet # Check whether --with-kc was given. if test "${with_kc+set}" = set; then : withval=$with_kc; fi if test -n "$with_kc" then MYCPPFLAGS="$MYCPPFLAGS -I$with_kc/include" MYLDFLAGS="$MYLDFLAGS -L$with_kc/lib" CPATH="$CPATH:$with_kc/include" LIBRARY_PATH="$LIBRARY_PATH:$with_kc/lib" LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$with_kc/lib" PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$with_kc/lib/pkgconfig" fi # Specify the installation path of Lua # Check whether --with-lua was given. if test "${with_lua+set}" = set; then : withval=$with_lua; fi if test -n "$with_lua" then MYCPPFLAGS="$MYCPPFLAGS -I$with_lua/include" MYLDFLAGS="$MYLDFLAGS -L$with_lua/lib" CPATH="$CPATH:$with_lua/include" LIBRARY_PATH="$LIBRARY_PATH:$with_lua/lib" LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$with_lua/lib" PKG_CONFIG_PATH="$PKG_CONFIG_PATH:$with_lua/lib/pkgconfig" fi # Messages printf '#================================================================\n' printf '# Configuring Kyoto Tycoon version %s%s.\n' "$PACKAGE_VERSION" "$enables" printf '#================================================================\n' #================================================================ # Checking Commands and Libraries #================================================================ # C and C++ compilers ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. set dummy ${ac_tool_prefix}gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$ac_cv_prog_CC"; then ac_ct_CC=$CC # Extract the first word of "gcc", so it can be a program name with args. set dummy gcc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="gcc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi else CC="$ac_cv_prog_CC" fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. set dummy ${ac_tool_prefix}cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="${ac_tool_prefix}cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi fi if test -z "$CC"; then # Extract the first word of "cc", so it can be a program name with args. set dummy cc; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else ac_prog_rejected=no as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then ac_prog_rejected=yes continue fi ac_cv_prog_CC="cc" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS if test $ac_prog_rejected = yes; then # We found a bogon in the path, so make sure we never use it. set dummy $ac_cv_prog_CC shift if test $# != 0; then # We chose a different compiler from the bogus one. # However, it has the same basename, so the bogon will be chosen # first if we set CC to just the basename; use the full file name. shift ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" fi fi fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi fi if test -z "$CC"; then if test -n "$ac_tool_prefix"; then for ac_prog in cl.exe do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CC"; then ac_cv_prog_CC="$CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CC="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CC=$ac_cv_prog_CC if test -n "$CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 $as_echo "$CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CC" && break done fi if test -z "$CC"; then ac_ct_CC=$CC for ac_prog in cl.exe do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CC+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CC"; then ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CC="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CC=$ac_cv_prog_ac_ct_CC if test -n "$ac_ct_CC"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 $as_echo "$ac_ct_CC" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CC" && break done if test "x$ac_ct_CC" = x; then CC="" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CC=$ac_ct_CC fi fi fi test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "no acceptable C compiler found in \$PATH See \`config.log' for more details" "$LINENO" 5; } # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" # Try to create an executable without -o first, disregard a.out. # It will help us diagnose broken compilers, and finding out an intuition # of exeext. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 $as_echo_n "checking whether the C compiler works... " >&6; } ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` # The possible output files: ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" ac_rmfiles= for ac_file in $ac_files do case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; * ) ac_rmfiles="$ac_rmfiles $ac_file";; esac done rm -f $ac_rmfiles if { { ac_try="$ac_link_default" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link_default") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. # So ignore a value of `no', otherwise this would lead to `EXEEXT = no' # in a Makefile. We should not override ac_cv_exeext if it was cached, # so that the user can short-circuit this test for compilers unknown to # Autoconf. for ac_file in $ac_files '' do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; [ab].out ) # We found the default executable, but exeext='' is most # certainly right. break;; *.* ) if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; then :; else ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` fi # We set ac_cv_exeext here because the later test for it is not # safe: cross compilers may not add the suffix if given an `-o' # argument, so we may need to know it at that point already. # Even if this section looks crufty: it has the advantage of # actually working. break;; * ) break;; esac done test "$ac_cv_exeext" = no && ac_cv_exeext= else ac_file='' fi if test -z "$ac_file"; then : { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error 77 "C compiler cannot create executables See \`config.log' for more details" "$LINENO" 5; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 $as_echo "yes" >&6; } fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 $as_echo_n "checking for C compiler default output file name... " >&6; } { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 $as_echo "$ac_file" >&6; } ac_exeext=$ac_cv_exeext rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 $as_echo_n "checking for suffix of executables... " >&6; } if { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : # If both `conftest.exe' and `conftest' are `present' (well, observable) # catch `conftest.exe'. For instance with Cygwin, `ls conftest' will # work properly (i.e., refer to `conftest.exe'), while it won't with # `rm'. for ac_file in conftest.exe conftest conftest.*; do test -f "$ac_file" || continue case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` break;; * ) break;; esac done else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of executables: cannot compile and link See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest conftest$ac_cv_exeext { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 $as_echo "$ac_cv_exeext" >&6; } rm -f conftest.$ac_ext EXEEXT=$ac_cv_exeext ac_exeext=$EXEEXT cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdio.h> int main () { FILE *f = fopen ("conftest.out", "w"); return ferror (f) || fclose (f) != 0; ; return 0; } _ACEOF ac_clean_files="$ac_clean_files conftest.out" # Check that the compiler produces executables we can run. If not, either # the compiler is broken, or we cross compile. { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 $as_echo_n "checking whether we are cross compiling... " >&6; } if test "$cross_compiling" != yes; then { { ac_try="$ac_link" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_link") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } if { ac_try='./conftest$ac_cv_exeext' { { case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_try") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; }; then cross_compiling=no else if test "$cross_compiling" = maybe; then cross_compiling=yes else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot run C compiled programs. If you meant to cross compile, use \`--host'. See \`config.log' for more details" "$LINENO" 5; } fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 $as_echo "$cross_compiling" >&6; } rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out ac_clean_files=$ac_clean_files_save { $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 $as_echo_n "checking for suffix of object files... " >&6; } if ${ac_cv_objext+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF rm -f conftest.o conftest.obj if { { ac_try="$ac_compile" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compile") 2>&5 ac_status=$? $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; }; then : for ac_file in conftest.o conftest.obj conftest.*; do test -f "$ac_file" || continue; case $ac_file in *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` break;; esac done else $as_echo "$as_me: failed program was:" >&5 sed 's/^/| /' conftest.$ac_ext >&5 { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "cannot compute suffix of object files: cannot compile See \`config.log' for more details" "$LINENO" 5; } fi rm -f conftest.$ac_cv_objext conftest.$ac_ext fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 $as_echo "$ac_cv_objext" >&6; } OBJEXT=$ac_cv_objext ac_objext=$OBJEXT { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 $as_echo_n "checking whether we are using the GNU C compiler... " >&6; } if ${ac_cv_c_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_c_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 $as_echo "$ac_cv_c_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GCC=yes else GCC= fi ac_test_CFLAGS=${CFLAGS+set} ac_save_CFLAGS=$CFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 $as_echo_n "checking whether $CC accepts -g... " >&6; } if ${ac_cv_prog_cc_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_c_werror_flag=$ac_c_werror_flag ac_c_werror_flag=yes ac_cv_prog_cc_g=no CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes else CFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : else ac_c_werror_flag=$ac_save_c_werror_flag CFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_c_werror_flag=$ac_save_c_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 $as_echo "$ac_cv_prog_cc_g" >&6; } if test "$ac_test_CFLAGS" = set; then CFLAGS=$ac_save_CFLAGS elif test $ac_cv_prog_cc_g = yes; then if test "$GCC" = yes; then CFLAGS="-g -O2" else CFLAGS="-g" fi else if test "$GCC" = yes; then CFLAGS="-O2" else CFLAGS= fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 $as_echo_n "checking for $CC option to accept ISO C89... " >&6; } if ${ac_cv_prog_cc_c89+:} false; then : $as_echo_n "(cached) " >&6 else ac_cv_prog_cc_c89=no ac_save_CC=$CC cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdarg.h> #include <stdio.h> #include <sys/types.h> #include <sys/stat.h> /* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ struct buf { int x; }; FILE * (*rcsopen) (struct buf *, struct stat *, int); static char *e (p, i) char **p; int i; { return p[i]; } static char *f (char * (*g) (char **, int), char **p, ...) { char *s; va_list v; va_start (v,p); s = g (p, va_arg (v,int)); va_end (v); return s; } /* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has function prototypes and stuff, but not '\xHH' hex character constants. These don't provoke an error unfortunately, instead are silently treated as 'x'. The following induces an error, until -std is added to get proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an array size at least. It's necessary to write '\x00'==0 to get something that's true only with -std. */ int osf4_cc_array ['\x00' == 0 ? 1 : -1]; /* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters inside strings and character constants. */ #define FOO(x) 'x' int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; int test (int i, double x); struct s1 {int (*f) (int a);}; struct s2 {int (*f) (double a);}; int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); int argc; char **argv; int main () { return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; ; return 0; } _ACEOF for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" do CC="$ac_save_CC $ac_arg" if ac_fn_c_try_compile "$LINENO"; then : ac_cv_prog_cc_c89=$ac_arg fi rm -f core conftest.err conftest.$ac_objext test "x$ac_cv_prog_cc_c89" != "xno" && break done rm -f conftest.$ac_ext CC=$ac_save_CC fi # AC_CACHE_VAL case "x$ac_cv_prog_cc_c89" in x) { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 $as_echo "none needed" >&6; } ;; xno) { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 $as_echo "unsupported" >&6; } ;; *) CC="$CC $ac_cv_prog_cc_c89" { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 $as_echo "$ac_cv_prog_cc_c89" >&6; } ;; esac if test "x$ac_cv_prog_cc_c89" != xno; then : fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu if test -z "$CXX"; then if test -n "$CCC"; then CXX=$CCC else if test -n "$ac_tool_prefix"; then for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. set dummy $ac_tool_prefix$ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$CXX"; then ac_cv_prog_CXX="$CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi CXX=$ac_cv_prog_CXX if test -n "$CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 $as_echo "$CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$CXX" && break done fi if test -z "$CXX"; then ac_ct_CXX=$CXX for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC do # Extract the first word of "$ac_prog", so it can be a program name with args. set dummy $ac_prog; ac_word=$2 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 $as_echo_n "checking for $ac_word... " >&6; } if ${ac_cv_prog_ac_ct_CXX+:} false; then : $as_echo_n "(cached) " >&6 else if test -n "$ac_ct_CXX"; then ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. else as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_exec_ext in '' $ac_executable_extensions; do if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then ac_cv_prog_ac_ct_CXX="$ac_prog" $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 break 2 fi done done IFS=$as_save_IFS fi fi ac_ct_CXX=$ac_cv_prog_ac_ct_CXX if test -n "$ac_ct_CXX"; then { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 $as_echo "$ac_ct_CXX" >&6; } else { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 $as_echo "no" >&6; } fi test -n "$ac_ct_CXX" && break done if test "x$ac_ct_CXX" = x; then CXX="g++" else case $cross_compiling:$ac_tool_warned in yes:) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} ac_tool_warned=yes ;; esac CXX=$ac_ct_CXX fi fi fi fi # Provide some information about the compiler. $as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 set X $ac_compile ac_compiler=$2 for ac_option in --version -v -V -qversion; do { { ac_try="$ac_compiler $ac_option >&5" case "(($ac_try" in *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; *) ac_try_echo=$ac_try;; esac eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" $as_echo "$ac_try_echo"; } >&5 (eval "$ac_compiler $ac_option >&5") 2>conftest.err ac_status=$? if test -s conftest.err; then sed '10a\ ... rest of stderr output deleted ... 10q' conftest.err >conftest.er1 cat conftest.er1 >&5 fi rm -f conftest.er1 conftest.err $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 test $ac_status = 0; } done { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 $as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } if ${ac_cv_cxx_compiler_gnu+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { #ifndef __GNUC__ choke me #endif ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_compiler_gnu=yes else ac_compiler_gnu=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cv_cxx_compiler_gnu=$ac_compiler_gnu fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 $as_echo "$ac_cv_cxx_compiler_gnu" >&6; } if test $ac_compiler_gnu = yes; then GXX=yes else GXX= fi ac_test_CXXFLAGS=${CXXFLAGS+set} ac_save_CXXFLAGS=$CXXFLAGS { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 $as_echo_n "checking whether $CXX accepts -g... " >&6; } if ${ac_cv_prog_cxx_g+:} false; then : $as_echo_n "(cached) " >&6 else ac_save_cxx_werror_flag=$ac_cxx_werror_flag ac_cxx_werror_flag=yes ac_cv_prog_cxx_g=no CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes else CXXFLAGS="" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : else ac_cxx_werror_flag=$ac_save_cxx_werror_flag CXXFLAGS="-g" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_prog_cxx_g=yes fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext ac_cxx_werror_flag=$ac_save_cxx_werror_flag fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 $as_echo "$ac_cv_prog_cxx_g" >&6; } if test "$ac_test_CXXFLAGS" = set; then CXXFLAGS=$ac_save_CXXFLAGS elif test $ac_cv_prog_cxx_g = yes; then if test "$GXX" = yes; then CXXFLAGS="-g -O2" else CXXFLAGS="-g" fi else if test "$GXX" = yes; then CXXFLAGS="-O2" else CXXFLAGS= fi fi ac_ext=c ac_cpp='$CPP $CPPFLAGS' ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu # Reset variables if test "$GCC" != "yes" then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: another compiler except for GCC was detected" >&5 $as_echo "$as_me: WARNING: another compiler except for GCC was detected" >&2;} MYCFLAGS="" MYCXXFLAGS="" fi test -n "$CFLAGS" && MYCFLAGS="$CFLAGS $MYCFLAGS" test -n "$CXXFLAGS" && MYCXXFLAGS="$CXXFLAGS $MYCXXFLAGS" test -n "$CPPFLAGS" && MYCPPFLAGS="$CPPFLAGS $MYCPPFLAGS" test -n "$LDFLAGS" && MYLDFLAGS="$LDFLAGS $MYLDFLAGS" # System-depending optimization printf 'checking for 64-bit availability... ' if printf 'main() {}' | $CC -xc -m64 -o config.tmp - >config.tmp 2>&1 then MYCFLAGS="-m64 $MYCFLAGS" MYCXXFLAGS="-m64 $MYCXXFLAGS" printf 'yes\n' else printf 'no\n' fi if test "$enable_opt" != "no" then printf 'checking for CPU optimization availability... ' if printf 'main() {}' | $CC -xc -march=native -o config.tmp - >config.tmp 2>&1 then MYCFLAGS="-march=native $MYCFLAGS" MYCXXFLAGS="-march=native $MYCXXFLAGS" printf 'yes\n' else printf 'no\n' fi fi printf 'checking for useless warnings... ' if printf 'main() {}' | $CC -xc \ -Wno-unused-but-set-variable -Wno-unused-but-set-parameter -o config.tmp - >config.tmp 2>&1 then MYCFLAGS="$MYCFLAGS -Wno-unused-but-set-variable -Wno-unused-but-set-parameter" MYCXXFLAGS="$MYCXXFLAGS -Wno-unused-but-set-variable -Wno-unused-but-set-parameter" printf 'yes\n' else printf 'no\n' fi # Underlying libraries { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lc" >&5 $as_echo_n "checking for main in -lc... " >&6; } if ${ac_cv_lib_c_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lc $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_c_main=yes else ac_cv_lib_c_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_c_main" >&5 $as_echo "$ac_cv_lib_c_main" >&6; } if test "x$ac_cv_lib_c_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBC 1 _ACEOF LIBS="-lc $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lm" >&5 $as_echo_n "checking for main in -lm... " >&6; } if ${ac_cv_lib_m_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lm $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_m_main=yes else ac_cv_lib_m_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_main" >&5 $as_echo "$ac_cv_lib_m_main" >&6; } if test "x$ac_cv_lib_m_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBM 1 _ACEOF LIBS="-lm $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lpthread" >&5 $as_echo_n "checking for main in -lpthread... " >&6; } if ${ac_cv_lib_pthread_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lpthread $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_pthread_main=yes else ac_cv_lib_pthread_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_main" >&5 $as_echo "$ac_cv_lib_pthread_main" >&6; } if test "x$ac_cv_lib_pthread_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBPTHREAD 1 _ACEOF LIBS="-lpthread $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lrt" >&5 $as_echo_n "checking for main in -lrt... " >&6; } if ${ac_cv_lib_rt_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lrt $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_rt_main=yes else ac_cv_lib_rt_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_main" >&5 $as_echo "$ac_cv_lib_rt_main" >&6; } if test "x$ac_cv_lib_rt_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRT 1 _ACEOF LIBS="-lrt $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -ldl" >&5 $as_echo_n "checking for main in -ldl... " >&6; } if ${ac_cv_lib_dl_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-ldl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_dl_main=yes else ac_cv_lib_dl_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_main" >&5 $as_echo "$ac_cv_lib_dl_main" >&6; } if test "x$ac_cv_lib_dl_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBDL 1 _ACEOF LIBS="-ldl $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lnsl" >&5 $as_echo_n "checking for main in -lnsl... " >&6; } if ${ac_cv_lib_nsl_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lnsl $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_nsl_main=yes else ac_cv_lib_nsl_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_nsl_main" >&5 $as_echo "$ac_cv_lib_nsl_main" >&6; } if test "x$ac_cv_lib_nsl_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBNSL 1 _ACEOF LIBS="-lnsl $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lsocket" >&5 $as_echo_n "checking for main in -lsocket... " >&6; } if ${ac_cv_lib_socket_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lsocket $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_socket_main=yes else ac_cv_lib_socket_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_socket_main" >&5 $as_echo "$ac_cv_lib_socket_main" >&6; } if test "x$ac_cv_lib_socket_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSOCKET 1 _ACEOF LIBS="-lsocket $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lresolv" >&5 $as_echo_n "checking for main in -lresolv... " >&6; } if ${ac_cv_lib_resolv_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lresolv $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_resolv_main=yes else ac_cv_lib_resolv_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_resolv_main" >&5 $as_echo "$ac_cv_lib_resolv_main" >&6; } if test "x$ac_cv_lib_resolv_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBRESOLV 1 _ACEOF LIBS="-lresolv $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lstdc++" >&5 $as_echo_n "checking for main in -lstdc++... " >&6; } if ${ac_cv_lib_stdcpp_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lstdc++ $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_stdcpp_main=yes else ac_cv_lib_stdcpp_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_stdcpp_main" >&5 $as_echo "$ac_cv_lib_stdcpp_main" >&6; } if test "x$ac_cv_lib_stdcpp_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBSTDC__ 1 _ACEOF LIBS="-lstdc++ $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lregex" >&5 $as_echo_n "checking for main in -lregex... " >&6; } if ${ac_cv_lib_regex_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lregex $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_regex_main=yes else ac_cv_lib_regex_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_regex_main" >&5 $as_echo "$ac_cv_lib_regex_main" >&6; } if test "x$ac_cv_lib_regex_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBREGEX 1 _ACEOF LIBS="-lregex $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lz" >&5 $as_echo_n "checking for main in -lz... " >&6; } if ${ac_cv_lib_z_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lz $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_z_main=yes else ac_cv_lib_z_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_main" >&5 $as_echo "$ac_cv_lib_z_main" >&6; } if test "x$ac_cv_lib_z_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBZ 1 _ACEOF LIBS="-lz $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -llzo2" >&5 $as_echo_n "checking for main in -llzo2... " >&6; } if ${ac_cv_lib_lzo2_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-llzo2 $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_lzo2_main=yes else ac_cv_lib_lzo2_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzo2_main" >&5 $as_echo "$ac_cv_lib_lzo2_main" >&6; } if test "x$ac_cv_lib_lzo2_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBLZO2 1 _ACEOF LIBS="-llzo2 $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -llzma" >&5 $as_echo_n "checking for main in -llzma... " >&6; } if ${ac_cv_lib_lzma_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-llzma $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_lzma_main=yes else ac_cv_lib_lzma_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lzma_main" >&5 $as_echo "$ac_cv_lib_lzma_main" >&6; } if test "x$ac_cv_lib_lzma_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBLZMA 1 _ACEOF LIBS="-llzma $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkyotocabinet" >&5 $as_echo_n "checking for main in -lkyotocabinet... " >&6; } if ${ac_cv_lib_kyotocabinet_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkyotocabinet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_kyotocabinet_main=yes else ac_cv_lib_kyotocabinet_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kyotocabinet_main" >&5 $as_echo "$ac_cv_lib_kyotocabinet_main" >&6; } if test "x$ac_cv_lib_kyotocabinet_main" = xyes; then : cat >>confdefs.h <<_ACEOF #define HAVE_LIBKYOTOCABINET 1 _ACEOF LIBS="-lkyotocabinet $LIBS" fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkyotocabinet" >&5 $as_echo_n "checking for main in -lkyotocabinet... " >&6; } if ${ac_cv_lib_kyotocabinet_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkyotocabinet $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_kyotocabinet_main=yes else ac_cv_lib_kyotocabinet_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kyotocabinet_main" >&5 $as_echo "$ac_cv_lib_kyotocabinet_main" >&6; } if test "x$ac_cv_lib_kyotocabinet_main" = xyes; then : MYCMDLIBS="$MYCMDLIBS -lkyotocabinet" fi if test "$enable_lua" = "yes" then { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -llua" >&5 $as_echo_n "checking for main in -llua... " >&6; } if ${ac_cv_lib_lua_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-llua $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_lua_main=yes else ac_cv_lib_lua_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lua_main" >&5 $as_echo "$ac_cv_lib_lua_main" >&6; } if test "x$ac_cv_lib_lua_main" = xyes; then : MYCMDLIBS="$MYCMDLIBS -llua" fi as_ac_Lib=`$as_echo "ac_cv_lib_lua$luaver''_main" | $as_tr_sh` { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -llua$luaver" >&5 $as_echo_n "checking for main in -llua$luaver... " >&6; } if eval \${$as_ac_Lib+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-llua$luaver $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : eval "$as_ac_Lib=yes" else eval "$as_ac_Lib=no" fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi eval ac_res=\$$as_ac_Lib { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5 $as_echo "$ac_res" >&6; } if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then : MYCMDLIBS="$MYCMDLIBS -llua$luaver" fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lkyototycoon" >&5 $as_echo_n "checking for main in -lkyototycoon... " >&6; } if ${ac_cv_lib_kyototycoon_main+:} false; then : $as_echo_n "(cached) " >&6 else ac_check_lib_save_LIBS=$LIBS LIBS="-lkyototycoon $LIBS" cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ int main () { return main (); ; return 0; } _ACEOF if ac_fn_cxx_try_link "$LINENO"; then : ac_cv_lib_kyototycoon_main=yes else ac_cv_lib_kyototycoon_main=no fi rm -f core conftest.err conftest.$ac_objext \ conftest$ac_exeext conftest.$ac_ext LIBS=$ac_check_lib_save_LIBS fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_kyototycoon_main" >&5 $as_echo "$ac_cv_lib_kyototycoon_main" >&6; } if test "x$ac_cv_lib_kyototycoon_main" = xyes; then : { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: old version of Kyoto Tycoon was detected" >&5 $as_echo "$as_me: WARNING: old version of Kyoto Tycoon was detected" >&2;} fi MYLDLIBPATH="$LD_LIBRARY_PATH" # Necessary headers ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5 $as_echo_n "checking how to run the C++ preprocessor... " >&6; } if test -z "$CXXCPP"; then if ${ac_cv_prog_CXXCPP+:} false; then : $as_echo_n "(cached) " >&6 else # Double quotes because CXXCPP needs to be expanded for CXXCPP in "$CXX -E" "/lib/cpp" do ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since # <limits.h> exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include <limits.h> #else # include <assert.h> #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <ac_nonexistent.h> _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : break fi done ac_cv_prog_CXXCPP=$CXXCPP fi CXXCPP=$ac_cv_prog_CXXCPP else ac_cv_prog_CXXCPP=$CXXCPP fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5 $as_echo "$CXXCPP" >&6; } ac_preproc_ok=false for ac_cxx_preproc_warn_flag in '' yes do # Use a header file that comes with gcc, so configuring glibc # with a fresh cross-compiler works. # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since # <limits.h> exists even on freestanding compilers. # On the NeXT, cc -E runs the code through the compiler's parser, # not just through cpp. "Syntax error" is here to catch this case. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #ifdef __STDC__ # include <limits.h> #else # include <assert.h> #endif Syntax error _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : else # Broken: fails on valid input. continue fi rm -f conftest.err conftest.i conftest.$ac_ext # OK, works on sane cases. Now check whether nonexistent headers # can be detected and how. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <ac_nonexistent.h> _ACEOF if ac_fn_cxx_try_cpp "$LINENO"; then : # Broken: success on invalid input. continue else # Passes both tests. ac_preproc_ok=: break fi rm -f conftest.err conftest.i conftest.$ac_ext done # Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. rm -f conftest.i conftest.err conftest.$ac_ext if $ac_preproc_ok; then : else { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 $as_echo "$as_me: error: in \`$ac_pwd':" >&2;} as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check See \`config.log' for more details" "$LINENO" 5; } fi ac_ext=cpp ac_cpp='$CXXCPP $CPPFLAGS' ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_cxx_compiler_gnu { $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5 $as_echo_n "checking for grep that handles long lines and -e... " >&6; } if ${ac_cv_path_GREP+:} false; then : $as_echo_n "(cached) " >&6 else if test -z "$GREP"; then ac_path_GREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in grep ggrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue # Check for GNU ac_path_GREP and select it if it is found. # Check for GNU $ac_path_GREP case `"$ac_path_GREP" --version 2>&1` in *GNU*) ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'GREP' >> "conftest.nl" "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_GREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_GREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_GREP"; then as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_GREP=$GREP fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5 $as_echo "$ac_cv_path_GREP" >&6; } GREP="$ac_cv_path_GREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5 $as_echo_n "checking for egrep... " >&6; } if ${ac_cv_path_EGREP+:} false; then : $as_echo_n "(cached) " >&6 else if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 then ac_cv_path_EGREP="$GREP -E" else if test -z "$EGREP"; then ac_path_EGREP_found=false # Loop through the user's path and test for each of PROGNAME-LIST as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. for ac_prog in egrep; do for ac_exec_ext in '' $ac_executable_extensions; do ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue # Check for GNU ac_path_EGREP and select it if it is found. # Check for GNU $ac_path_EGREP case `"$ac_path_EGREP" --version 2>&1` in *GNU*) ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; *) ac_count=0 $as_echo_n 0123456789 >"conftest.in" while : do cat "conftest.in" "conftest.in" >"conftest.tmp" mv "conftest.tmp" "conftest.in" cp "conftest.in" "conftest.nl" $as_echo 'EGREP' >> "conftest.nl" "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break as_fn_arith $ac_count + 1 && ac_count=$as_val if test $ac_count -gt ${ac_path_EGREP_max-0}; then # Best one so far, save it but keep looking for a better one ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_max=$ac_count fi # 10*(2^10) chars as input seems more than enough test $ac_count -gt 10 && break done rm -f conftest.in conftest.tmp conftest.nl conftest.out;; esac $ac_path_EGREP_found && break 3 done done done IFS=$as_save_IFS if test -z "$ac_cv_path_EGREP"; then as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5 fi else ac_cv_path_EGREP=$EGREP fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5 $as_echo "$ac_cv_path_EGREP" >&6; } EGREP="$ac_cv_path_EGREP" { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5 $as_echo_n "checking for ANSI C header files... " >&6; } if ${ac_cv_header_stdc+:} false; then : $as_echo_n "(cached) " >&6 else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdlib.h> #include <stdarg.h> #include <string.h> #include <float.h> int main () { ; return 0; } _ACEOF if ac_fn_cxx_try_compile "$LINENO"; then : ac_cv_header_stdc=yes else ac_cv_header_stdc=no fi rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext if test $ac_cv_header_stdc = yes; then # SunOS 4.x string.h does not declare mem*, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <string.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "memchr" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <stdlib.h> _ACEOF if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | $EGREP "free" >/dev/null 2>&1; then : else ac_cv_header_stdc=no fi rm -f conftest* fi if test $ac_cv_header_stdc = yes; then # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. if test "$cross_compiling" = yes; then : : else cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ #include <ctype.h> #include <stdlib.h> #if ((' ' & 0x0FF) == 0x020) # define ISLOWER(c) ('a' <= (c) && (c) <= 'z') # define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) #else # define ISLOWER(c) \ (('a' <= (c) && (c) <= 'i') \ || ('j' <= (c) && (c) <= 'r') \ || ('s' <= (c) && (c) <= 'z')) # define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) #endif #define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) int main () { int i; for (i = 0; i < 256; i++) if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) return 2; return 0; } _ACEOF if ac_fn_cxx_try_run "$LINENO"; then : else ac_cv_header_stdc=no fi rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ conftest.$ac_objext conftest.beam conftest.$ac_ext fi fi fi { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5 $as_echo "$ac_cv_header_stdc" >&6; } if test $ac_cv_header_stdc = yes; then $as_echo "#define STDC_HEADERS 1" >>confdefs.h fi # On IRIX 5.3, sys/types and inttypes.h are conflicting. for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ inttypes.h stdint.h unistd.h do : as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh` ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default " if eval test \"x\$"$as_ac_Header"\" = x"yes"; then : cat >>confdefs.h <<_ACEOF #define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1 _ACEOF fi done ac_fn_cxx_check_header_mongrel "$LINENO" "stdlib.h" "ac_cv_header_stdlib_h" "$ac_includes_default" if test "x$ac_cv_header_stdlib_h" = xyes; then : true else as_fn_error $? "stdlib.h is required" "$LINENO" 5 fi ac_fn_cxx_check_header_mongrel "$LINENO" "stdint.h" "ac_cv_header_stdint_h" "$ac_includes_default" if test "x$ac_cv_header_stdint_h" = xyes; then : true else as_fn_error $? "stdint.h is required" "$LINENO" 5 fi ac_fn_cxx_check_header_mongrel "$LINENO" "unistd.h" "ac_cv_header_unistd_h" "$ac_includes_default" if test "x$ac_cv_header_unistd_h" = xyes; then : true else as_fn_error $? "unistd.h is required" "$LINENO" 5 fi ac_fn_cxx_check_header_mongrel "$LINENO" "sys/socket.h" "ac_cv_header_sys_socket_h" "$ac_includes_default" if test "x$ac_cv_header_sys_socket_h" = xyes; then : true else as_fn_error $? "sys/socket.h is required" "$LINENO" 5 fi ac_fn_cxx_check_header_mongrel "$LINENO" "kccommon.h" "ac_cv_header_kccommon_h" "$ac_includes_default" if test "x$ac_cv_header_kccommon_h" = xyes; then : true else as_fn_error $? "kccommon.h is required" "$LINENO" 5 fi if test "$enable_lua" = "yes" then ac_fn_cxx_check_header_mongrel "$LINENO" "lua.h" "ac_cv_header_lua_h" "$ac_includes_default" if test "x$ac_cv_header_lua_h" = xyes; then : true else as_fn_error $? "lua.h is required" "$LINENO" 5 fi fi # Static linking if test "$is_static" = "yes" then MYCMDLDFLAGS="$MYCMDLDFLAGS -static" MYCMDLIBS="$MYCMDLIBS $LIBS" fi # As-needed linking if uname | grep Linux >config.tmp then MYLDFLAGS="$MYLDFLAGS -Wl,-rpath-link,.:/usr/local/lib:$MYLDLIBPATH" MYLDFLAGS="$MYLDFLAGS -Wl,--as-needed" else MYCMDLIBS="$MYCMDLIBS $LIBS" fi # Checking the version of Kyoto Cabinet with pkg-config if type pkg-config >config.tmp 2>&1 then printf 'checking Kyoto Cabinet by pkg-config... ' if pkg-config --atleast-version=1.2.65 kyotocabinet then printf 'yes\n' else printf 'no\n' as_fn_error $? "required version of Kyoto Cabinet was not detected" "$LINENO" 5 fi fi # Shared libraries if test "$enable_shared" != "no" && test "$enable_profile" != "yes" then if uname | grep Darwin >config.tmp then MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.$MYLIBVER.$MYLIBREV.0.dylib" MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.$MYLIBVER.dylib" MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.dylib" MYLDLIBPATHENV="DYLD_LIBRARY_PATH" else MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.so.$MYLIBVER.$MYLIBREV.0" MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.so.$MYLIBVER" MYLIBRARYFILES="$MYLIBRARYFILES libkyototycoon.so" fi fi if uname | grep Darwin >config.tmp then MYSHLIBFILES="ktplugservmemc.dylib" fi # Work around of bugs of some environments if uname | grep Darwin >config.tmp then MYCFLAGS="$MYCFLAGS -Os" MYCXXFLAGS="$MYCXXFLAGS -Os" fi #================================================================ # Generic Settings #================================================================ # Export variables # Targets ac_config_files="$ac_config_files Makefile kyototycoon.pc" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure # tests run on this system so they can be shared between configure # scripts and configure runs, see configure's option --config-cache. # It is not useful on other systems. If it contains results you don't # want to keep, you may remove or edit it. # # config.status only pays attention to the cache file if you give it # the --recheck option to rerun configure. # # `ac_cv_env_foo' variables (set or unset) will be overridden when # loading this file, other *unset* `ac_cv_foo' will be assigned the # following values. _ACEOF # The following way of writing the cache mishandles newlines in values, # but we know of no workaround that is simple, portable, and efficient. # So, we kill variables containing newlines. # Ultrix sh set writes to stderr and can't be redirected directly, # and sets the high bit in the cache file unless we assign to the vars. ( for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do eval ac_val=\$$ac_var case $ac_val in #( *${as_nl}*) case $ac_var in #( *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 $as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; esac case $ac_var in #( _ | IFS | as_nl) ;; #( BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( *) { eval $ac_var=; unset $ac_var;} ;; esac ;; esac done (set) 2>&1 | case $as_nl`(ac_space=' '; set) 2>&1` in #( *${as_nl}ac_space=\ *) # `set' does not quote correctly, so add quotes: double-quote # substitution turns \\\\ into \\, and sed turns \\ into \. sed -n \ "s/'/'\\\\''/g; s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" ;; #( *) # `set' quotes correctly as required by POSIX, so do not add quotes. sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" ;; esac | sort ) | sed ' /^ac_cv_env_/b end t clear :clear s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ t end s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ :end' >>confcache if diff "$cache_file" confcache >/dev/null 2>&1; then :; else if test -w "$cache_file"; then if test "x$cache_file" != "x/dev/null"; then { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 $as_echo "$as_me: updating cache $cache_file" >&6;} if test ! -f "$cache_file" || test -h "$cache_file"; then cat confcache >"$cache_file" else case $cache_file in #( */* | ?:*) mv -f confcache "$cache_file"$$ && mv -f "$cache_file"$$ "$cache_file" ;; #( *) mv -f confcache "$cache_file" ;; esac fi fi else { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 $as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} fi fi rm -f confcache test "x$prefix" = xNONE && prefix=$ac_default_prefix # Let make expand exec_prefix. test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' # Transform confdefs.h into DEFS. # Protect against shell expansion while executing Makefile rules. # Protect against Makefile macro expansion. # # If the first sed substitution is executed (which looks for macros that # take arguments), then branch to the quote section. Otherwise, # look for a macro that doesn't take arguments. ac_script=' :mline /\\$/{ N s,\\\n,, b mline } t clear :clear s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g t quote s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g t quote b any :quote s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g s/\[/\\&/g s/\]/\\&/g s/\$/$$/g H :any ${ g s/^\n// s/\n/ /g p } ' DEFS=`sed -n "$ac_script" confdefs.h` ac_libobjs= ac_ltlibobjs= U= for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue # 1. Remove the extension, and $U if already installed. ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' ac_i=`$as_echo "$ac_i" | sed "$ac_script"` # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR # will be set to the directory where LIBOBJS objects are built. as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' done LIBOBJS=$ac_libobjs LTLIBOBJS=$ac_ltlibobjs : "${CONFIG_STATUS=./config.status}" ac_write_fail=0 ac_clean_files_save=$ac_clean_files ac_clean_files="$ac_clean_files $CONFIG_STATUS" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 $as_echo "$as_me: creating $CONFIG_STATUS" >&6;} as_write_fail=0 cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 #! $SHELL # Generated by $as_me. # Run this file to recreate the current configuration. # Compiler output produced by configure, useful for debugging # configure, is in config.log if it exists. debug=false ac_cs_recheck=false ac_cs_silent=false SHELL=\${CONFIG_SHELL-$SHELL} export SHELL _ASEOF cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 ## -------------------- ## ## M4sh Initialization. ## ## -------------------- ## # Be more Bourne compatible DUALCASE=1; export DUALCASE # for MKS sh if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : emulate sh NULLCMD=: # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which # is contrary to our usage. Disable this feature. alias -g '${1+"$@"}'='"$@"' setopt NO_GLOB_SUBST else case `(set -o) 2>/dev/null` in #( *posix*) : set -o posix ;; #( *) : ;; esac fi as_nl=' ' export as_nl # Printing a long string crashes Solaris 7 /usr/bin/printf. as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo # Prefer a ksh shell builtin over an external printf program on Solaris, # but without wasting forks for bash or zsh. if test -z "$BASH_VERSION$ZSH_VERSION" \ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='print -r --' as_echo_n='print -rn --' elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then as_echo='printf %s\n' as_echo_n='printf %s' else if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' as_echo_n='/usr/ucb/echo -n' else as_echo_body='eval expr "X$1" : "X\\(.*\\)"' as_echo_n_body='eval arg=$1; case $arg in #( *"$as_nl"*) expr "X$arg" : "X\\(.*\\)$as_nl"; arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; esac; expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" ' export as_echo_n_body as_echo_n='sh -c $as_echo_n_body as_echo' fi export as_echo_body as_echo='sh -c $as_echo_body as_echo' fi # The user is always right. if test "${PATH_SEPARATOR+set}" != set; then PATH_SEPARATOR=: (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || PATH_SEPARATOR=';' } fi # IFS # We need space, tab and new line, in precisely that order. Quoting is # there to prevent editors from complaining about space-tab. # (If _AS_PATH_WALK were called with IFS unset, it would disable word # splitting by setting IFS to empty value.) IFS=" "" $as_nl" # Find who we are. Look in the path if we contain no directory separator. as_myself= case $0 in #(( *[\\/]* ) as_myself=$0 ;; *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR for as_dir in $PATH do IFS=$as_save_IFS test -z "$as_dir" && as_dir=. test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break done IFS=$as_save_IFS ;; esac # We did not find ourselves, most probably we were run as `sh COMMAND' # in which case we are not to be found in the path. if test "x$as_myself" = x; then as_myself=$0 fi if test ! -f "$as_myself"; then $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 exit 1 fi # Unset variables that we do not need and which cause bugs (e.g. in # pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" # suppresses any "Segmentation fault" message there. '((' could # trigger a bug in pdksh 5.2.14. for as_var in BASH_ENV ENV MAIL MAILPATH do eval test x\${$as_var+set} = xset \ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : done PS1='$ ' PS2='> ' PS4='+ ' # NLS nuisances. LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE # CDPATH. (unset CDPATH) >/dev/null 2>&1 && unset CDPATH # as_fn_error STATUS ERROR [LINENO LOG_FD] # ---------------------------------------- # Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are # provided, also output the error to LOG_FD, referencing LINENO. Then exit the # script with STATUS, using 1 if that was 0. as_fn_error () { as_status=$1; test $as_status -eq 0 && as_status=1 if test "$4"; then as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4 fi $as_echo "$as_me: error: $2" >&2 as_fn_exit $as_status } # as_fn_error # as_fn_set_status STATUS # ----------------------- # Set $? to STATUS, without forking. as_fn_set_status () { return $1 } # as_fn_set_status # as_fn_exit STATUS # ----------------- # Exit the shell with STATUS, even in a "trap 0" or "set -e" context. as_fn_exit () { set +e as_fn_set_status $1 exit $1 } # as_fn_exit # as_fn_unset VAR # --------------- # Portably unset VAR. as_fn_unset () { { eval $1=; unset $1;} } as_unset=as_fn_unset # as_fn_append VAR VALUE # ---------------------- # Append the text in VALUE to the end of the definition contained in VAR. Take # advantage of any shell optimizations that allow amortized linear growth over # repeated appends, instead of the typical quadratic growth present in naive # implementations. if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : eval 'as_fn_append () { eval $1+=\$2 }' else as_fn_append () { eval $1=\$$1\$2 } fi # as_fn_append # as_fn_arith ARG... # ------------------ # Perform arithmetic evaluation on the ARGs, and store the result in the # global $as_val. Take advantage of shells that can avoid forks. The arguments # must be portable across $(()) and expr. if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : eval 'as_fn_arith () { as_val=$(( $* )) }' else as_fn_arith () { as_val=`expr "$@" || test $? -eq 1` } fi # as_fn_arith if expr a : '\(a\)' >/dev/null 2>&1 && test "X`expr 00001 : '.*\(...\)'`" = X001; then as_expr=expr else as_expr=false fi if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then as_basename=basename else as_basename=false fi if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then as_dirname=dirname else as_dirname=false fi as_me=`$as_basename -- "$0" || $as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ X"$0" : 'X\(//\)$' \| \ X"$0" : 'X\(/\)' \| . 2>/dev/null || $as_echo X/"$0" | sed '/^.*\/\([^/][^/]*\)\/*$/{ s//\1/ q } /^X\/\(\/\/\)$/{ s//\1/ q } /^X\/\(\/\).*/{ s//\1/ q } s/.*/./; q'` # Avoid depending upon Character Ranges. as_cr_letters='abcdefghijklmnopqrstuvwxyz' as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' as_cr_Letters=$as_cr_letters$as_cr_LETTERS as_cr_digits='0123456789' as_cr_alnum=$as_cr_Letters$as_cr_digits ECHO_C= ECHO_N= ECHO_T= case `echo -n x` in #((((( -n*) case `echo 'xy\c'` in *c*) ECHO_T=' ';; # ECHO_T is single tab character. xy) ECHO_C='\c';; *) echo `echo ksh88 bug on AIX 6.1` > /dev/null ECHO_T=' ';; esac;; *) ECHO_N='-n';; esac rm -f conf$$ conf$$.exe conf$$.file if test -d conf$$.dir; then rm -f conf$$.dir/conf$$.file else rm -f conf$$.dir mkdir conf$$.dir 2>/dev/null fi if (echo >conf$$.file) 2>/dev/null; then if ln -s conf$$.file conf$$ 2>/dev/null; then as_ln_s='ln -s' # ... but there are two gotchas: # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. # In both cases, we have to default to `cp -p'. ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || as_ln_s='cp -p' elif ln conf$$.file conf$$ 2>/dev/null; then as_ln_s=ln else as_ln_s='cp -p' fi else as_ln_s='cp -p' fi rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file rmdir conf$$.dir 2>/dev/null # as_fn_mkdir_p # ------------- # Create "$as_dir" as a directory, including parents if necessary. as_fn_mkdir_p () { case $as_dir in #( -*) as_dir=./$as_dir;; esac test -d "$as_dir" || eval $as_mkdir_p || { as_dirs= while :; do case $as_dir in #( *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( *) as_qdir=$as_dir;; esac as_dirs="'$as_qdir' $as_dirs" as_dir=`$as_dirname -- "$as_dir" || $as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$as_dir" : 'X\(//\)[^/]' \| \ X"$as_dir" : 'X\(//\)$' \| \ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$as_dir" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` test -d "$as_dir" && break done test -z "$as_dirs" || eval "mkdir $as_dirs" } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir" } # as_fn_mkdir_p if mkdir -p . 2>/dev/null; then as_mkdir_p='mkdir -p "$as_dir"' else test -d ./-p && rmdir ./-p as_mkdir_p=false fi if test -x / >/dev/null 2>&1; then as_test_x='test -x' else if ls -dL / >/dev/null 2>&1; then as_ls_L_option=L else as_ls_L_option= fi as_test_x=' eval sh -c '\'' if test -d "$1"; then test -d "$1/."; else case $1 in #( -*)set "./$1";; esac; case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( ???[sx]*):;;*)false;;esac;fi '\'' sh ' fi as_executable_p=$as_test_x # Sed expression to map a string onto a valid CPP name. as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" # Sed expression to map a string onto a valid variable name. as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" exec 6>&1 ## ----------------------------------- ## ## Main body of $CONFIG_STATUS script. ## ## ----------------------------------- ## _ASEOF test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Save the log message, to keep $0 and so on meaningful, and to # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" This file was extended by kyototycoon $as_me 0.9.56, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES CONFIG_HEADERS = $CONFIG_HEADERS CONFIG_LINKS = $CONFIG_LINKS CONFIG_COMMANDS = $CONFIG_COMMANDS $ $0 $@ on `(hostname || uname -n) 2>/dev/null | sed 1q` " _ACEOF case $ac_config_files in *" "*) set x $ac_config_files; shift; ac_config_files=$*;; esac cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 # Files that config.status was made for. config_files="$ac_config_files" _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 ac_cs_usage="\ \`$as_me' instantiates files and other configuration actions from templates according to the current configuration. Unless the files and actions are specified as TAGs, all are instantiated by default. Usage: $0 [OPTION]... [TAG]... -h, --help print this help, then exit -V, --version print version number and configuration settings, then exit --config print configuration, then exit -q, --quiet, --silent do not print progress messages -d, --debug don't remove temporary files --recheck update $as_me by reconfiguring in the same conditions --file=FILE[:TEMPLATE] instantiate the configuration file FILE Configuration files: $config_files Report bugs to the package provider." _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ kyototycoon config.status 0.9.56 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" Copyright (C) 2010 Free Software Foundation, Inc. This config.status script is free software; the Free Software Foundation gives unlimited permission to copy, distribute and modify it." ac_pwd='$ac_pwd' srcdir='$srcdir' test -n "\$AWK" || AWK=awk _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # The default lists apply if the user does not specify any file. ac_need_defaults=: while test $# != 0 do case $1 in --*=?*) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` ac_shift=: ;; --*=) ac_option=`expr "X$1" : 'X\([^=]*\)='` ac_optarg= ac_shift=: ;; *) ac_option=$1 ac_optarg=$2 ac_shift=shift ;; esac case $ac_option in # Handling of the options. -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) ac_cs_recheck=: ;; --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) $as_echo "$ac_cs_version"; exit ;; --config | --confi | --conf | --con | --co | --c ) $as_echo "$ac_cs_config"; exit ;; --debug | --debu | --deb | --de | --d | -d ) debug=: ;; --file | --fil | --fi | --f ) $ac_shift case $ac_optarg in *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; '') as_fn_error $? "missing file argument" ;; esac as_fn_append CONFIG_FILES " '$ac_optarg'" ac_need_defaults=false;; --he | --h | --help | --hel | -h ) $as_echo "$ac_cs_usage"; exit ;; -q | -quiet | --quiet | --quie | --qui | --qu | --q \ | -silent | --silent | --silen | --sile | --sil | --si | --s) ac_cs_silent=: ;; # This is an error. -*) as_fn_error $? "unrecognized option: \`$1' Try \`$0 --help' for more information." ;; *) as_fn_append ac_config_targets " $1" ac_need_defaults=false ;; esac shift done ac_configure_extra_args= if $ac_cs_silent; then exec 6>/dev/null ac_configure_extra_args="$ac_configure_extra_args --silent" fi _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 if \$ac_cs_recheck; then set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion shift \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 CONFIG_SHELL='$SHELL' export CONFIG_SHELL exec "\$@" fi _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 exec 5>>config.log { echo sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX ## Running $as_me. ## _ASBOX $as_echo "$ac_log" } >&5 _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # Handling of arguments. for ac_config_target in $ac_config_targets do case $ac_config_target in "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; "kyototycoon.pc") CONFIG_FILES="$CONFIG_FILES kyototycoon.pc" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; esac done # If the user did not use the arguments to specify the items to instantiate, # then the envvar interface is used. Set only those that are not. # We use the long form for the default assignment because of an extremely # bizarre bug on SunOS 4.1.3. if $ac_need_defaults; then test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files fi # Have a temporary directory for convenience. Make it in the build tree # simply because there is no reason against having it here, and in addition, # creating and moving files from /tmp can sometimes cause problems. # Hook for its removal unless debugging. # Note that there is a small window in which the directory will not be cleaned: # after its creation but before its name has been assigned to `$tmp'. $debug || { tmp= ac_tmp= trap 'exit_status=$? : "${ac_tmp:=$tmp}" { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status ' 0 trap 'as_fn_exit 1' 1 2 13 15 } # Create a (secure) tmp directory for tmp files. { tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && test -d "$tmp" } || { tmp=./conf$$-$RANDOM (umask 077 && mkdir "$tmp") } || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5 ac_tmp=$tmp # Set up the scripts for CONFIG_FILES section. # No need to generate them if there are no CONFIG_FILES. # This happens for instance with `./config.status config.h'. if test -n "$CONFIG_FILES"; then ac_cr=`echo X | tr X '\015'` # On cygwin, bash can eat \r inside `` if the user requested igncr. # But we know of no other shell where ac_cr would be empty at this # point, so we can use a bashism as a fallback. if test "x$ac_cr" = x; then eval ac_cr=\$\'\\r\' fi ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null` if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then ac_cs_awk_cr='\\r' else ac_cs_awk_cr=$ac_cr fi echo 'BEGIN {' >"$ac_tmp/subs1.awk" && _ACEOF { echo "cat >conf$$subs.awk <<_ACEOF" && echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && echo "_ACEOF" } >conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'` ac_delim='%!_!# ' for ac_last_try in false false false false false :; do . ./conf$$subs.sh || as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` if test $ac_delim_n = $ac_delim_num; then break elif $ac_last_try; then as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5 else ac_delim="$ac_delim!$ac_delim _$ac_delim!! " fi done rm -f conf$$subs.sh cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK && _ACEOF sed -n ' h s/^/S["/; s/!.*/"]=/ p g s/^[^!]*!// :repl t repl s/'"$ac_delim"'$// t delim :nl h s/\(.\{148\}\)..*/\1/ t more1 s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ p n b repl :more1 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t nl :delim h s/\(.\{148\}\)..*/\1/ t more2 s/["\\]/\\&/g; s/^/"/; s/$/"/ p b :more2 s/["\\]/\\&/g; s/^/"/; s/$/"\\/ p g s/.\{148\}// t delim ' <conf$$subs.awk | sed ' /^[^""]/{ N s/\n// } ' >>$CONFIG_STATUS || ac_write_fail=1 rm -f conf$$subs.awk cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 _ACAWK cat >>"\$ac_tmp/subs1.awk" <<_ACAWK && for (key in S) S_is_set[key] = 1 FS = "" } { line = $ 0 nfields = split(line, field, "@") substed = 0 len = length(field[1]) for (i = 2; i < nfields; i++) { key = field[i] keylen = length(key) if (S_is_set[key]) { value = S[key] line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) len += length(value) + length(field[++i]) substed = 1 } else len += 1 + keylen } print line } _ACAWK _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" else cat fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5 _ACEOF # VPATH may cause trouble with some makes, so we remove sole $(srcdir), # ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and # trailing colons and then remove the whole line if VPATH becomes empty # (actually we leave an empty line to preserve line numbers). if test "x$srcdir" = x.; then ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{ h s/// s/^/:/ s/[ ]*$/:/ s/:\$(srcdir):/:/g s/:\${srcdir}:/:/g s/:@srcdir@:/:/g s/^:*// s/:*$// x s/\(=[ ]*\).*/\1/ G s/\n// s/^[^=]*=[ ]*$// }' fi cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 fi # test -n "$CONFIG_FILES" eval set X " :F $CONFIG_FILES " shift for ac_tag do case $ac_tag in :[FHLC]) ac_mode=$ac_tag; continue;; esac case $ac_mode$ac_tag in :[FHL]*:*);; :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;; :[FH]-) ac_tag=-:-;; :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; esac ac_save_IFS=$IFS IFS=: set x $ac_tag IFS=$ac_save_IFS shift ac_file=$1 shift case $ac_mode in :L) ac_source=$1;; :[FH]) ac_file_inputs= for ac_f do case $ac_f in -) ac_f="$ac_tmp/stdin";; *) # Look for the file first in the build tree, then in the source tree # (if the path is not absolute). The absolute path cannot be DOS-style, # because $ac_f cannot contain `:'. test -f "$ac_f" || case $ac_f in [\\/$]*) false;; *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; esac || as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;; esac case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac as_fn_append ac_file_inputs " '$ac_f'" done # Let's still pretend it is `configure' which instantiates (i.e., don't # use $as_me), people would be surprised to read: # /* config.h. Generated by config.status. */ configure_input='Generated from '` $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' `' by configure.' if test x"$ac_file" != x-; then configure_input="$ac_file. $configure_input" { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 $as_echo "$as_me: creating $ac_file" >&6;} fi # Neutralize special characters interpreted by sed in replacement strings. case $configure_input in #( *\&* | *\|* | *\\* ) ac_sed_conf_input=`$as_echo "$configure_input" | sed 's/[\\\\&|]/\\\\&/g'`;; #( *) ac_sed_conf_input=$configure_input;; esac case $ac_tag in *:-:* | *:-) cat >"$ac_tmp/stdin" \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac ;; esac ac_dir=`$as_dirname -- "$ac_file" || $as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ X"$ac_file" : 'X\(//\)[^/]' \| \ X"$ac_file" : 'X\(//\)$' \| \ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || $as_echo X"$ac_file" | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ s//\1/ q } /^X\(\/\/\)[^/].*/{ s//\1/ q } /^X\(\/\/\)$/{ s//\1/ q } /^X\(\/\).*/{ s//\1/ q } s/.*/./; q'` as_dir="$ac_dir"; as_fn_mkdir_p ac_builddir=. case "$ac_dir" in .) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` # A ".." for each directory in $ac_dir_suffix. ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` case $ac_top_builddir_sub in "") ac_top_builddir_sub=. ac_top_build_prefix= ;; *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; esac ;; esac ac_abs_top_builddir=$ac_pwd ac_abs_builddir=$ac_pwd$ac_dir_suffix # for backward compatibility: ac_top_builddir=$ac_top_build_prefix case $srcdir in .) # We are building in place. ac_srcdir=. ac_top_srcdir=$ac_top_builddir_sub ac_abs_top_srcdir=$ac_pwd ;; [\\/]* | ?:[\\/]* ) # Absolute name. ac_srcdir=$srcdir$ac_dir_suffix; ac_top_srcdir=$srcdir ac_abs_top_srcdir=$srcdir ;; *) # Relative name. ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix ac_top_srcdir=$ac_top_build_prefix$srcdir ac_abs_top_srcdir=$ac_pwd/$srcdir ;; esac ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix case $ac_mode in :F) # # CONFIG_FILE # _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # If the template does not know about datarootdir, expand it. # FIXME: This hack should be removed a few years after 2.60. ac_datarootdir_hack=; ac_datarootdir_seen= ac_sed_dataroot=' /datarootdir/ { p q } /@datadir@/p /@docdir@/p /@infodir@/p /@localedir@/p /@mandir@/p' case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in *datarootdir*) ac_datarootdir_seen=yes;; *@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 $as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_datarootdir_hack=' s&@datadir@&$datadir&g s&@docdir@&$docdir&g s&@infodir@&$infodir&g s&@localedir@&$localedir&g s&@mandir@&$mandir&g s&\\\${datarootdir}&$datarootdir&g' ;; esac _ACEOF # Neutralize VPATH when `$srcdir' = `.'. # Shell code in configure.ac might set extrasub. # FIXME: do we really want to maintain this feature? cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_sed_extra="$ac_vpsub $extrasub _ACEOF cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 :t /@[a-zA-Z_][a-zA-Z_0-9]*@/!b s|@configure_input@|$ac_sed_conf_input|;t t s&@top_builddir@&$ac_top_builddir_sub&;t t s&@top_build_prefix@&$ac_top_build_prefix&;t t s&@srcdir@&$ac_srcdir&;t t s&@abs_srcdir@&$ac_abs_srcdir&;t t s&@top_srcdir@&$ac_top_srcdir&;t t s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t s&@builddir@&$ac_builddir&;t t s&@abs_builddir@&$ac_abs_builddir&;t t s&@abs_top_builddir@&$ac_abs_top_builddir&;t t $ac_datarootdir_hack " eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5 test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } && { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \ "$ac_tmp/out"`; test -z "$ac_out"; } && { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&5 $as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' which seems to be undefined. Please make sure it is defined" >&2;} rm -f "$ac_tmp/stdin" case $ac_file in -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";; *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";; esac \ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;; esac done # for ac_tag as_fn_exit 0 _ACEOF ac_clean_files=$ac_clean_files_save test $ac_write_fail = 0 || as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5 # configure is writing to config.log, and then calls config.status. # config.status does its own redirection, appending to config.log. # Unfortunately, on DOS this fails, as config.log is still kept open # by configure, so config.status won't be able to write to it; its # output is simply discarded. So we exec the FD to /dev/null, # effectively closing config.log, so it can be properly (re)opened and # appended to by config.status. When coming back to configure, we # need to make the FD available again. if test "$no_create" != yes; then ac_cs_success=: ac_config_status_args= test "$silent" = yes && ac_config_status_args="$ac_config_status_args --quiet" exec 5>/dev/null $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false exec 5>>config.log # Use ||, not &&, to avoid exiting from the if with $? = 1, which # would make configure fail if this is the last instruction. $ac_cs_success || as_fn_exit 1 fi if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} fi # Messages printf '#================================================================\n' printf '# Ready to make.\n' printf '#================================================================\n' # END OF FILE ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktplugdb.cc����������������������������������������������������������������������0000644�0001750�0001750�00000002303�11757471602�015351� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * Interface of pluggable database abstraction * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include "ktplugdb.h" #include "myconf.h" namespace kyototycoon { // common namespace // There is no implementation now. } // common namespace // END OF FILE �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktremotedb.h���������������������������������������������������������������������0000644�0001750�0001750�00000253665�11757471602�015562� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * Remote database * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #ifndef _KTREMOTEDB_H // duplication check #define _KTREMOTEDB_H #include <ktcommon.h> #include <ktutil.h> #include <ktsocket.h> #include <ktthserv.h> #include <kthttp.h> #include <ktrpc.h> #include <ktulog.h> #include <ktshlib.h> #include <kttimeddb.h> #include <ktdbext.h> namespace kyototycoon { // common namespace /** * Remote database. * @note This class is a concrete class to access remote database servers. This class can be * inherited but overwriting methods is forbidden. Before every database operation, it is * necessary to call the RemoteDB::open method in order to connect to a database server. To * avoid resource starvation it is important to close every database file by the RemoteDB::close * method when the connection is no longer in use. Although all methods of this class are * thread-safe, its instance does not have mutual exclusion mechanism. So, multiple threads * must not share the same instance and they must use their own respective instances. */ class RemoteDB { public: class Cursor; class Error; struct BulkRecord; /** The maximum size of each record data. */ static const size_t DATAMAXSIZ = 1ULL << 28; private: struct OrderedKey; /** An alias of list of cursors. */ typedef std::list<Cursor*> CursorList; /** The size for a record buffer. */ static const int32_t RECBUFSIZ = 2048; public: /** * Cursor to indicate a record. */ class Cursor { friend class RemoteDB; public: /** * Constructor. * @param db the container database object. */ explicit Cursor(RemoteDB* db) : db_(db), id_(0) { _assert_(db); uint64_t uid = (((uint64_t)(intptr_t)db_ >> 8) << 16) ^ ((uint64_t)(intptr_t)this >> 8); uid ^= ((uint64_t)(kc::time() * 65536)) << 24; id_ = ((uid << 16) & (kc::INT64MAX >> 4)) + (++db->curcnt_); db_->curs_.push_back(this); } /** * Destructor. */ virtual ~Cursor() { _assert_(true); if (!db_) return; std::map<std::string, std::string> inmap; set_cur_param(inmap); std::map<std::string, std::string> outmap; db_->rpc_.call("cur_delete", &inmap, &outmap); db_->curs_.remove(this); } /** * Jump the cursor to the first record for forward scan. * @return true on success, or false on failure. */ bool jump() { _assert_(true); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_jump", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } return true; } /** * Jump the cursor to a record for forward scan. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @return true on success, or false on failure. */ bool jump(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); inmap["key"] = std::string(kbuf, ksiz); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_jump", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } return true; } /** * Jump the cursor to a record for forward scan. * @note Equal to the original Cursor::jump method except that the parameter is std::string. */ bool jump(const std::string& key) { _assert_(true); return jump(key.c_str(), key.size()); } /** * Jump the cursor to the last record for backward scan. * @return true on success, or false on failure. * @note This method is dedicated to tree databases. Some database types, especially hash * databases, may provide a dummy implementation. */ bool jump_back() { _assert_(true); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_jump_back", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } return true; } /** * Jump the cursor to a record for backward scan. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @return true on success, or false on failure. * @note This method is dedicated to tree databases. Some database types, especially hash * databases, will provide a dummy implementation. */ bool jump_back(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); inmap["key"] = std::string(kbuf, ksiz); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_jump_back", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } return true; } /** * Jump the cursor to a record for backward scan. * @note Equal to the original Cursor::jump_back method except that the parameter is * std::string. */ bool jump_back(const std::string& key) { _assert_(true); return jump_back(key.c_str(), key.size()); } /** * Step the cursor to the next record. * @return true on success, or false on failure. */ bool step() { _assert_(true); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_step", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } return true; } /** * Step the cursor to the previous record. * @return true on success, or false on failure. * @note This method is dedicated to tree databases. Some database types, especially hash * databases, may provide a dummy implementation. */ bool step_back() { _assert_(true); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_step_back", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } return true; } /** * Set the value of the current record. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @param step true to move the cursor to the next record, or false for no move. * @return true on success, or false on failure. */ bool set_value(const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX, bool step = false) { _assert_(vbuf && vsiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); inmap["value"] = std::string(vbuf, vsiz); if (xt < TimedDB::XTMAX) kc::strprintf(&inmap["xt"], "%lld", (long long)xt); if (step) inmap["step"] = ""; std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_set_value", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } return true; } /** * Set the value of the current record. * @note Equal to the original Cursor::set_value method except that the parameter is * std::string. */ bool set_value_str(const std::string& value, int64_t xt = kc::INT64MAX, bool step = false) { _assert_(true); return set_value(value.c_str(), value.size(), xt, step); } /** * Remove the current record. * @return true on success, or false on failure. * @note If no record corresponds to the key, false is returned. The cursor is moved to the * next record implicitly. */ bool remove() { _assert_(true); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_remove", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } return true; } /** * Get the key of the current record. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param step true to move the cursor to the next record, or false for no move. * @return the pointer to the key region of the current record, or NULL on failure. * @note If the cursor is invalidated, NULL is returned. Because an additional zero * code is appended at the end of the region of the return value, the return value can be * treated as a C-style string. Because the region of the return value is allocated with the * the new[] operator, it should be released with the delete[] operator when it is no longer * in use. */ char* get_key(size_t* sp, bool step = false) { _assert_(sp); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); if (step) inmap["step"] = ""; std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_get_key", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } size_t ksiz; const char* kbuf = strmapget(outmap, "key", &ksiz); if (!kbuf) { db_->set_error(RPCClient::RVELOGIC, "no information"); return NULL; } char* rbuf = new char[ksiz+1]; std::memcpy(rbuf, kbuf, ksiz); rbuf[ksiz] = '\0'; *sp = ksiz; return rbuf; } /** * Get the key of the current record. * @note Equal to the original Cursor::get_key method except that a parameter is a string to * contain the result and the return value is bool for success. */ bool get_key(std::string* key, bool step = false) { _assert_(key); size_t ksiz; char* kbuf = get_key(&ksiz, step); if (!kbuf) return false; key->clear(); key->append(kbuf, ksiz); delete[] kbuf; return true; } /** * Get the value of the current record. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param step true to move the cursor to the next record, or false for no move. * @return the pointer to the value region of the current record, or NULL on failure. * @note If the cursor is invalidated, NULL is returned. Because an additional zero * code is appended at the end of the region of the return value, the return value can be * treated as a C-style string. Because the region of the return value is allocated with the * the new[] operator, it should be released with the delete[] operator when it is no longer * in use. */ char* get_value(size_t* sp, bool step = false) { _assert_(sp); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); if (step) inmap["step"] = ""; std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_get_value", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } size_t vsiz; const char* vbuf = strmapget(outmap, "value", &vsiz); if (!vbuf) { db_->set_error(RPCClient::RVELOGIC, "no information"); return NULL; } char* rbuf = new char[vsiz+1]; std::memcpy(rbuf, vbuf, vsiz); rbuf[vsiz] = '\0'; *sp = vsiz; return rbuf; } /** * Get the value of the current record. * @note Equal to the original Cursor::get_value method except that a parameter is a string * to contain the result and the return value is bool for success. */ bool get_value(std::string* value, bool step = false) { _assert_(value); size_t vsiz; char* vbuf = get_value(&vsiz, step); if (!vbuf) return false; value->clear(); value->append(vbuf, vsiz); delete[] vbuf; return true; } /** * Get a pair of the key and the value of the current record. * @param ksp the pointer to the variable into which the size of the region of the return * value is assigned. * @param vbp the pointer to the variable into which the pointer to the value region is * assigned. * @param vsp the pointer to the variable into which the size of the value region is * assigned. * @param xtp the pointer to the variable into which the absolute expiration time is * assigned. If it is NULL, it is ignored. * @param step true to move the cursor to the next record, or false for no move. * @return the pointer to the pair of the key region, or NULL on failure. * @note If the cursor is invalidated, NULL is returned. Because an additional zero code is * appended at the end of each region of the key and the value, each region can be treated * as a C-style string. The return value should be deleted explicitly by the caller with * the detele[] operator. */ char* get(size_t* ksp, const char** vbp, size_t* vsp, int64_t* xtp = NULL, bool step = false) { _assert_(ksp && vbp && vsp); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); if (step) inmap["step"] = ""; std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_get", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); *ksp = 0; *vbp = NULL; *vsp = 0; return false; } size_t ksiz = 0; const char* kbuf = strmapget(outmap, "key", &ksiz); size_t vsiz = 0; const char* vbuf = strmapget(outmap, "value", &vsiz); if (!kbuf || !vbuf) { db_->set_error(RPCClient::RVELOGIC, "no information"); *ksp = 0; *vbp = NULL; *vsp = 0; return NULL; } const char* rp = strmapget(outmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; char* rbuf = new char[ksiz+vsiz+2]; std::memcpy(rbuf, kbuf, ksiz); rbuf[ksiz] = '\0'; std::memcpy(rbuf + ksiz + 1 , vbuf, vsiz); rbuf[ksiz+1+vsiz] = '\0'; *ksp = ksiz; *vbp = rbuf + ksiz + 1; *vsp = vsiz; if (xtp) *xtp = xt; return rbuf; } /** * Get a pair of the key and the value of the current record. * @note Equal to the original Cursor::get method except that parameters are strings * to contain the result and the return value is bool for success. */ bool get(std::string* key, std::string* value, int64_t* xtp = NULL, bool step = false) { _assert_(key && value); size_t ksiz, vsiz; const char* vbuf; char* kbuf = get(&ksiz, &vbuf, &vsiz, xtp, step); if (!kbuf) return false; key->clear(); key->append(kbuf, ksiz); value->clear(); value->append(vbuf, vsiz); delete[] kbuf; return true; } /** * Get a pair of the key and the value of the current record and remove it atomically. * @param ksp the pointer to the variable into which the size of the region of the return * value is assigned. * @param vbp the pointer to the variable into which the pointer to the value region is * assigned. * @param vsp the pointer to the variable into which the size of the value region is * assigned. * @param xtp the pointer to the variable into which the absolute expiration time is * assigned. If it is NULL, it is ignored. * @return the pointer to the pair of the key region, or NULL on failure. * @note If the cursor is invalidated, NULL is returned. Because an additional zero code is * appended at the end of each region of the key and the value, each region can be treated * as a C-style string. The return value should be deleted explicitly by the caller with * the detele[] operator. The cursor is moved to the next record implicitly. */ char* seize(size_t* ksp, const char** vbp, size_t* vsp, int64_t* xtp = NULL) { _assert_(ksp && vbp && vsp); std::map<std::string, std::string> inmap; db_->set_sig_param(inmap); db_->set_db_param(inmap); set_cur_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = db_->rpc_.call("cur_seize", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { db_->set_rpc_error(rv, outmap); return false; } size_t ksiz = 0; const char* kbuf = strmapget(outmap, "key", &ksiz); size_t vsiz = 0; const char* vbuf = strmapget(outmap, "value", &vsiz); if (!kbuf || !vbuf) { db_->set_error(RPCClient::RVELOGIC, "no information"); return NULL; } const char* rp = strmapget(outmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; char* rbuf = new char[ksiz+vsiz+2]; std::memcpy(rbuf, kbuf, ksiz); rbuf[ksiz] = '\0'; std::memcpy(rbuf + ksiz + 1 , vbuf, vsiz); rbuf[ksiz+1+vsiz] = '\0'; *ksp = ksiz; *vbp = rbuf + ksiz + 1; *vsp = vsiz; if (xtp) *xtp = xt; return rbuf; } /** * Get a pair of the key and the value of the current record and remove it atomically. * @note Equal to the original Cursor::seize method except that parameters are strings * to contain the result and the return value is bool for success. */ bool seize(std::string* key, std::string* value, int64_t* xtp = NULL) { _assert_(key && value); size_t ksiz, vsiz; const char* vbuf; char* kbuf = seize(&ksiz, &vbuf, &vsiz, xtp); if (!kbuf) return false; key->clear(); key->append(kbuf, ksiz); value->clear(); value->append(vbuf, vsiz); delete[] kbuf; return true; } /** * Get the database object. * @return the database object. */ RemoteDB* db() { _assert_(true); return db_; } /** * Get the last happened error. * @return the last happened error. */ Error error() { _assert_(true); return db()->error(); } private: /** * Set the parameter of the target cursor. * @param inmap the string map to contain the input parameters. */ void set_cur_param(std::map<std::string, std::string>& inmap) { _assert_(true); kc::strprintf(&inmap["CUR"], "%lld", (long long)id_); } /** Dummy constructor to forbid the use. */ Cursor(const Cursor&); /** Dummy Operator to forbid the use. */ Cursor& operator =(const Cursor&); /** The inner database. */ RemoteDB* db_; /** The ID number. */ int64_t id_; }; /** * Error data. */ class Error { public: /** * Error codes. */ enum Code { SUCCESS = RPCClient::RVSUCCESS, ///< success NOIMPL = RPCClient::RVENOIMPL, ///< not implemented INVALID = RPCClient::RVEINVALID, ///< invalid operation LOGIC = RPCClient::RVELOGIC, ///< logical inconsistency TIMEOUT = RPCClient::RVETIMEOUT, ///< timeout INTERNAL = RPCClient::RVEINTERNAL, ///< internal error NETWORK = RPCClient::RVENETWORK, ///< network error EMISC = RPCClient::RVEMISC ///< miscellaneous error }; /** * Default constructor. */ explicit Error() : code_(SUCCESS), message_("no error") { _assert_(true); } /** * Copy constructor. * @param src the source object. */ Error(const Error& src) : code_(src.code_), message_(src.message_) { _assert_(true); } /** * Constructor. * @param code an error code. * @param message a supplement message. */ explicit Error(Code code, const std::string& message) : code_(code), message_(message) { _assert_(true); } /** * Destructor. */ ~Error() { _assert_(true); } /** * Set the error information. * @param code an error code. * @param message a supplement message. */ void set(Code code, const std::string& message) { _assert_(true); code_ = code; message_ = message; } /** * Get the error code. * @return the error code. */ Code code() const { _assert_(true); return code_; } /** * Get the readable string of the code. * @return the readable string of the code. */ const char* name() const { _assert_(true); return codename(code_); } /** * Get the supplement message. * @return the supplement message. */ const char* message() const { _assert_(true); return message_.c_str(); } /** * Get the readable string of an error code. * @param code the error code. * @return the readable string of the error code. */ static const char* codename(Code code) { _assert_(true); switch (code) { case SUCCESS: return "success"; case NOIMPL: return "not implemented"; case INVALID: return "invalid operation"; case LOGIC: return "logical inconsistency"; case INTERNAL: return "internal error"; case NETWORK: return "network error"; default: break; } return "miscellaneous error"; } /** * Assignment operator from the self type. * @param right the right operand. * @return the reference to itself. */ Error& operator =(const Error& right) { _assert_(true); if (&right == this) return *this; code_ = right.code_; message_ = right.message_; return *this; } /** * Cast operator to integer. * @return the error code. */ operator int32_t() const { return code_; } private: /** The error code. */ Code code_; /** The supplement message. */ std::string message_; }; /** * Record for bulk operation. */ struct BulkRecord { uint16_t dbidx; ///< index of the target database std::string key; ///< key std::string value; ///< value int64_t xt; ///< expiration time }; /** * Magic data in binary protocol. */ enum BinaryMagic { BMNOP = 0xb0, ///< no operation BMREPLICATION = 0xb1, ///< replication BMPLAYSCRIPT = 0xb4, ///< call a scripting procedure BMSETBULK = 0xb8, ///< set in bulk BMREMOVEBULK = 0xb9, ///< remove in bulk BMGETBULK = 0xba, ///< get in bulk BMERROR = 0xbf ///< error }; /** * Options in binary protocol. */ enum BinaryOption { BONOREPLY = 1 << 0 ///< no reply }; /** * Default constructor. */ explicit RemoteDB() : rpc_(), ecode_(RPCClient::RVSUCCESS), emsg_("no error"), dbexpr_(""), curs_(), curcnt_(0), sigwait_(false), sigwaitname_(""), sigwaittime_(0), sigsend_(false), sigsendbrd_(false) { _assert_(true); } /** * Destructor. */ virtual ~RemoteDB() { _assert_(true); if (!curs_.empty()) { CursorList::const_iterator cit = curs_.begin(); CursorList::const_iterator citend = curs_.end(); while (cit != citend) { Cursor* cur = *cit; cur->db_ = NULL; ++cit; } } } /** * Get the last happened error code. * @return the last happened error code. */ Error error() const { _assert_(true); return Error((Error::Code)ecode_, emsg_); } /** * Open the connection. * @param host the name or the address of the server. If it is an empty string, the local host * is specified. * @param port the port numger of the server. * @param timeout the timeout of each operation in seconds. If it is not more than 0, no * timeout is specified. * @return true on success, or false on failure. */ bool open(const std::string& host = "", int32_t port = DEFPORT, double timeout = -1) { _assert_(true); if (!rpc_.open(host, port, timeout)) { set_error(RPCClient::RVENETWORK, "connection failed"); return false; } return true; } /** * Close the connection. * @param grace true for graceful shutdown, or false for immediate disconnection. * @return true on success, or false on failure. */ bool close(bool grace = true) { _assert_(true); return rpc_.close(); } /** * Get the report of the server information. * @param strmap a string map to contain the result. * @return true on success, or false on failure. */ bool report(std::map<std::string, std::string>* strmap) { _assert_(strmap); strmap->clear(); std::map<std::string, std::string> inmap; set_sig_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("report", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } strmap->insert(outmap.begin(), outmap.end()); return true; } /** * Call a procedure of the scripting extension. * @param name the name of the procedure to call. * @param params a string map containing the input parameters. * @param result a string map to contain the output data. * @return true on success, or false on failure. */ bool play_script(const std::string& name, const std::map<std::string, std::string>& params, std::map<std::string, std::string>* result) { _assert_(result); result->clear(); std::map<std::string, std::string> inmap; set_sig_param(inmap); inmap["name"] = name; std::map<std::string, std::string>::const_iterator it = params.begin(); std::map<std::string, std::string>::const_iterator itend = params.end(); while (it != itend) { std::string key = "_"; key.append(it->first); inmap[key] = it->second; ++it; } std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("play_script", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } it = outmap.begin(); itend = outmap.end(); while (it != itend) { const char* kbuf = it->first.data(); size_t ksiz = it->first.size(); if (ksiz > 0 && *kbuf == '_') { std::string key(kbuf + 1, ksiz - 1); (*result)[key] = it->second; } ++it; } return true; } /** * Set the replication configuration. * @param host the name or the address of the master server. If it is an empty string, * replication is disabled. * @param port the port numger of the server. * @param ts the maximum time stamp of already read logs. If it is kyotocabinet::UINT64MAX, * the current setting is not modified. If it is kyotocabinet::UINT64MAX - 1, the current * time is specified. * @param iv the interval of each replication operation in milliseconds. If it is negative, * the current interval is not modified. * @return true on success, or false on failure. */ bool tune_replication(const std::string& host = "", int32_t port = DEFPORT, uint64_t ts = kc::UINT64MAX, double iv = -1) { std::map<std::string, std::string> inmap; set_sig_param(inmap); if (!host.empty()) inmap["host"] = host; if (port != DEFPORT) kc::strprintf(&inmap["port"], "%d", port); if (ts == kc::UINT64MAX - 1) { inmap["ts"] = "now"; } else if (ts != kc::UINT64MAX) { kc::strprintf(&inmap["ts"], "%llu", (unsigned long long)ts); } if (iv >= 0) kc::strprintf(&inmap["iv"], "%.6f", iv); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("tune_replication", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Get status of each update log files. * @param fstvec a vector to store status structures of each update log files. * @return true on success, or false on failure. */ bool ulog_list(std::vector<UpdateLogger::FileStatus>* fstvec) { _assert_(fstvec); fstvec->clear(); std::map<std::string, std::string> inmap; set_sig_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("ulog_list", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } std::map<std::string, std::string>::iterator it = outmap.begin(); std::map<std::string, std::string>::iterator itend = outmap.end(); while (it != itend) { size_t idx = it->second.find(':'); if (idx != std::string::npos) { const std::string& tsstr = it->second.substr(idx + 1); int64_t fsiz = kc::atoi(it->second.c_str()); int64_t fts = kc::atoi(tsstr.c_str()); if (!it->first.empty() && fsiz >= 0 && fts >= 0) { UpdateLogger::FileStatus fs = { it->first, fsiz, fts }; fstvec->push_back(fs); } } ++it; } return true; } /** * Remove old update log files. * @param ts the maximum time stamp of disposable logs. * @return true on success, or false on failure. */ bool ulog_remove(uint64_t ts = kc::UINT64MAX) { _assert_(true); std::map<std::string, std::string> inmap; set_sig_param(inmap); kc::strprintf(&inmap["ts"], "%llu", (unsigned long long)ts); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("ulog_remove", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Get the miscellaneous status information. * @param strmap a string map to contain the result. * @return true on success, or false on failure. */ bool status(std::map<std::string, std::string>* strmap) { _assert_(strmap); strmap->clear(); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("status", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } strmap->insert(outmap.begin(), outmap.end()); return true; } /** * Remove all records. * @return true on success, or false on failure. */ bool clear() { _assert_(true); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("clear", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Synchronize updated contents with the file and the device. * @param hard true for physical synchronization with the device, or false for logical * synchronization with the file system. * @param command the command name to process the database file. If it is an empty string, no * postprocessing is performed. * @return true on success, or false on failure. */ bool synchronize(bool hard, const std::string& command = "") { _assert_(true); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); if (hard) inmap["hard"] = ""; if (!command.empty()) inmap["command"] = command; std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("synchronize", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Get the number of records. * @return the number of records, or -1 on failure. */ int64_t count() { _assert_(true); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("status", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return -1; } const char* rp = strmapget(outmap, "count"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return -1; } return kc::atoi(rp); } /** * Get the size of the database file. * @return the size of the database file in bytes, or -1 on failure. */ int64_t size() { _assert_(true); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("status", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return -1; } const char* rp = strmapget(outmap, "size"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return -1; } return kc::atoi(rp); } /** * Set the value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. * @note If no record corresponds to the key, a new record is created. If the corresponding * record exists, the value is overwritten. */ bool set(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); inmap["value"] = std::string(vbuf, vsiz); if (xt < TimedDB::XTMAX) kc::strprintf(&inmap["xt"], "%lld", (long long)xt); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("set", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Set the value of a record. * @note Equal to the original DB::set method except that the parameters are std::string. */ bool set(const std::string& key, const std::string& value, int64_t xt = kc::INT64MAX) { _assert_(true); return set(key.c_str(), key.size(), value.c_str(), value.size(), xt); } /** * Add a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. * @note If no record corresponds to the key, a new record is created. If the corresponding * record exists, the record is not modified and false is returned. */ bool add(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); inmap["value"] = std::string(vbuf, vsiz); if (xt < TimedDB::XTMAX) kc::strprintf(&inmap["xt"], "%lld", (long long)xt); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("add", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Set the value of a record. * @note Equal to the original DB::add method except that the parameters are std::string. */ bool add(const std::string& key, const std::string& value, int64_t xt = kc::INT64MAX) { _assert_(true); return add(key.c_str(), key.size(), value.c_str(), value.size(), xt); } /** * Replace the value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. * @note If no record corresponds to the key, no new record is created and false is returned. * If the corresponding record exists, the value is modified. */ bool replace(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); inmap["value"] = std::string(vbuf, vsiz); if (xt < TimedDB::XTMAX) kc::strprintf(&inmap["xt"], "%lld", (long long)xt); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("replace", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Replace the value of a record. * @note Equal to the original DB::replace method except that the parameters are std::string. */ bool replace(const std::string& key, const std::string& value, int64_t xt = kc::INT64MAX) { _assert_(true); return replace(key.c_str(), key.size(), value.c_str(), value.size(), xt); } /** * Append the value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param vbuf the pointer to the value region. * @param vsiz the size of the value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. * @note If no record corresponds to the key, a new record is created. If the corresponding * record exists, the given value is appended at the end of the existing value. */ bool append(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && vbuf && vsiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); inmap["value"] = std::string(vbuf, vsiz); if (xt < TimedDB::XTMAX) kc::strprintf(&inmap["xt"], "%lld", (long long)xt); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("append", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Set the value of a record. * @note Equal to the original DB::append method except that the parameters are std::string. */ bool append(const std::string& key, const std::string& value, int64_t xt = kc::INT64MAX) { _assert_(true); return append(key.c_str(), key.size(), value.c_str(), value.size(), xt); } /** * Add a number to the numeric integer value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param num the additional number. * @param orig the origin number if no record corresponds to the key. If it is INT64MIN and * no record corresponds, this function fails. If it is INT64MAX, the value is set as the * additional number regardless of the current value. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return the result value, or kyotocabinet::INT64MIN on failure. * @note The value is serialized as an 8-byte binary integer in big-endian order, not a decimal * string. If existing value is not 8-byte, this function fails. */ int64_t increment(const char* kbuf, size_t ksiz, int64_t num, int64_t orig = 0, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); kc::strprintf(&inmap["num"], "%lld", (long long)num); kc::strprintf(&inmap["orig"], "%lld", (long long)orig); if (xt < TimedDB::XTMAX) kc::strprintf(&inmap["xt"], "%lld", (long long)xt); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("increment", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return kc::INT64MIN; } const char* rp = strmapget(outmap, "num"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return kc::INT64MIN; } return kc::atoi(rp); } /** * Add a number to the numeric integer value of a record. * @note Equal to the original DB::increment method except that the parameter is std::string. */ int64_t increment(const std::string& key, int64_t num, int64_t orig = 0, int64_t xt = kc::INT64MAX) { _assert_(true); return increment(key.c_str(), key.size(), num, orig, xt); } /** * Add a number to the numeric double value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param num the additional number. * @param orig the origin number if no record corresponds to the key. If it is negative * infinity and no record corresponds, this function fails. If it is positive infinity, the * value is set as the additional number regardless of the current value. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return the result value, or Not-a-number on failure. * @note The value is serialized as an 16-byte binary fixed-point number in big-endian order, * not a decimal string. If existing value is not 16-byte, this function fails. */ double increment_double(const char* kbuf, size_t ksiz, double num, double orig = 0, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); kc::strprintf(&inmap["num"], "%f", num); kc::strprintf(&inmap["orig"], "%f", orig); if (xt < TimedDB::XTMAX) kc::strprintf(&inmap["xt"], "%lld", (long long)xt); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("increment_double", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return kc::nan(); } const char* rp = strmapget(outmap, "num"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return kc::nan(); } return kc::atof(rp); } /** * Add a number to the numeric double value of a record. * @note Equal to the original DB::increment_double method except that the parameter is * std::string. */ double increment_double(const std::string& key, double num, double orig = 0, int64_t xt = kc::INT64MAX) { _assert_(true); return increment_double(key.c_str(), key.size(), num, orig, xt); } /** * Perform compare-and-swap. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param ovbuf the pointer to the old value region. NULL means that no record corresponds. * @param ovsiz the size of the old value region. * @param nvbuf the pointer to the new value region. NULL means that the record is removed. * @param nvsiz the size of new old value region. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @return true on success, or false on failure. */ bool cas(const char* kbuf, size_t ksiz, const char* ovbuf, size_t ovsiz, const char* nvbuf, size_t nvsiz, int64_t xt = kc::INT64MAX) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); if (ovbuf) inmap["oval"] = std::string(ovbuf, ovsiz); if (nvbuf) inmap["nval"] = std::string(nvbuf, nvsiz); if (xt < TimedDB::XTMAX) kc::strprintf(&inmap["xt"], "%lld", (long long)xt); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("cas", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Perform compare-and-swap. * @note Equal to the original DB::cas method except that the parameters are std::string. */ bool cas(const std::string& key, const std::string& ovalue, const std::string& nvalue, int64_t xt = kc::INT64MAX) { _assert_(true); return cas(key.c_str(), key.size(), ovalue.c_str(), ovalue.size(), nvalue.c_str(), nvalue.size(), xt); } /** * Remove a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @return true on success, or false on failure. * @note If no record corresponds to the key, false is returned. */ bool remove(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("remove", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Remove a record. * @note Equal to the original DB::remove method except that the parameter is std::string. */ bool remove(const std::string& key) { _assert_(true); return remove(key.c_str(), key.size()); } /** * Retrieve the value of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param xtp the pointer to the variable into which the absolute expiration time is assigned. * If it is NULL, it is ignored. * @return the pointer to the value region of the corresponding record, or NULL on failure. * @note If no record corresponds to the key, NULL is returned. Because an additional zero * code is appended at the end of the region of the return value, the return value can be * treated as a C-style string. Because the region of the return value is allocated with the * the new[] operator, it should be released with the delete[] operator when it is no longer * in use. */ char* get(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp = NULL) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && sp); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("get", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); *sp = 0; if (xtp) *xtp = 0; return NULL; } size_t vsiz; const char* vbuf = strmapget(outmap, "value", &vsiz); if (!vbuf) { set_error(RPCClient::RVELOGIC, "no information"); *sp = 0; if (xtp) *xtp = 0; return NULL; } const char* rp = strmapget(outmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; char* rbuf = new char[vsiz+1]; std::memcpy(rbuf, vbuf, vsiz); rbuf[vsiz] = '\0'; *sp = vsiz; if (xtp) *xtp = xt; return rbuf; } /** * Retrieve the value of a record. * @note Equal to the original DB::get method except that the first parameters is the key * string and the second parameter is a string to contain the result and the return value is * bool for success. */ bool get(const std::string& key, std::string* value, int64_t* xtp = NULL) { _assert_(value); size_t vsiz; char* vbuf = get(key.c_str(), key.size(), &vsiz, xtp); if (!vbuf) return false; value->clear(); value->append(vbuf, vsiz); delete[] vbuf; return true; } /** * Check the existence of a record. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param xtp the pointer to the variable into which the absolute expiration time is assigned. * If it is NULL, it is ignored. * @return the size of the value, or -1 on failure. */ int32_t check(const char* kbuf, size_t ksiz, int64_t* xtp = NULL) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("check", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); if (xtp) *xtp = 0; return -1; } const char* rp = strmapget(outmap, "vsiz"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); if (xtp) *xtp = 0; return -1; } int32_t vsiz = kc::atoi(rp); rp = strmapget(outmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; if (xtp) *xtp = xt; return vsiz; } /** * Check the existence of a record. * @note Equal to the original DB::check method except that the first parameters is the key * string. */ int32_t check(const std::string& key, int64_t* xtp = NULL) { return check(key.data(), key.size(), xtp); } /** * Retrieve the value of a record and remove it atomically. * @param kbuf the pointer to the key region. * @param ksiz the size of the key region. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param xtp the pointer to the variable into which the absolute expiration time is assigned. * If it is NULL, it is ignored. * @return the pointer to the value region of the corresponding record, or NULL on failure. * @note If no record corresponds to the key, NULL is returned. Because an additional zero * code is appended at the end of the region of the return value, the return value can be * treated as a C-style string. Because the region of the return value is allocated with the * the new[] operator, it should be released with the delete[] operator when it is no longer * in use. */ char* seize(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp = NULL) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && sp); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["key"] = std::string(kbuf, ksiz); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("seize", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); *sp = 0; if (xtp) *xtp = 0; return NULL; } size_t vsiz; const char* vbuf = strmapget(outmap, "value", &vsiz); if (!vbuf) { set_error(RPCClient::RVELOGIC, "no information"); *sp = 0; if (xtp) *xtp = 0; return NULL; } const char* rp = strmapget(outmap, "xt"); int64_t xt = rp ? kc::atoi(rp) : kc::INT64MAX; char* rbuf = new char[vsiz+1]; std::memcpy(rbuf, vbuf, vsiz); rbuf[vsiz] = '\0'; *sp = vsiz; if (xtp) *xtp = xt; return rbuf; } /** * Retrieve the value of a record and remove it atomically. * @note Equal to the original DB::seize method except that the first parameters is the key * string and the second parameter is a string to contain the result and the return value is * bool for success. */ bool seize(const std::string& key, std::string* value, int64_t* xtp = NULL) { _assert_(value); size_t vsiz; char* vbuf = seize(key.c_str(), key.size(), &vsiz, xtp); if (!vbuf) return false; value->clear(); value->append(vbuf, vsiz); delete[] vbuf; return true; } /** * Store records at once. * @param recs the records to store. * @param xt the expiration time from now in seconds. If it is negative, the absolute value * is treated as the epoch time. * @param atomic true to perform all operations atomically, or false for non-atomic operations. * @return the number of stored records, or -1 on failure. */ int64_t set_bulk(const std::map<std::string, std::string>& recs, int64_t xt = kc::INT64MAX, bool atomic = true) { _assert_(true); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); if (xt < TimedDB::XTMAX) kc::strprintf(&inmap["xt"], "%lld", (long long)xt); if (atomic) inmap["atomic"] = ""; std::map<std::string, std::string>::const_iterator it = recs.begin(); std::map<std::string, std::string>::const_iterator itend = recs.end(); while (it != itend) { std::string key = "_"; key.append(it->first); inmap[key] = it->second; ++it; } std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("set_bulk", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return -1; } const char* rp = strmapget(outmap, "num"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return -1; } return kc::atoi(rp); } /** * Store records at once. * @param keys the keys of the records to remove. * @param atomic true to perform all operations atomically, or false for non-atomic operations. * @return the number of removed records, or -1 on failure. */ int64_t remove_bulk(const std::vector<std::string>& keys, bool atomic = true) { _assert_(true); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); if (atomic) inmap["atomic"] = ""; std::vector<std::string>::const_iterator it = keys.begin(); std::vector<std::string>::const_iterator itend = keys.end(); while (it != itend) { std::string key = "_"; key.append(*it); inmap[key] = ""; ++it; } std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("remove_bulk", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return -1; } const char* rp = strmapget(outmap, "num"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return -1; } return kc::atoi(rp); } /** * Retrieve records at once. * @param keys the keys of the records to retrieve. * @param recs a string map to contain the retrieved records. * @param atomic true to perform all operations atomically, or false for non-atomic operations. * @return the number of retrieved records, or -1 on failure. */ int64_t get_bulk(const std::vector<std::string>& keys, std::map<std::string, std::string>* recs, bool atomic = true) { _assert_(true); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); if (atomic) inmap["atomic"] = ""; std::vector<std::string>::const_iterator it = keys.begin(); std::vector<std::string>::const_iterator itend = keys.end(); while (it != itend) { std::string key = "_"; key.append(*it); inmap[key] = ""; ++it; } std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("get_bulk", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return -1; } std::map<std::string, std::string>::const_iterator oit = outmap.begin(); std::map<std::string, std::string>::const_iterator oitend = outmap.end(); while (oit != oitend) { const char* kbuf = oit->first.data(); size_t ksiz = oit->first.size(); if (ksiz > 0 && *kbuf == '_') { std::string key(kbuf + 1, ksiz - 1); (*recs)[key] = oit->second; } ++oit; } const char* rp = strmapget(outmap, "num"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return -1; } return kc::atoi(rp); } /** * Scan the database and eliminate regions of expired records. * @param step the number of steps. If it is not more than 0, the whole region is scanned. * @return true on success, or false on failure. */ bool vacuum(int64_t step = 0) { _assert_(true); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); if (step > 0) kc::strprintf(&inmap["step"], "%lld", (long long)step); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("vacuum", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return false; } return true; } /** * Get keys matching a prefix string. * @param prefix the prefix string. * @param strvec a string vector to contain the result. * @param max the maximum number to retrieve. If it is negative, no limit is specified. * @return the number of retrieved keys or -1 on failure. */ int64_t match_prefix(const std::string& prefix, std::vector<std::string>* strvec, int64_t max = -1) { _assert_(strvec); strvec->clear(); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["prefix"] = prefix; if (max >= 0) kc::strprintf(&inmap["max"], "%lld", (long long)max); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("match_prefix", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return -1; } std::map<std::string, std::string>::const_iterator oit = outmap.begin(); std::map<std::string, std::string>::const_iterator oitend = outmap.end(); std::vector<OrderedKey> okeys; while (oit != oitend) { const char* kbuf = oit->first.data(); size_t ksiz = oit->first.size(); if (ksiz > 0 && *kbuf == '_') { std::string key(kbuf + 1, ksiz - 1); OrderedKey okey; okey.order = kc::atoi(oit->second.c_str()); okey.key = key; okeys.push_back(okey); } ++oit; } std::sort(okeys.begin(), okeys.end()); std::vector<OrderedKey>::const_iterator okit = okeys.begin(); std::vector<OrderedKey>::const_iterator okitend = okeys.end(); while (okit != okitend) { strvec->push_back(okit->key); ++okit; } const char* rp = strmapget(outmap, "num"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return -1; } return kc::atoi(rp); } /** * Get keys matching a regular expression string. * @param regex the regular expression string. * @param strvec a string vector to contain the result. * @param max the maximum number to retrieve. If it is negative, no limit is specified. * @return the number of retrieved keys or -1 on failure. */ int64_t match_regex(const std::string& regex, std::vector<std::string>* strvec, int64_t max = -1) { _assert_(strvec); strvec->clear(); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["regex"] = regex; if (max >= 0) kc::strprintf(&inmap["max"], "%lld", (long long)max); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("match_regex", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return -1; } std::map<std::string, std::string>::const_iterator oit = outmap.begin(); std::map<std::string, std::string>::const_iterator oitend = outmap.end(); std::vector<OrderedKey> okeys; while (oit != oitend) { const char* kbuf = oit->first.data(); size_t ksiz = oit->first.size(); if (ksiz > 0 && *kbuf == '_') { std::string key(kbuf + 1, ksiz - 1); OrderedKey okey; okey.order = kc::atoi(oit->second.c_str()); okey.key = key; okeys.push_back(okey); } ++oit; } std::sort(okeys.begin(), okeys.end()); std::vector<OrderedKey>::const_iterator okit = okeys.begin(); std::vector<OrderedKey>::const_iterator okitend = okeys.end(); while (okit != okitend) { strvec->push_back(okit->key); ++okit; } const char* rp = strmapget(outmap, "num"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return -1; } return kc::atoi(rp); } /** * Get keys similar to a string in terms of the levenshtein distance. * @param origin the origin string. * @param range the maximum distance of keys to adopt. * @param utf flag to treat keys as UTF-8 strings. * @param strvec a string vector to contain the result. * @param max the maximum number to retrieve. If it is negative, no limit is specified. * @return the number of retrieved keys or -1 on failure. */ int64_t match_similar(const std::string& origin, size_t range, bool utf, std::vector<std::string>* strvec, int64_t max = -1) { _assert_(strvec); strvec->clear(); std::map<std::string, std::string> inmap; set_sig_param(inmap); set_db_param(inmap); inmap["origin"] = origin; kc::strprintf(&inmap["range"], "%lld", (long long)range); kc::strprintf(&inmap["utf"], "%d", (int)utf); if (max >= 0) kc::strprintf(&inmap["max"], "%lld", (long long)max); std::map<std::string, std::string> outmap; RPCClient::ReturnValue rv = rpc_.call("match_similar", &inmap, &outmap); if (rv != RPCClient::RVSUCCESS) { set_rpc_error(rv, outmap); return -1; } std::map<std::string, std::string>::const_iterator oit = outmap.begin(); std::map<std::string, std::string>::const_iterator oitend = outmap.end(); std::vector<OrderedKey> okeys; while (oit != oitend) { const char* kbuf = oit->first.data(); size_t ksiz = oit->first.size(); if (ksiz > 0 && *kbuf == '_') { std::string key(kbuf + 1, ksiz - 1); OrderedKey okey; okey.order = kc::atoi(oit->second.c_str()); okey.key = key; okeys.push_back(okey); } ++oit; } std::sort(okeys.begin(), okeys.end()); std::vector<OrderedKey>::const_iterator okit = okeys.begin(); std::vector<OrderedKey>::const_iterator okitend = okeys.end(); while (okit != okitend) { strvec->push_back(okit->key); ++okit; } const char* rp = strmapget(outmap, "num"); if (!rp) { set_error(RPCClient::RVELOGIC, "no information"); return -1; } return kc::atoi(rp); } /** * Set the target database. * @param expr the expression of the target database. */ void set_target(const std::string& expr) { _assert_(true); dbexpr_ = expr; } /** * Set the signal waiting condition of the next procedure. * @param name the name of the condition variable. * @param timeout the timeout in seconds. * @note This setting is used only in the next procedure call and then cleared. */ void set_signal_waiting(const std::string& name, double timeout = 0) { _assert_(true); sigwait_ = true; sigwaitname_ = name; sigwaittime_ = timeout; } /** * Set the signal sending condition of the next procedure. * @param name the name of the condition variable. * @param broadcast true to send the signal to every corresponding thread, or false to send it * to just one thread. * @note This setting is used only in the next procedure call and then cleared. */ void set_signal_sending(const std::string& name, bool broadcast = false) { _assert_(true); sigsend_ = true; sigsendname_ = name; sigsendbrd_ = broadcast; } /** * Call a procedure of the scripting extension in the binary protocol. * @param name the name of the procedure to call. * @param params a string map containing the input parameters. * @param result a string map to contain the output data. If it is NULL, it is ignored. * @param opts the optional features by bitwise-or: RemoteDB::BONOREPLY to ignore reply from * the server. * @return true on success, or false on failure. */ bool play_script_binary(const std::string& name, const std::map<std::string, std::string>& params, std::map<std::string, std::string>* result = NULL, uint32_t opts = 0) { _assert_(true); if (result) result->clear(); size_t rsiz = 1 + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t) + name.size(); std::map<std::string, std::string>::const_iterator it = params.begin(); std::map<std::string, std::string>::const_iterator itend = params.end(); while (it != itend) { rsiz += sizeof(uint32_t) + sizeof(uint32_t); rsiz += it->first.size() + it->second.size(); ++it; } char* rbuf = new char[rsiz]; char* wp = rbuf; *(wp++) = BMPLAYSCRIPT; uint32_t flags = 0; if (opts & BONOREPLY) flags |= BONOREPLY; kc::writefixnum(wp, flags, sizeof(flags)); wp += sizeof(flags); kc::writefixnum(wp, name.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); kc::writefixnum(wp, params.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); std::memcpy(wp, name.data(), name.size()); wp += name.size(); it = params.begin(); while (it != itend) { kc::writefixnum(wp, it->first.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); kc::writefixnum(wp, it->second.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); std::memcpy(wp, it->first.data(), it->first.size()); wp += it->first.size(); std::memcpy(wp, it->second.data(), it->second.size()); wp += it->second.size(); ++it; } Socket* sock = rpc_.reveal_core()->reveal_core(); char stack[RECBUFSIZ]; bool err = false; if (sock->send(rbuf, rsiz)) { if (!(opts & BONOREPLY)) { char hbuf[sizeof(uint32_t)]; int32_t c = sock->receive_byte(); if (c == BMPLAYSCRIPT) { if (sock->receive(hbuf, sizeof(hbuf))) { uint32_t rnum = kc::readfixnum(hbuf, sizeof(uint32_t)); for (int64_t i = 0; !err && i < rnum; i++) { char ubuf[sizeof(uint32_t)+sizeof(uint32_t)]; if (sock->receive(ubuf, sizeof(ubuf))) { const char* rp = ubuf; size_t ksiz = kc::readfixnum(rp, sizeof(uint32_t)); rp += sizeof(uint32_t); size_t vsiz = kc::readfixnum(rp, sizeof(uint32_t)); rp += sizeof(uint32_t); if (ksiz <= DATAMAXSIZ && vsiz <= DATAMAXSIZ) { size_t jsiz = ksiz + vsiz; char* jbuf = jsiz > sizeof(stack) ? new char[jsiz] : stack; if (sock->receive(jbuf, jsiz)) { std::string key(jbuf, ksiz); std::string value(jbuf + ksiz, vsiz); if (result) (*result)[key] = value; } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; err = true; } if (jbuf != stack) delete[] jbuf; } else { ecode_ = RPCClient::RVEINTERNAL; emsg_ = "internal error"; err = true; } } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; err = true; } } } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; err = true; } } else if (c == BMERROR) { ecode_ = RPCClient::RVEINTERNAL; emsg_ = "internal error"; err = true; } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; err = true; } } } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "send failed"; err = true; } delete[] rbuf; return !err; } /** * Store records at once in the binary protocol. * @param recs the records to store. * @param opts the optional features by bitwise-or: RemoteDB::BONOREPLY to ignore reply from * the server. * @return the number of stored records, or -1 on failure. */ int64_t set_bulk_binary(const std::vector<BulkRecord>& recs, uint32_t opts = 0) { _assert_(true); size_t rsiz = 1 + sizeof(uint32_t) + sizeof(uint32_t); std::vector<BulkRecord>::const_iterator it = recs.begin(); std::vector<BulkRecord>::const_iterator itend = recs.end(); while (it != itend) { rsiz += sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(int64_t); rsiz += it->key.size() + it->value.size(); ++it; } char* rbuf = new char[rsiz]; char* wp = rbuf; *(wp++) = BMSETBULK; uint32_t flags = 0; if (opts & BONOREPLY) flags |= BONOREPLY; kc::writefixnum(wp, flags, sizeof(flags)); wp += sizeof(flags); kc::writefixnum(wp, recs.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); it = recs.begin(); while (it != itend) { kc::writefixnum(wp, it->dbidx, sizeof(uint16_t)); wp += sizeof(uint16_t); kc::writefixnum(wp, it->key.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); kc::writefixnum(wp, it->value.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); kc::writefixnum(wp, it->xt, sizeof(int64_t)); wp += sizeof(int64_t); std::memcpy(wp, it->key.data(), it->key.size()); wp += it->key.size(); std::memcpy(wp, it->value.data(), it->value.size()); wp += it->value.size(); ++it; } Socket* sock = rpc_.reveal_core()->reveal_core(); int64_t rv; if (sock->send(rbuf, rsiz)) { if (opts & BONOREPLY) { rv = 0; } else { char hbuf[sizeof(uint32_t)]; int32_t c = sock->receive_byte(); if (c == BMSETBULK) { if (sock->receive(hbuf, sizeof(hbuf))) { rv = kc::readfixnum(hbuf, sizeof(uint32_t)); } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; rv = -1; } } else if (c == BMERROR) { ecode_ = RPCClient::RVEINTERNAL; emsg_ = "internal error"; rv = -1; } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; rv = -1; } } } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "send failed"; rv = -1; } delete[] rbuf; return rv; } /** * Store records at once in the binary protocol. * @param recs the records to remove. * @param opts the optional features by bitwise-or: RemoteDB::BONOREPLY to ignore reply from * the server. * @return the number of removed records, or -1 on failure. */ int64_t remove_bulk_binary(const std::vector<BulkRecord>& recs, uint32_t opts = 0) { _assert_(true); size_t rsiz = 1 + sizeof(uint32_t) + sizeof(uint32_t); std::vector<BulkRecord>::const_iterator it = recs.begin(); std::vector<BulkRecord>::const_iterator itend = recs.end(); while (it != itend) { rsiz += sizeof(uint16_t) + sizeof(uint32_t); rsiz += it->key.size(); ++it; } char* rbuf = new char[rsiz]; char* wp = rbuf; *(wp++) = BMREMOVEBULK; uint32_t flags = 0; if (opts & BONOREPLY) flags |= BONOREPLY; kc::writefixnum(wp, flags, sizeof(flags)); wp += sizeof(flags); kc::writefixnum(wp, recs.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); it = recs.begin(); while (it != itend) { kc::writefixnum(wp, it->dbidx, sizeof(uint16_t)); wp += sizeof(uint16_t); kc::writefixnum(wp, it->key.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); std::memcpy(wp, it->key.data(), it->key.size()); wp += it->key.size(); ++it; } Socket* sock = rpc_.reveal_core()->reveal_core(); int64_t rv; if (sock->send(rbuf, rsiz)) { if (opts & BONOREPLY) { rv = 0; } else { char hbuf[sizeof(uint32_t)]; int32_t c = sock->receive_byte(); if (c == BMREMOVEBULK) { if (sock->receive(hbuf, sizeof(hbuf))) { rv = kc::readfixnum(hbuf, sizeof(uint32_t)); } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; rv = -1; } } else if (c == BMERROR) { ecode_ = RPCClient::RVEINTERNAL; emsg_ = "internal error"; rv = -1; } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; rv = -1; } } } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "send failed"; rv = -1; } delete[] rbuf; return rv; } /** * Retrieve records at once in the binary protocol. * @param recs the records to retrieve. The value member and the xt member of each retrieved * record will be set appropriately. The xt member of each missing record will be -1. * @return the number of retrieved records, or -1 on failure. */ int64_t get_bulk_binary(std::vector<BulkRecord>* recs) { _assert_(recs); size_t rsiz = 1 + sizeof(uint32_t) + sizeof(uint32_t); std::vector<BulkRecord>::iterator it = recs->begin(); std::vector<BulkRecord>::iterator itend = recs->end(); while (it != itend) { rsiz += sizeof(uint16_t) + sizeof(uint32_t); rsiz += it->key.size(); ++it; } char* rbuf = new char[rsiz]; char* wp = rbuf; *(wp++) = BMGETBULK; kc::writefixnum(wp, 0, sizeof(uint32_t)); wp += sizeof(uint32_t); kc::writefixnum(wp, recs->size(), sizeof(uint32_t)); wp += sizeof(uint32_t); std::map<std::string, BulkRecord*> map; it = recs->begin(); while (it != itend) { kc::writefixnum(wp, it->dbidx, sizeof(uint16_t)); wp += sizeof(uint16_t); kc::writefixnum(wp, it->key.size(), sizeof(uint32_t)); wp += sizeof(uint32_t); std::memcpy(wp, it->key.data(), it->key.size()); wp += it->key.size(); it->xt = -1; std::string mkey((char*)&it->dbidx, sizeof(uint16_t)); mkey.append(it->key); map[mkey] = &*it; ++it; } Socket* sock = rpc_.reveal_core()->reveal_core(); char stack[RECBUFSIZ]; int64_t rv = -1; bool err = false; if (sock->send(rbuf, rsiz)) { char hbuf[sizeof(uint32_t)]; int32_t c = sock->receive_byte(); if (c == BMGETBULK) { if (sock->receive(hbuf, sizeof(hbuf))) { rv = kc::readfixnum(hbuf, sizeof(uint32_t)); for (int64_t i = 0; !err && i < rv; i++) { char ubuf[sizeof(uint16_t)+sizeof(uint32_t)+sizeof(uint32_t)+sizeof(int64_t)]; if (sock->receive(ubuf, sizeof(ubuf))) { const char* rp = ubuf; uint16_t dbidx = kc::readfixnum(rp, sizeof(uint16_t)); rp += sizeof(uint16_t); size_t ksiz = kc::readfixnum(rp, sizeof(uint32_t)); rp += sizeof(uint32_t); size_t vsiz = kc::readfixnum(rp, sizeof(uint32_t)); rp += sizeof(uint32_t); int64_t xt = kc::readfixnum(rp, sizeof(uint64_t)); if (ksiz <= DATAMAXSIZ && vsiz <= DATAMAXSIZ) { size_t jsiz = ksiz + vsiz; char* jbuf = jsiz > sizeof(stack) ? new char[jsiz] : stack; if (sock->receive(jbuf, jsiz)) { std::string key(jbuf, ksiz); std::string value(jbuf + ksiz, vsiz); std::string mkey((char*)&dbidx, sizeof(uint16_t)); mkey.append(jbuf, ksiz); std::map<std::string, BulkRecord*>::iterator it = map.find(mkey); if (it != map.end()) { BulkRecord* rec = it->second; rec->value = value; rec->xt = xt; } } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; err = true; } if (jbuf != stack) delete[] jbuf; } else { ecode_ = RPCClient::RVEINTERNAL; emsg_ = "internal error"; err = true; } } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; err = true; } } } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; err = true; } } else if (c == BMERROR) { ecode_ = RPCClient::RVEINTERNAL; emsg_ = "internal error"; err = true; } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "receive failed"; err = true; } } else { ecode_ = RPCClient::RVENETWORK; emsg_ = "send failed"; err = true; } delete[] rbuf; return err ? -1 : rv; } /** * Get the expression of the socket. * @return the expression of the socket or an empty string on failure. */ const std::string expression() { _assert_(true); return rpc_.expression(); } /** * Create a cursor object. * @return the return value is the created cursor object. * @note Because the object of the return value is allocated by the constructor, it should be * released with the delete operator when it is no longer in use. */ Cursor* cursor() { _assert_(true); return new Cursor(this); } private: /** * Key with the order. */ struct OrderedKey { int64_t order; std::string key; bool operator <(const OrderedKey& right) const { return order < right.order; } }; /** * Set the parameter of signaling. * @param inmap the string map to contain the input parameters. */ void set_sig_param(std::map<std::string, std::string>& inmap) { if (sigwait_) { inmap["WAIT"] = sigwaitname_; sigwait_ = false; sigwaitname_.clear(); if (sigwaittime_ > 0) kc::strprintf(&inmap["WAITTIME"], "%.6f", sigwaittime_); } if (sigsend_) { inmap["SIGNAL"] = sigsendname_; if (sigsendbrd_) inmap["SIGNALBROAD"] = ""; sigsend_ = false; sigsendname_.clear(); } } /** * Set the parameter of the target database. * @param inmap the string map to contain the input parameters. */ void set_db_param(std::map<std::string, std::string>& inmap) { _assert_(true); if (dbexpr_.empty()) return; inmap["DB"] = dbexpr_; } /** * Set the error status of RPC. * @param rv the return value by the RPC client. * @param message a supplement message. */ void set_error(RPCClient::ReturnValue rv, const char* message) { _assert_(true); ecode_ = rv; emsg_ = message; } /** * Set the error status of RPC. * @param rv the return value by the RPC client. * @param outmap the string map to contain the output parameters. */ void set_rpc_error(RPCClient::ReturnValue rv, const std::map<std::string, std::string>& outmap) { _assert_(true); ecode_ = rv; size_t vsiz; const char* vbuf = strmapget(outmap, "ERROR", &vsiz); if (vbuf) { emsg_ = std::string(vbuf, vsiz); } else { emsg_ = "unexpected error"; } } /** Dummy constructor to forbid the use. */ RemoteDB(const RemoteDB&); /** Dummy Operator to forbid the use. */ RemoteDB& operator =(const RemoteDB&); /** The RPC client. */ RPCClient rpc_; /** The last happened error code. */ RPCClient::ReturnValue ecode_; /** The last happened error messagee. */ std::string emsg_; /** The target database expression. */ std::string dbexpr_; /** The cursor objects. */ CursorList curs_; /** The count of cursor generation. */ int64_t curcnt_; /** The flag of signal waiting. */ bool sigwait_; /** The name of the condition variable of signal waiting. */ std::string sigwaitname_; /** The timeout of signal waiting. */ double sigwaittime_; /** The flag of signal sending. */ bool sigsend_; /** The name of the condition variable of signal sending. */ std::string sigsendname_; /** The flag of broadcast of signal sending. */ bool sigsendbrd_; }; /** * Replication client. */ class ReplicationClient { public: /** * Opening options. */ enum Option { WHITESID = 1 << 0 ///< fetch messages of the specified SID only }; /** * Default constructor. */ explicit ReplicationClient() : sock_(), alive_(false) { _assert_(true); } /** * Open the connection. * @param host the name or the address of the server. If it is an empty string, the local host * is specified. * @param port the port numger of the server. * @param timeout the timeout of each operation in seconds. If it is not more than 0, no * timeout is specified. * @param ts the maximum time stamp of already read logs. * @param sid the server ID number. * @param opts the optional features by bitwise-or: ReplicationClient::WHITESID to fetch * messages whose server ID number is the specified one only. * @return true on success, or false on failure. */ bool open(const std::string& host = "", int32_t port = DEFPORT, double timeout = -1, uint64_t ts = 0, uint16_t sid = 0, uint32_t opts = 0) { _assert_(true); const std::string& thost = host.empty() ? Socket::get_local_host_name() : host; const std::string& addr = Socket::get_host_address(thost); if (addr.empty() || port < 1) return false; std::string expr; kc::strprintf(&expr, "%s:%d", addr.c_str(), port); if (timeout > 0) sock_.set_timeout(timeout); if (!sock_.open(expr)) return false; uint32_t flags = 0; if (opts & WHITESID) flags |= WHITESID; char tbuf[1+sizeof(flags)+sizeof(ts)+sizeof(sid)]; char* wp = tbuf; *(wp++) = RemoteDB::BMREPLICATION; kc::writefixnum(wp, flags, sizeof(flags)); wp += sizeof(flags); kc::writefixnum(wp, ts, sizeof(ts)); wp += sizeof(ts); kc::writefixnum(wp, sid, sizeof(sid)); wp += sizeof(sid); if (!sock_.send(tbuf, sizeof(tbuf)) || sock_.receive_byte() != RemoteDB::BMREPLICATION) { sock_.close(); return false; } alive_ = true; return true; } /** * Close the connection. * @return true on success, or false on failure. */ bool close() { _assert_(true); return sock_.close(false); } /** * Read the next message. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param tsp the pointer to the variable into which the time stamp is assigned. * @return the pointer to the region of the message, or NULL on failure. Because the region * of the return value is allocated with the the new[] operator, it should be released with * the delete[] operator when it is no longer in use. */ char* read(size_t* sp, uint64_t* tsp) { _assert_(sp && tsp); *sp = 0; *tsp = 0; int32_t magic = sock_.receive_byte(); if (magic == RemoteDB::BMREPLICATION) { char hbuf[sizeof(uint64_t)+sizeof(uint32_t)]; if (!sock_.receive(hbuf, sizeof(hbuf))) { alive_ = false; return NULL; } const char* rp = hbuf; uint64_t ts = kc::readfixnum(rp, sizeof(uint64_t)); rp += sizeof(uint64_t); size_t msiz = kc::readfixnum(rp, sizeof(uint32_t)); rp += sizeof(uint32_t); char* mbuf = new char[msiz]; if (!sock_.receive(mbuf, msiz)) { delete[] mbuf; alive_ = false; return NULL; } *sp = msiz; *tsp = ts; return mbuf; } else if (magic == RemoteDB::BMNOP) { char hbuf[sizeof(uint64_t)]; if (!sock_.receive(hbuf, sizeof(hbuf))) { alive_ = false; return NULL; } *tsp = kc::readfixnum(hbuf, sizeof(uint64_t)); char c = RemoteDB::BMREPLICATION; sock_.send(&c, 1); } else { alive_ = false; } return NULL; } /** * Check whether the connection is alive. * @return true if alive, false if not. */ bool alive() { _assert_(true); return alive_; } private: /** The client socket. */ Socket sock_; /** The alive flag. */ bool alive_; }; } // common namespace #endif // duplication check // END OF FILE ���������������������������������������������������������������������������kyototycoon-0.9.56/myscript.h�����������������������������������������������������������������������0000644�0001750�0001750�00000006015�11757471602�015255� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * The scripting extension * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #ifndef _MYSCRIPT_H // duplication check #define _MYSCRIPT_H #include <ktcommon.h> #include <ktutil.h> #include <ktsocket.h> #include <ktthserv.h> #include <kthttp.h> #include <ktrpc.h> #include <ktulog.h> #include <ktshlib.h> #include <kttimeddb.h> #include <ktdbext.h> #include <ktremotedb.h> namespace kc = kyotocabinet; namespace kt = kyototycoon; /** * Script processor. */ class ScriptProcessor { public: /** * Default constructor. */ explicit ScriptProcessor() ; /** * Destructor. */ ~ScriptProcessor(); /** * Set domain-specific resources. * @param thid the ID number of the worker thread. * @param serv the server object. * @param dbs an array of database objects. * @param dbnum the number of elements of the array. * @param dbmap the map binding database names to their indices. * @return the return value of the procedure. */ bool set_resources(int32_t thid, kt::RPCServer* serv, kt::TimedDB* dbs, int32_t dbnum, const std::map<std::string, int32_t>* dbmap); /** * Load a script file. * @param path the path of the sciprt file. * @return true on success, or false on failure. */ bool load(const std::string& path); /** * Clear the internal state. */ void clear(); /** * Call a procedure. * @param name the name of the procecude. * @param inmap a string map which contains the input of the procedure. * @param outmap a string map to contain the input parameters. * @return the return value of the procedure. */ kt::RPCClient::ReturnValue call(const std::string& name, const std::map<std::string, std::string>& inmap, std::map<std::string, std::string>& outmap); private: /** Dummy constructor to forbid the use. */ ScriptProcessor(const ScriptProcessor&); /** Dummy Operator to forbid the use. */ ScriptProcessor& operator =(const ScriptProcessor&); /** Opaque pointer. */ void* opq_; }; #endif // duplication check // END OF FILE �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktplugdb.h�����������������������������������������������������������������������0000644�0001750�0001750�00000004155�11757471602�015222� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * Interface of pluggable database abstraction * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #ifndef _KTPLUGDB_H // duplication check #define _KTPLUGDB_H #include <ktcommon.h> #include <ktutil.h> #include <ktsocket.h> #include <ktthserv.h> #include <kthttp.h> #include <ktrpc.h> #include <ktulog.h> #include <ktshlib.h> #include <kttimeddb.h> #include <ktdbext.h> #include <ktremotedb.h> namespace kyototycoon { // common namespace /** * Interface of pluggable database abstraction. */ class PluggableDB : public kc::BasicDB { public: /** * Destructor. */ virtual ~PluggableDB() { _assert_(true); } }; /** * The name of the initializer function. */ const char* const KTDBINITNAME = "ktdbinit"; extern "C" { /** * Initializer of a database implementation. * @note Each shared library of a pluggable database module must implement a function whose name * is "ktdbinit" and return a new instance of a derived class of the PluggableDB class. The * instance will be deleted implicitly by the caller. */ typedef PluggableDB* (*KTDBINIT)(); } } // common namespace #endif // duplication check // END OF FILE �������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/Doxyfile�������������������������������������������������������������������������0000644�0001750�0001750�00000002575�11503116721�014732� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������# Doxyfile for Kyoto Tycoon # General configuration options PROJECT_NAME = "Kyoto Tycoon" OUTPUT_LANGUAGE = English EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_STATIC = YES REPEAT_BRIEF = YES ALWAYS_DETAILED_SEC = YES SHOW_INCLUDE_FILES = YES VERBATIM_HEADERS = NO JAVADOC_AUTOBRIEF = YES SORT_MEMBER_DOCS = NO INLINE_INFO = NO OPTIMIZE_OUTPUT_FOR_C = NO OPTIMIZE_OUTPUT_JAVA = NO SHOW_USED_FILES = NO QUIET = YES WARNINGS = YES SEARCHENGINE = NO # Configuration options related to the input files INPUT = . FILE_PATTERNS = overview ktcommon.h ktutil.h ktsocket.h ktthserv.h kthttp.h ktrpc.h \ ktulog.h ktshlib.h kttimeddb.h ktdbext.h ktremotedb.h ktplugserv.h ktplugdb.h RECURSIVE = NO # Configuration options related to the alphabetical index ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 3 # Configuration options related to the HTML output GENERATE_HTML = YES HTML_OUTPUT = doc/api HTML_FILE_EXTENSION = .html GENERATE_TREEVIEW = NO TREEVIEW_WIDTH = 250 # Configuration options related to the LaTeX output GENERATE_LATEX = NO LATEX_OUTPUT = latex # Configuration options related to the man page output GENERATE_MAN = NO MAN_OUTPUT = . MAN_EXTENSION = .3 # Configuration options related to the dot tool HAVE_DOT = NO CLASS_GRAPH = NO COLLABORATION_GRAPH = NO INCLUDE_GRAPH = NO INCLUDED_BY_GRAPH = NO GRAPHICAL_HIERARCHY = YES GENERATE_LEGEND = NO DOT_CLEANUP = YES # END OF FILE �����������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/kttimeddb.cc���������������������������������������������������������������������0000644�0001750�0001750�00000035057�11757471602�015520� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * Timed database * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include "kttimeddb.h" #include "myconf.h" namespace kyototycoon { // common namespace /** * Constants for implementation. */ namespace { const char SSMAGICDATA[] = "KTSS\n"; ///< magic data of the snapshot file const uint8_t SSRECMAGIC = 0xcc; ///< magic data for record in the snapshot const int32_t SSIOUNIT = 1 * (1<<20); ///< unit size of the snapshot IO } /** Special pointer for no operation. */ const char* const TimedDB::Visitor::NOP = (const char*)0; /** Special pointer to remove the record. */ const char* const TimedDB::Visitor::REMOVE = (const char*)1; /** * Create a child process. * @return the process ID of the child process to the paremnt process, or 0 for the child * process, or -1 on failure. */ static int64_t fork_impl(); /** * Wait for a process to terminate. * @param pid the process ID of the process. * @param stauts the pointer to a variable to indicate the stauts code. * @param timeout the time to wait in seconds. If it is not more than 0, no timeout is * specified. * @return 0 on success, or -1 on failure, or 1 on timeout. */ static int32_t wait_impl(int64_t pid, int32_t* status, double timeout); /** * Kill a termination signal to a process. * @param pid the process ID of the process. * @param crit true for critical signal, or false for normal termination. * @return true on success, or false on failure. */ static bool kill_impl(int64_t pid, bool crit); /** * Change the process priority. * @param inc the increment of the nice value of the process priority. * @return true on success, or false on failure. */ static bool nice_impl(int32_t inc); /** * The terminate the calling process. * @param the status code. */ static void exit_impl(int32_t status); /** * Dump records atomically into a file. */ bool TimedDB::dump_snapshot_atomic(const std::string& dest, kc::Compressor* zcomp, kc::BasicDB::ProgressChecker* checker) { _assert_(true); bool forkable = false; kc::BasicDB* idb = db_.reveal_inner_db(); if (idb) { const std::type_info& info = typeid(*idb); if (info == typeid(kc::ProtoHashDB) || info == typeid(kc::ProtoTreeDB) || info == typeid(kc::StashDB) || info == typeid(kc::CacheDB) || info == typeid(kc::GrassDB)) forkable = true; } int64_t cpid = -1; if (forkable) { class Forker : public kc::BasicDB::FileProcessor { public: explicit Forker() : cpid_(-1) {} int64_t cpid() { return cpid_; } private: bool process(const std::string& path, int64_t count, int64_t size) { cpid_ = fork_impl(); return true; } int64_t cpid_; }; Forker forker; db_.occupy(true, &forker); cpid = forker.cpid(); }; if (cpid > 0) { int64_t osiz = 0; int32_t cnt = 0; while (true) { cnt++; int32_t status; int32_t rv = wait_impl(cpid, &status, 1); if (rv == 0) return status == 0; if (rv < 0) { kill_impl(cpid, true); wait_impl(cpid, &status, 1); break; } int64_t nsiz = 0; kc::File::Status sbuf; if (kc::File::status(dest, &sbuf)) nsiz = sbuf.size; if (nsiz > osiz) { osiz = nsiz; cnt = 0; } if (cnt >= 10) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::LOGIC, "hanging"); kill_impl(cpid, true); wait_impl(cpid, &status, 0); break; } } return false; } else if (cpid == 0) { nice_impl(1); } kc::File file; if (!file.open(dest, kc::File::OWRITER | kc::File::OCREATE | kc::File::OTRUNCATE)) { if (cpid != 0) db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); return false; } uint32_t chksum = 0; if (zcomp) { size_t zsiz; char* zbuf = zcomp->compress(SSMAGICDATA, sizeof(SSMAGICDATA), &zsiz); if (zbuf) { chksum = kc::hashmurmur(zbuf, zsiz); delete[] zbuf; } } uint64_t ts = UpdateLogger::clock_pure(); uint64_t dbcount = db_.count(); uint64_t dbsize = db_.size(); char head[sizeof(chksum)+sizeof(ts)+sizeof(dbcount)+sizeof(dbsize)]; char* wp = head; kc::writefixnum(wp, chksum, sizeof(chksum)); wp += sizeof(chksum); kc::writefixnum(wp, ts, sizeof(ts)); wp += sizeof(ts); kc::writefixnum(wp, dbcount, sizeof(dbcount)); wp += sizeof(dbcount); kc::writefixnum(wp, dbsize, sizeof(dbsize)); wp += sizeof(dbsize); if (!file.append(SSMAGICDATA, sizeof(SSMAGICDATA)) || !file.append(head, sizeof(head))) { if (cpid != 0) db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); return false; } class Dumper : public kc::BasicDB::Visitor { public: explicit Dumper(kc::File* file, kc::Compressor* zcomp) : file_(file), zcomp_(zcomp), emsg_(NULL), buf_("") {} void flush() { if (buf_.empty()) return; if (zcomp_) { size_t zsiz; char* zbuf = zcomp_->compress(buf_.data(), buf_.size(), &zsiz); if (zbuf) { uint32_t num = kc::hton32(zsiz); if (!file_->append((char*)&num, sizeof(num)) || !file_->append(zbuf, zsiz)) emsg_ = file_->error(); } else { emsg_ = "compression failed"; } delete[] zbuf; } else { if (!file_->append(buf_.data(), buf_.size())) emsg_ = file_->error(); } buf_.clear(); } const char* emsg() { return emsg_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp) { char numbuf[kc::NUMBUFSIZ]; char* wp = numbuf; *(wp++) = SSRECMAGIC; wp += kc::writevarnum(wp, ksiz); wp += kc::writevarnum(wp, vsiz); buf_.append(numbuf, wp - numbuf); buf_.append(kbuf, ksiz); buf_.append(vbuf, vsiz); if ((int32_t)buf_.size() >= SSIOUNIT) flush(); return NOP; } kc::File* file_; kc::Compressor* zcomp_; const char* emsg_; std::string buf_; }; Dumper dumper(&file, zcomp); bool err = false; if (!db_.iterate(&dumper, false, checker)) err = true; dumper.flush(); const char* emsg = dumper.emsg(); if (emsg) { if (cpid != 0) db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, emsg); err = true; } if (!file.close()) { if (cpid != 0) db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); return false; } if (cpid == 0) exit_impl(0); return !err; } /** * Load records atomically from a file. */ bool TimedDB::load_snapshot_atomic(const std::string& src, kc::Compressor* zcomp, kc::BasicDB::ProgressChecker* checker) { _assert_(true); kc::File file; if (!file.open(src, kc::File::OREADER)) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); return false; } uint32_t chksum = 0; if (zcomp) { size_t zsiz; char* zbuf = zcomp->compress(SSMAGICDATA, sizeof(SSMAGICDATA), &zsiz); if (zbuf) { chksum = kc::hashmurmur(zbuf, zsiz); delete[] zbuf; } } char head[sizeof(SSMAGICDATA)+sizeof(chksum)+sizeof(uint64_t)*3]; if (!file.read(0, head, sizeof(head))) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); return false; } const char* rp = head; if (std::memcmp(rp, SSMAGICDATA, sizeof(SSMAGICDATA))) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::BROKEN, "invalid magic data"); return false; } rp += sizeof(SSMAGICDATA); if (kc::readfixnum(rp, sizeof(chksum)) != chksum) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::BROKEN, "invalid check sum"); return false; } if (zcomp) { int64_t off = sizeof(head); int64_t size = file.size() - off; while (size > (int64_t)sizeof(uint32_t)) { uint32_t zsiz; if (!file.read(off, (char*)&zsiz, sizeof(zsiz))) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); return false; } zsiz = kc::ntoh32(zsiz); off += sizeof(uint32_t); size -= sizeof(uint32_t); if (zsiz < 1 || zsiz > size) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, "too short region"); return false; } char* zbuf = new char[zsiz]; if (!file.read(off, zbuf, zsiz)) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); delete[] zbuf; return false; } off += zsiz; size -= zsiz; size_t rsiz; char* rbuf = zcomp->decompress(zbuf, zsiz, &rsiz); if (!rbuf) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, "decompression failed"); delete[] zbuf; return false; } delete[] zbuf; const char* rp = rbuf; while (rsiz >= 3) { if (*(uint8_t*)rp != SSRECMAGIC) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, "invalid magic data"); delete[] rbuf; return false; } rp++; rsiz--; uint64_t ksiz; size_t step = kc::readvarnum(rp, rsiz, &ksiz); rp += step; rsiz -= step; uint64_t vsiz; step = kc::readvarnum(rp, rsiz, &vsiz); rp += step; rsiz -= step; if (!db_.set(rp, ksiz, rp + ksiz, vsiz)) { delete[] rbuf; return false; } rp += ksiz + vsiz; rsiz -= ksiz + vsiz; } delete[] rbuf; } } else { int64_t off = sizeof(head); int64_t size = file.size() - off; char stack[SSIOUNIT]; while (size >= 3) { int64_t rsiz = size; if (rsiz > 1 + (int64_t)sizeof(uint32_t) * 2) rsiz = 1 + sizeof(uint32_t) * 2; if (!file.read(off, stack, rsiz)) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); return false; } if (*(uint8_t*)stack != SSRECMAGIC) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, "invalid magic data"); return false; } off++; size--; char* rp = stack + 1; uint64_t ksiz; size_t step = kc::readvarnum(rp, size, &ksiz); off += step; rp += step; size -= step; uint64_t vsiz; step = kc::readvarnum(rp, size, &vsiz); off += step; rp += step; size -= step; rsiz = ksiz + vsiz; if (size < rsiz) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, "too short region"); return false; } char* rbuf = rsiz > (int64_t)sizeof(stack) ? new char[rsiz] : stack; if (!file.read(off, rbuf, rsiz)) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); if (rbuf != stack) delete[] rbuf; return false; } if (!db_.set(rbuf, ksiz, rbuf + ksiz, vsiz)) { if (rbuf != stack) delete[] rbuf; return false; } if (rbuf != stack) delete[] rbuf; off += rsiz; size -= rsiz; } if (size != 0) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, "too long region"); return false; } } if (!file.close()) { db_.set_error(_KCCODELINE_, kc::BasicDB::Error::SYSTEM, file.error()); return false; } return true; } /** * Get status of an atomic snapshot file. */ bool TimedDB::status_snapshot_atomic(const std::string& src, uint64_t* tsp, int64_t* cntp, int64_t* sizp) { _assert_(true); kc::File file; if (!file.open(src, kc::File::OREADER)) return false; char head[sizeof(SSMAGICDATA)+sizeof(uint32_t)+sizeof(uint64_t)*3]; if (!file.read(0, head, sizeof(head))) return false; if (!file.close()) return false; if (std::memcmp(head, SSMAGICDATA, sizeof(SSMAGICDATA))) return false; const char* rp = head + sizeof(SSMAGICDATA) + sizeof(uint32_t); uint64_t ts = kc::readfixnum(rp, sizeof(ts)); rp += sizeof(ts); int64_t dbcount = kc::readfixnum(rp, sizeof(dbcount)); rp += sizeof(dbcount); int64_t dbsize = kc::readfixnum(rp, sizeof(dbsize)); rp += sizeof(dbcount); if (tsp) *tsp = ts; if (cntp) *cntp = dbcount; if (sizp) *sizp = dbsize; return true; } /** * Create a child process. */ static int64_t fork_impl() { #if defined(_SYS_CYGWIN_) || defined(_SYS_MINGW_) _assert_(true); return -1; #else _assert_(true); return (int64_t)::fork(); #endif } /** * Wait for a process to terminate. */ static int32_t wait_impl(int64_t pid, int32_t* status, double timeout) { #if defined(_SYS_CYGWIN_) || defined(_SYS_MINGW_) _assert_(status); return false; #else _assert_(status); if (timeout > 0) { double etime = kc::time() + timeout; while (true) { int code; ::pid_t rid = ::waitpid(pid, &code, WNOHANG); if (rid > 0) { *status = code; return 0; } if (rid != 0 && errno != EINTR) break; kc::Thread::sleep(0.1); if (kc::time() > etime) return 1; } return -1; } while (true) { int code; ::pid_t rid = ::waitpid(pid, &code, 0); if (rid > 0) { *status = code; return 0; } if (rid != 0 && errno != EINTR) break; } return -1; #endif } /** * Kill a termination signal to a process. */ static bool kill_impl(int64_t pid, bool crit) { #if defined(_SYS_CYGWIN_) || defined(_SYS_MINGW_) return false; #else int signum = crit ? SIGKILL : SIGTERM; return ::kill(pid, signum) == 0; #endif } /** * Change the process priority. */ static bool nice_impl(int32_t inc) { #if defined(_SYS_CYGWIN_) || defined(_SYS_MINGW_) return true; #else return ::nice(inc) != -1; #endif } /** * The terminate the calling process. */ static void exit_impl(int32_t status) { #if defined(_SYS_CYGWIN_) || defined(_SYS_MINGW_) _assert_(true); std::exit(status); #else _assert_(true); ::_exit(status); #endif } } // common namespace // END OF FILE ���������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktplugserv.cc��������������������������������������������������������������������0000644�0001750�0001750�00000002303�11757471602�015743� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * Interface of pluggable server abstraction * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include "ktplugserv.h" #include "myconf.h" namespace kyototycoon { // common namespace // There is no implementation now. } // common namespace // END OF FILE �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktreplmysql.rb�������������������������������������������������������������������0000644�0001750�0001750�00000003267�11757471566�016165� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������require 'dbi' require 'base64' hostname = "localhost" dbname = "kttest" username = "root" password = "" rtspath = "ktreplprint.rts" begin dbh = DBI::connect("dbi:Mysql:#{dbname}:#{hostname}", username, password) sthins = dbh.prepare("INSERT INTO kttest ( k, v, xt ) VALUES ( ?, ?, ? )" + " ON DUPLICATE KEY UPDATE v = ?, xt = ?;") sthrem = dbh.prepare("DELETE FROM kttest WHERE k = ?;") sthclr = dbh.prepare("DELETE FROM kttest;") mode = File::Constants::RDWR | File::Constants::CREAT File::open(rtspath, mode) do |rtsfile| while true begin line = $stdin.readline rescue break end line = line.strip fields = line.split("\t") next if fields.length < 4 rts = fields[0] rsid = fields[1] rdbid = fields[2] rcmd = fields[3] args = [] i = 4 while i < fields.length args.push(fields[i].unpack("m")[0]) i += 1 end case rcmd when "set" if args.length >= 2 key = args[0] value = args[1][5,args[1].length] nums = args[1].unpack("C5") xt = 0 nums.each do |num| xt = (xt << 8) + num end xt = 1 << 32 if xt > (1 << 32) xt = Time::at(xt).strftime("%Y-%m-%d %H:%M:%S") sthins.execute(key, value, xt, value, xt) end when "remove" if args.length >= 1 key = args[0] sthrem.execute(key) end when "clear" sthclr.execute() end rtsfile.pos = 0 rtsfile.printf("%020d\n", rts) end end rescue Exception => e printf("Error: %s\n", e) ensure dbh.disconnect if dbh end exit 0 �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/ktshlib.h������������������������������������������������������������������������0000644�0001750�0001750�00000003676�11757471602�015055� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * Shared library * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #ifndef _KTSHLIB_H // duplication check #define _KTSHLIB_H #include <ktcommon.h> #include <ktutil.h> namespace kyototycoon { // common namespace /** * Shared library. */ class SharedLibrary { public: /** * Default constructor. */ SharedLibrary(); /** * Destructor */ ~SharedLibrary(); /** * Open a shared library. * @param path the path of the shared library file. * @return true on success, or false on failure. */ bool open(const char* path); /** * Close the shared library. * @return true on success, or false on failure. */ bool close(); /** * Get the pointer to a symbol. * @param name the name of the symbol. * @return the pointer to the symbol, or NULL on failure. */ void* symbol(const char* name); private: /** Opaque pointer. */ void* opq_; }; } // common namespace #endif // duplication check // END OF FILE ������������������������������������������������������������������kyototycoon-0.9.56/ChangeLog������������������������������������������������������������������������0000644�0001750�0001750�00000033760�11757464000�015005� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������2012-05-01 FAL Labs <info@fallabs.com> * cmdcommon.h (DBUpdateLogger::set_rsid): supressed a warning. * kttimeddb.h (TimedDB::check): new function. * ktremovedb.h (RemoteDB::check): new function. - Release: 0.9.56 2012-03-27 FAL Labs <info@fallabs.com> * ktserver.c (Worker::do_synchronize): a source of the timestamp was added. - Release: 0.9.55 2012-03-16 FAL Labs <info@fallabs.com> * ktserver.cc (Worker::do_match_similar): new function. * ktremotedb.h (RemoteDB::match_similar): new function. * kttimeddb.h (TimedDB::match_similar): new function. - Release: 0.9.54 2012-01-30 FAL Labs <info@fallabs.com> * ktsocket.cc (setsocketoptions): omit error check because Solaris doesn't implement some options. - Release: 0.9.53 2011-10-30 FAL Labs <info@fallabs.com> * ktserver.c (run): check to the number of databases was added. * ktulog.h (UpdateLogger::Reader::open): a bug related to ID detection was fixed. - Release: 0.9.52 2011-08-17 FAL Labs <info@fallabs.com> * ktulog.h (UpdateLogger::Reader::open): a bug related to unsupported files was fixed. - Release: 0.9.51 2011-07-01 FAL Labs <info@fallabs.com> * ktsocket.cc (waitsocket): the poll mode was added. - Release: 0.9.50 2011-06-28 FAL Labs <info@fallabs.com> * ktplugservmemc.cc (Worker::do_queue_set): the delimiter was changed. - Release: 0.9.49 2011-06-22 FAL Labs <info@fallabs.com> * ktdbext.h (MapReduce::FlushThread): new class. * ktdbext.h (MapReduce::cache_flush): parallel mode was added. - Release: 0.9.48 2011-06-17 FAL Labs <info@fallabs.com> * kcutil.h (maskthreadsignal): new function. * ktthserv.h (TaskQueueImpl::do_start, TaskQueueImpl::do_finish): new functions. * ktplugservmmc.cc (Worker::configure): "tout" and "th" parameters were added. - Release: 0.9.47 2011-06-12 FAL Labs <info@fallabs.com> * ktplugservmmc.cc (Worker::do_queue_get): signal handler was modified. * cmdcommon.h (DEFTHNUM): modified from 8 to 16. - Release: 0.9.46 2011-06-11 FAL Labs <info@fallabs.com> * ktsocket.cc (_init_func): new function. * kttimeddb.cc (TimedDB::Curosr::seize, TimedDB::seize): new functions. * ktremotedb.cc (RemoteDB::Curosr::seize, RemoteDB::seize): new functions. * ktplugservmmc.cc (Worker::do_queue_set, Worker::do_queue_get): new functions. - Release: 0.9.45 2011-06-11 FAL Labs <info@fallabs.com> * ktserver (Worker::process): "WAIT" and "SIGNAL" parameters were added. * ktserver (Worker::do_void): new function. * ktserver (proc): handling condition variable was added. * ktremotedb.h (RemoteDB::set_signal_waiting, RemoteDB::set_signal_sending): new functions. - Release: 0.9.44 2011-05-19 FAL Labs <info@fallabs.com> * kttimeddb.h (TimedDB::scan_parallel): new function. * ktdbext.h (MapReduce::execute): parallel options were added. * ktdbext.h (MapReduce::tune_thread): new function. - Release: 0.9.43 2011-05-17 FAL Labs <info@fallabs.com> * kttimeddb.h (TimedDB::increment): "orig" parameter was added. * ktserver.cc (Worker::do_increment): "orig" parameter was added. - Release: 0.9.42 2011-05-03 FAL Labs <info@fallabs.com> * ktdbext.h (MapReduce::map): MapEmitter was integrated. * ktdbext.h (MapReduce::emit): new function. * ktdbext.h (MapReduce::execute): a bug of wrong handling of empty databases was fixed. - Release: 0.9.41 2011-04-22 FAL Labs <info@fallabs.com> * kttimeddb.h (TimedDB::recover): expiration was edded. - Release: 0.9.40 2011-03-22 FAL Labs <info@fallabs.com> * ktplugservmemc.cc (Worker::do_get): a bug retrieving a useless record was fixed. * myscript.cc (ScriptProcessor::call): a bug related to the nil character was fixed. * myscript.cc (db_get_bulk): a bug related to the nil character was fixed. - Release: 0.9.39 2011-03-06 FAL Labs <info@fallabs.com> * ktplugdbvoid.cc (VoidDB::log): new function. - Release: 0.9.38 2011-02-25 FAL Labs <info@fallabs.com> * kctimeddb.h (TimedDB::occupy): new function. * kttimeddb.h (TimedDB::dump_snapshot_atomic): fork mechanism was modified. * myscript.cc (db_occupy): new function. - Release: 0.9.37 2011-02-23 FAL Labs <info@fallabs.com> - all database classes were refactored to support some old compilers. - Release: 0.9.36 2011-02-21 FAL Labs <info@fallabs.com> * ktdbext.h (MapReduce::execute): adaptive comparator was added. * ktdbext.h (MapReduce::execute_reduce): new function. * ktdbext.h (MapReduce::before, MapReduce::after): new functions. * myscript.cc (SoftVisitor::visit_before, SoftVisitor::visit_after): new functions. - Release: 0.9.35 2011-02-14 FAL Labs <info@fallabs.com> * ktremotemgr.cc (procimport): a bug related to the database expression was fixed. - configuration files were modified for affinity for binary distributions. - all classes were refactored to abolish unnamed namespaces. - Release: 0.9.34 2011-02-08 FAL Labs <info@fallabs.com> * kttimeddb.h (TimedDB::Cursor::get_key): signature was modified. * kttimeddb.h (TimedDB::Cursor::get_pair, TimedDBCursor::get): renamed. * kttimeddb.h (TimedDB::get): signature was modified. - Release: 0.9.33 2011-02-07 FAL Labs <info@fallabs.com> * myscript.cc (kt_hash_murmur, kt_hash_fnv): accuracy was improved. - Release: 0.9.32 2011-02-06 FAL Labs <info@fallabs.com> * ktcommon.h: macros for integer range were removed. - Release: 0.9.31 2011-01-30 FAL Labs <info@fallabs.com> * kttimeddb.h (TimedDB::merge): type of the comarator was changed. * ktdbext.h (MapReduce::execute): type of the comarator was changed. - Release: 0.9.30 2011-01-27 FAL Labs <info@fallabs.com> * myscript.cc (arraydump, arrayload, mapdump, mapload): new functions. * ktremotemgr.cc (runscript): "-arg" option was changed to the normal arguments. - Release: 0.9.29 2011-01-25 FAL Labs <info@fallabs.com> * ktserver (Worker): operation counters were added. * ktserver (Worker::do_rest_put): "x-kt-mode" was added. * ktplugservmemc.cc (Worker): operation counters were added. - Release: 0.9.28 2011-01-21 FAL Labs <info@fallabs.com> * myscript.h (ScriptProcessor::clear): new function. * ktserver.cc (proc): the SIGHUP handler was modified. - Release: 0.9.27 2011-01-20 FAL Labs <info@fallabs.com> * ktpluvservmemc.cc (Worker::process): "gets" is now supported. * kttimeddb.h (TimeDB::status_snapshot_atomic): new function. * kttimedmgr.cc (runbgsinfo, procbgsinfo): new functions. - Release: 0.9.26 2011-01-18 FAL Labs <info@fallabs.com> * ktserver.cc (dosnapshot): new function. * kttimeddb.cc (TimedDB::dump_snapshot_atomic): refactored. - Release: 0.9.25 2011-01-08 FAL Labs <info@fallabs.com> * myscript.cc (set_resources): a bug about database name solver was fixed. * kttimeddb.h (TimedDB::dump_snapshot_atomic): new function. * kttimeddb.cc (fork_impl, wait_impl, nice_impl, exit_impl): new function. - Release: 0.9.24 2011-01-05 FAL Labs <info@fallabs.com> * ktthserv.h (TaskQueueImpl::do_task): keep-alive mechanism was modified. * ktserver.cc (Worker::do_bin_set_bulk): noreply is now supported. * ktplugservmemc (Worker::do_version): new function. * ktplugservmemc (Worker::do_set, do_delete, do_incr): noreply is now supported. - Release: 0.9.23 2011-01-02 FAL Labs <info@fallabs.com> * kctimeddb.h (TimedDB::accept_bulk): new function. * kctimeddb.h (TimedDB::set_bulk, TimedDB::remove_bulk, TimedDB::get_bulk): new functions. * ktplugdbvoid.cc (VoidDB::accept_bulk): new function. * myscript.cc (db_accept_bulk): new function. * myscript.cc (db_set_bulk, db_remove_bulk, db_get_bulk): new functions. - Release: 0.9.22 2010-12-27 FAL Labs <info@fallabs.com> * ktremotedb.h (ReplicationClient::open): WHITESID options was added. * ktserver.cc (Worker::do_bin_replication): WHITESID options was added. - Release: 0.9.21 2010-12-25 FAL Labs <info@fallabs.com> * ktserver.cc (Worker::do_ulog_list, do_ulog_remove): new functions. * ktremotedb.cc (RemoteDB::ulog_list, RemoteDB::ulog_remove): new functions. * ktremotemgr.cc (runslave, procslave): "-uf" and "-ur" options were added. - Release: 0.9.20 2010-12-20 FAL Labs <info@fallabs.com> * ktsocket.h (Poller::wait): EPOLLRDHUP was abolished to support old kernels. * kttimeddb.h (TimedDB::tokenize_update_log): new function. - Release: 0.9.19 2010-12-20 FAL Labs <info@fallabs.com> * ktplugdb.h, ktplugdbvoid.h: new files. - Release: 0.9.18 2010-12-18 FAL Labs <info@fallabs.com> * ktplugservmmc.cc (Worker::do_set, Worker::do_get): "flags" support was added. - Release: 0.9.17 2010-12-11 FAL Labs <info@fallabs.com> * cmdcommon.h (oprintf): new function instead of "iprintf". - Release: 0.9.16 2010-12-05 FAL Labs <info@fallabs.com> * cmdcommon.h (DBUpdateLogger::trigger): transaction mechanism was modified. * ktplugservmmc.cc (Worker::do_incr, Worker::do_decr): new functions. * ktserver.cc (Worker::do_regex_match): a bug related to error handling was fixed. - Release: 0.9.15 2010-12-03 FAL Labs <info@fallabs.com> * ktshlib.h, ktshlib.cc, ktserver.h, ktplugserv.cc: new files. * ktutil.h (printstrvec, strtokenize): new functions. - Release: 0.9.14 2010-12-01 FAL Labs <info@fallabs.com> * ktserver.cc (Worker::do_bin_play_script): new function. * ktremotedb.cc (RemoteDB::play_script_binary): new function; * ktremotemgr.cc (runscript, procscript): "-bin" option was added. - Release: 0.9.13 2010-11-27 FAL Labs <info@fallabs.com> * cmdcommon.h (DBUpdateLogger::parse): invalid use of member variables was cleared. * ktserver.cc (Worker::do_bin_set_bulk, Worker::do_bin_get_bulk): new functions. * kcserver.cc (run, proc): "-uasi" option was added. - Release: 0.9.12 2010-11-27 FAL Labs <info@fallabs.com> * ktsocket.h (Poller::deposit): EPOLLRDHUP was abolished to support old kernels. * ktremotedb.h (RemoteDB::tune_replication): new function. * ktserver.cc (Worker::do_tune_replication): new function. * ktremotemgr.cc (runtunerepl, proctunerepl): new functions. - Release: 0.9.11 2010-11-20 FAL Labs <info@fallabs.com> * ktulog.h (UpdateLogger::write_meta, validate_meta): new functions. - Release: 0.9.10 2010-11-12 FAL Labs <info@fallabs.com> * ktulog.h, ktulog.cc: new files. * ktutiltest.cc (runulog, proculog): new functions. * kttimeddb.h (TimedDB::tune_update_trigger, TimedDB::recover): new functions. * ktserver.cc (main, proc): "-ulog", "-ulim", and "-sid" options were added. * ktserver.cc (Worker::process_binary, Worker::do_replication): new functions. * ktserver.cc (Worker::do_synchronize): the second parameter was added to the command. - Release: 0.9.9 2010-11-12 FAL Labs <info@fallabs.com> * kttimeddb.h (TimedDB::tune_options): abolished. * kttimeddb.h (TimedDB::open): some tuning parameters was added. - Release: 0.9.8 2010-11-09 FAL Labs <info@fallabs.com> * ktserver (main): the default database was changed to the stash database. * myscript.cc (db_open): the default database was changed to the stash database. - Release: 0.9.7 2010-11-04 FAL Labs <info@fallabs.com> * kcdbext.h (MapReduce::execute): the cache algorithm was modified. * myscript.cc (db_mapreduce): tuning parameters were added. - Release: 0.9.6 2010-10-21 FAL Labs <info@fallabs.com> * kttimeddb.h (TimedDB::merge): new function. * kttimeddb.h (TimedDB::expire_records): locking model was modified. * ktdbext.h: new file. - Release: 0.9.5 2010-10-21 FAL Labs <info@fallabs.com> * kttimeddb.h (TimedDB::match_prefix, TimedDB::match_regex): new functions. * kttimeddb.h (TimedDB::jump_back, TimedDB::jump_step): a bug about error code was fixed. * ktremotedb.h (RemoteDB::match_prefix, RemoteDB::match_regex): new functions. * ktserver.cc (do_match_prefix, do_match_regex): new functions. - Release: 0.9.4 2010-10-15 FAL Labs <info@fallabs.com> * kttimedtest.cc (procorder, procqueue, procwicked, proctran): "tune_logger" was added. * kttimedmgr.cc (runcreate, runinform, runset, runget): "-lv" option was added. * ktthserv.h (SESSIDLE, SESSTIMER): new constants. * ktthserv.h (ThreadedServer::Worker::process_timer): new function. * ktserver.cc (Worker::process_idle): efficiency of the auto vacuum was improved. - Release: 0.9.3 2010-10-13 FAL Labs <info@fallabs.com> * ktutil.h (FEATURES): new constant. * ktserver.cc (do_report): "kc_conf_features" and "kt_conf_features" were added. * ktserver.cc (do_play_scriot): the rule related to the status code was modified. * kttimedmgr.cc (runclear, procclear): new functions. - Release: 0.9.2 2010-10-14 FAL Labs <info@fallabs.com> * ktsocket.cc (Poller::Poller, Poller::~Poller, Poller::wait): "kqueue" is now supported. - Release: 0.9.1 2010-10-13 FAL Labs <info@fallabs.com> * ktsocket.cc (Poller::Poller, Poller::~Poller, Poller::wait): "epoll" is now supported. * ktserver.cc (do_report): connection stats data were added. - Release: 0.9.0 2010-10-11 FAL Labs <info@fallabs.com> * ktserver.cc (Worker::process_idle): a bug related to the read only mode was fixed. * myscript.cc (serv_log, kt_pack, kt_unpack, kt_split, kt_codec, kt_bit): new functions. - Release: 0.8.1 2010-10-08 FAL Labs <info@fallabs.com> * kttimeddb.h (TimedDB::vacuum): new function. * ktremotedb.h (RemoteDB::vacuum): new function. * ktserver.cc (Worker::process_idle): new function. * ktserver.cc (Worker::do_play_script): new function. * kttimedmgr.cc (runimport, procimport): "-xt" option was added. * ktremovemgr.cc (runimport, procimport): new functions. * myscript.h, myscript.cc: new files. - Release: 0.8.0 2010-10-05 FAL Labs <info@fallabs.com> * ktserver (Worker::process): the URL convention for RESTful interface was extended. - Release: 0.7.1 2010-10-03 FAL Labs <info@fallabs.com> * ktrpc.h (RPIClient::NOIMPL): new constant. * ktremotedb.h (RemoteDB::bulk_set, RemoteDB::bulk_get): new functions. * ktserver.cc (Worker::do_bulk_set, Worker::do_bulk_get): new functions. * ktserver.cc (Worker::do_synchronize): new function. * ktremotetest (runwicked, procwicked): new functions. - Release: 0.7.0 2010-09-06 FAL Labs <info@fallabs.com> - The initial version. - Release: 0.6.5 ����������������kyototycoon-0.9.56/kthttp.cc������������������������������������������������������������������������0000644�0001750�0001750�00000002244�11757471602�015057� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * HTTP utilities * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include "kthttp.h" #include "myconf.h" namespace kyototycoon { // common namespace // There is no implementation now. } // common namespace // END OF FILE ������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/myconf.h�������������������������������������������������������������������������0000644�0001750�0001750�00000007653�11757471602�014707� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * System-dependent configurations * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #ifndef _MYCONF_H // duplication check #define _MYCONF_H /************************************************************************************************* * system discrimination *************************************************************************************************/ #if defined(__linux__) #define _SYS_LINUX_ #define _KT_OSNAME "Linux" #elif defined(__FreeBSD__) #define _SYS_FREEBSD_ #define _KT_OSNAME "FreeBSD" #elif defined(__NetBSD__) #define _SYS_NETBSD_ #define _KT_OSNAME "NetBSD" #elif defined(__OpenBSD__) #define _SYS_OPENBSD_ #define _KT_OSNAME "OpenBSD" #elif defined(__sun__) || defined(__sun) #define _SYS_SUNOS_ #define _KT_OSNAME "SunOS" #elif defined(__hpux) #define _SYS_HPUX_ #define _KT_OSNAME "HP-UX" #elif defined(__osf) #define _SYS_TRU64_ #define _KT_OSNAME "Tru64" #elif defined(_AIX) #define _SYS_AIX_ #define _KT_OSNAME "AIX" #elif defined(__APPLE__) && defined(__MACH__) #define _SYS_MACOSX_ #define _KT_OSNAME "Mac OS X" #elif defined(_MSC_VER) #define _SYS_MSVC_ #define _KT_OSNAME "Windows (VC++)" #elif defined(_WIN32) #define _SYS_MINGW_ #define _KT_OSNAME "Windows (MinGW)" #elif defined(__CYGWIN__) #define _SYS_CYGWIN_ #define _KT_OSNAME "Windows (Cygwin)" #else #define _SYS_GENERIC_ #define _KT_OSNAME "Generic" #endif #define _KT_VERSION "0.9.56" #define _KT_LIBVER 2 #define _KT_LIBREV 19 #if ! defined(_MYNOEVENT) #if defined(_SYS_LINUX_) #define _KT_EVENT_EPOLL #elif defined(_SYS_FREEBSD_) || defined(_SYS_MACOSX_) #define _KT_EVENT_KQUEUE #endif #endif #if defined(_MYLUA) #define _KT_LUA 1 #else #define _KT_LUA 0 #endif /************************************************************************************************* * general headers *************************************************************************************************/ extern "C" { #include <assert.h> #include <ctype.h> #include <errno.h> #include <float.h> #include <limits.h> #include <locale.h> #include <math.h> #include <setjmp.h> #include <stdarg.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <string.h> #include <time.h> } extern "C" { #include <stdint.h> } #if defined(_SYS_MSVC_) || defined(_SYS_MINGW_) #include <windows.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <direct.h> #include <io.h> #include <process.h> #else extern "C" { #include <unistd.h> #include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <sys/time.h> #include <sys/times.h> #include <sys/wait.h> #include <sys/resource.h> #include <sys/socket.h> #include <sys/un.h> #include <sys/select.h> #include <fcntl.h> #include <poll.h> #include <dirent.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <arpa/inet.h> #include <netdb.h> #include <dlfcn.h> } #endif #endif // duplication check // END OF FILE �������������������������������������������������������������������������������������kyototycoon-0.9.56/kyototycoon.idl������������������������������������������������������������������0000644�0001750�0001750�00000010635�11757471602�016330� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * IDL for bindings of scripting languages * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ /** * namespace of Kyoto Tycoon */ module kyototycoon { //---------------------------------------------------------------- // prediction //---------------------------------------------------------------- interface List; interface Map; interface Error; interface Cursor; interface DB; //---------------------------------------------------------------- // list of strings (substituted by the native mechanism) //---------------------------------------------------------------- interface List { string get(in long index); }; //---------------------------------------------------------------- // map of strings (substituted by the native mechanism) //---------------------------------------------------------------- interface Map { string get(in string key); }; //---------------------------------------------------------------- // error information //---------------------------------------------------------------- interface Error { const long SUCCESS = 0; const long NOIMPL = 1; const long INVALID = 2; const long LOGIC = 3; const long INTERNAL = 4; const long NETWORK = 5; const long EMISC = 15; long code(); string name(); string message(); }; //---------------------------------------------------------------- // cursor //---------------------------------------------------------------- interface Cursor { boolean set_value(in string value, in long long xt, in boolean step); boolean remove(); string get_key(in boolean step); string get_value(in boolean step); boolean jump(); boolean jump_(in string key); boolean jump_back(); boolean jump_back_(in string key); boolean step(); boolean step_back(); DB db(); Error error(); }; //---------------------------------------------------------------- // common database operations //---------------------------------------------------------------- interface DB { Error error(); boolean open(in string host, in long port, in double timeout); boolean close(); Map report(); Map play_script(in string name, in Map args); boolean tune_replication(in string host, in long port, in long long ts, in double iv); List ulog_list(); boolean ulog_remove(in long long ts); Map status(); boolean clear(); long long count(); long long size(); boolean set(in string key, in string value, in long long xt); boolean add(in string key, in string value, in long long xt); boolean replace(in string key, in string value, in long long xt); boolean append(in string key, in string value, in long long xt); long long increment(in string key, in long long num, in long long orig, in long long xt); double increment_double(in string key, in double num, in double orig, in long long xt); boolean cas(in string key, in string oval, in string nval, in long long xt); boolean remove(in string key); string get(in string key); string seize(in string key); long long set_bulk(in Map recs, in long long xt); long long remove_bulk(in List keys); Map get_bulk(in List keys); boolean vacuum(in long long steps); List match_prefix(in string prefix, in long long max); List match_regex(in string regex, in long long max); List match_similar(in string origin, in long long range, in boolean utf, in long long max); void set_target(in string expr); string expression(); Cursor cursor(); }; }; /* END OF FILE */ ���������������������������������������������������������������������������������������������������kyototycoon-0.9.56/kttimedmgr.cc��������������������������������������������������������������������0000644�0001750�0001750�00000174231�11757471602�015716� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * The command line utility of the timed database * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #include <kttimeddb.h> #include "cmdcommon.h" // global variables const char* g_progname; // program name // function prototypes int main(int argc, char** argv); static void usage(); static void dberrprint(kt::TimedDB* db, const char* info); static int32_t runcreate(int argc, char** argv); static int32_t runinform(int argc, char** argv); static int32_t runset(int argc, char** argv); static int32_t runremove(int argc, char** argv); static int32_t runget(int argc, char** argv); static int32_t runlist(int argc, char** argv); static int32_t runclear(int argc, char** argv); static int32_t runimport(int argc, char** argv); static int32_t runcopy(int argc, char** argv); static int32_t rundump(int argc, char** argv); static int32_t runload(int argc, char** argv); static int32_t runvacuum(int argc, char** argv); static int32_t runrecover(int argc, char** argv); static int32_t runmerge(int argc, char** argv); static int32_t runcheck(int argc, char** argv); static int32_t runbgsinform(int argc, char** argv); static int32_t proccreate(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid); static int32_t procinform(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool st); static int32_t procset(const char* path, const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, int32_t mode, int64_t xt); static int32_t procremove(const char* path, const char* kbuf, size_t ksiz, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid); static int32_t procget(const char* path, const char* kbuf, size_t ksiz, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool rm, bool px, bool pt, bool pz); static int32_t proclist(const char* path, const char*kbuf, size_t ksiz, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool des, int64_t max, bool rm, bool pv, bool px, bool pt); static int32_t procclear(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid); static int32_t procimport(const char* path, const char* file, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool sx, int64_t xt); static int32_t proccopy(const char* path, const char* file, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid); static int32_t procdump(const char* path, const char* file, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid); static int32_t procload(const char* path, const char* file, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid); static int32_t procvacuum(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid); static int32_t procrecover(const char* path, const char* dir, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, uint64_t ts); static int32_t procmerge(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, kt::TimedDB::MergeMode mode, const std::vector<std::string>& srcpaths); static int32_t proccheck(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid); static int32_t procbgsinform(const char* bgspath); // main routine int main(int argc, char** argv) { g_progname = argv[0]; kc::setstdiobin(); if (argc < 2) usage(); int32_t rv = 0; if (!std::strcmp(argv[1], "create")) { rv = runcreate(argc, argv); } else if (!std::strcmp(argv[1], "inform")) { rv = runinform(argc, argv); } else if (!std::strcmp(argv[1], "set")) { rv = runset(argc, argv); } else if (!std::strcmp(argv[1], "remove")) { rv = runremove(argc, argv); } else if (!std::strcmp(argv[1], "get")) { rv = runget(argc, argv); } else if (!std::strcmp(argv[1], "list")) { rv = runlist(argc, argv); } else if (!std::strcmp(argv[1], "clear")) { rv = runclear(argc, argv); } else if (!std::strcmp(argv[1], "import")) { rv = runimport(argc, argv); } else if (!std::strcmp(argv[1], "copy")) { rv = runcopy(argc, argv); } else if (!std::strcmp(argv[1], "dump")) { rv = rundump(argc, argv); } else if (!std::strcmp(argv[1], "load")) { rv = runload(argc, argv); } else if (!std::strcmp(argv[1], "vacuum")) { rv = runvacuum(argc, argv); } else if (!std::strcmp(argv[1], "recover")) { rv = runrecover(argc, argv); } else if (!std::strcmp(argv[1], "merge")) { rv = runmerge(argc, argv); } else if (!std::strcmp(argv[1], "check")) { rv = runcheck(argc, argv); } else if (!std::strcmp(argv[1], "bgsinform")) { rv = runbgsinform(argc, argv); } else if (!std::strcmp(argv[1], "version") || !std::strcmp(argv[1], "--version")) { printversion(); } else { usage(); } return rv; } // print the usage and exit static void usage() { eprintf("%s: the command line utility of the timed database of Kyoto Tycoon\n", g_progname); eprintf("\n"); eprintf("usage:\n"); eprintf(" %s create [-otr] [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " path\n", g_progname); eprintf(" %s inform [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " [-st] path\n", g_progname); eprintf(" %s set [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " [-add|-rep|-app|-inci|-incd] [-sx] [-xt num] path key value\n", g_progname); eprintf(" %s remove [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " [-sx] path key\n", g_progname); eprintf(" %s get [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " [-rm] [-sx] [-px] [-pt] [-pz] path key\n", g_progname); eprintf(" %s list [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " [-des] [-max num] [-rm] [-sx] [-pv] [-px] [-pt] path [key]\n", g_progname); eprintf(" %s clear [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " path\n", g_progname); eprintf(" %s import [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " [-sx] [-xt num] path [file]\n", g_progname); eprintf(" %s copy [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " path file\n", g_progname); eprintf(" %s dump [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " path [file]\n", g_progname); eprintf(" %s load [-otr] [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " path [file]\n", g_progname); eprintf(" %s vacuum [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " path\n", g_progname); eprintf(" %s recover [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " [-ts num] [-sid num] [-dbid num] [-dbid num] path dir\n", g_progname); eprintf(" %s merge [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " [-add|-rep|-app] path src...\n", g_progname); eprintf(" %s check [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " path\n", g_progname); eprintf(" %s bgsinform file\n", g_progname); eprintf("\n"); std::exit(1); } // print error message of database static void dberrprint(kt::TimedDB* db, const char* info) { const kc::BasicDB::Error& err = db->error(); eprintf("%s: %s: %s: %d: %s: %s\n", g_progname, info, db->path().c_str(), err.code(), err.name(), err.message()); } // parse arguments of create command static int32_t runcreate(int argc, char** argv) { bool argbrk = false; const char* path = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-otr")) { oflags |= kc::BasicDB::OTRUNCATE; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = proccreate(path, oflags, ulogpath, ulim, sid, dbid); return rv; } // parse arguments of inform command static int32_t runinform(int argc, char** argv) { bool argbrk = false; const char* path = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool st = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-st")) { st = true; } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = procinform(path, oflags, ulogpath, ulim, sid, dbid, st); return rv; } // parse arguments of set command static int32_t runset(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* kstr = NULL; const char* vstr = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; int32_t mode = 0; bool sx = false; int64_t xt = kc::INT64MAX; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-add")) { mode = 'a'; } else if (!std::strcmp(argv[i], "-rep")) { mode = 'r'; } else if (!std::strcmp(argv[i], "-app")) { mode = 'c'; } else if (!std::strcmp(argv[i], "-inci")) { mode = 'i'; } else if (!std::strcmp(argv[i], "-incd")) { mode = 'd'; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-xt")) { if (++i >= argc) usage(); xt = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!kstr) { kstr = argv[i]; } else if (!vstr) { vstr = argv[i]; } else { usage(); } } if (!path || !kstr || !vstr) usage(); char* kbuf; size_t ksiz; char* vbuf; size_t vsiz; if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; vbuf = kc::hexdecode(vstr, &vsiz); vstr = vbuf; } else { ksiz = std::strlen(kstr); kbuf = NULL; vsiz = std::strlen(vstr); vbuf = NULL; } int32_t rv = procset(path, kstr, ksiz, vstr, vsiz, oflags, ulogpath, ulim, sid, dbid, mode, xt); delete[] kbuf; delete[] vbuf; return rv; } // parse arguments of remove command static int32_t runremove(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* kstr = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool sx = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!kstr) { kstr = argv[i]; } else { usage(); } } if (!path || !kstr) usage(); char* kbuf; size_t ksiz; if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; } else { ksiz = std::strlen(kstr); kbuf = NULL; } int32_t rv = procremove(path, kstr, ksiz, oflags, ulogpath, ulim, sid, dbid); delete[] kbuf; return rv; } // parse arguments of get command static int32_t runget(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* kstr = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool rm = false; bool sx = false; bool px = false; bool pt = false; bool pz = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-rm")) { rm = true; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-px")) { px = true; } else if (!std::strcmp(argv[i], "-pt")) { pt = true; } else if (!std::strcmp(argv[i], "-pz")) { pz = true; } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!kstr) { kstr = argv[i]; } else { usage(); } } if (!path || !kstr) usage(); char* kbuf; size_t ksiz; if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; } else { ksiz = std::strlen(kstr); kbuf = NULL; } int32_t rv = procget(path, kstr, ksiz, oflags, ulogpath, ulim, sid, dbid, rm, px, pt, pz); delete[] kbuf; return rv; } // parse arguments of list command static int32_t runlist(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* kstr = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool des = false; int64_t max = -1; bool rm = false; bool sx = false; bool pv = false; bool px = false; bool pt = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-des")) { des = true; } else if (!std::strcmp(argv[i], "-max")) { if (++i >= argc) usage(); max = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-rm")) { rm = true; } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-pv")) { pv = true; } else if (!std::strcmp(argv[i], "-px")) { px = true; } else if (!std::strcmp(argv[i], "-pt")) { pt = true; } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!kstr) { kstr = argv[i]; } else { usage(); } } if (!path) usage(); char* kbuf = NULL; size_t ksiz = 0; if (kstr) { if (sx) { kbuf = kc::hexdecode(kstr, &ksiz); kstr = kbuf; } else { ksiz = std::strlen(kstr); kbuf = new char[ksiz+1]; std::memcpy(kbuf, kstr, ksiz); kbuf[ksiz] = '\0'; } } int32_t rv = proclist(path, kbuf, ksiz, oflags, ulogpath, ulim, sid, dbid, des, max, rm, pv, px, pt); delete[] kbuf; return rv; } // parse arguments of clear command static int32_t runclear(int argc, char** argv) { bool argbrk = false; const char* path = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = procclear(path, oflags, ulogpath, ulim, sid, dbid); return rv; } // parse arguments of import command static int32_t runimport(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* file = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool sx = false; int64_t xt = kc::INT64MAX; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sx")) { sx = true; } else if (!std::strcmp(argv[i], "-xt")) { if (++i >= argc) usage(); xt = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!file) { file = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = procimport(path, file, oflags, ulogpath, ulim, sid, dbid, sx, xt); return rv; } // parse arguments of copy command static int32_t runcopy(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* file = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!file) { file = argv[i]; } else { usage(); } } if (!path || !file) usage(); int32_t rv = proccopy(path, file, oflags, ulogpath, ulim, sid, dbid); return rv; } // parse arguments of dump command static int32_t rundump(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* file = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!file) { file = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = procdump(path, file, oflags, ulogpath, ulim, sid, dbid); return rv; } // parse arguments of load command static int32_t runload(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* file = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-otr")) { oflags |= kc::BasicDB::OTRUNCATE; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!file) { file = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = procload(path, file, oflags, ulogpath, ulim, sid, dbid); return rv; } // parse arguments of vacuum command static int32_t runvacuum(int argc, char** argv) { bool argbrk = false; const char* path = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = procvacuum(path, oflags, ulogpath, ulim, sid, dbid); return rv; } // parse arguments of recover command static int32_t runrecover(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* dir = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; uint64_t ts = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-ts")) { if (++i >= argc) usage(); if (!std::strcmp(argv[i], "now") || !std::strcmp(argv[i], "-")) { ts = kt::UpdateLogger::clock_pure(); } else { ts = kc::atoix(argv[i]); } } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!dir) { dir = argv[i]; } else { usage(); } } if (!path || !dir) usage(); int32_t rv = procrecover(path, dir, oflags, ulogpath, ulim, sid, dbid, ts); return rv; } // parse arguments of merge command static int32_t runmerge(int argc, char** argv) { bool argbrk = false; const char* path = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; kt::TimedDB::MergeMode mode = kt::TimedDB::MSET; std::vector<std::string> srcpaths; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-add")) { mode = kt::TimedDB::MADD; } else if (!std::strcmp(argv[i], "-rep")) { mode = kt::TimedDB::MREPLACE; } else if (!std::strcmp(argv[i], "-app")) { mode = kt::TimedDB::MAPPEND; } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else { srcpaths.push_back(argv[i]); } } if (!path && srcpaths.size() < 1) usage(); int32_t rv = procmerge(path, oflags, ulogpath, ulim, sid, dbid, mode, srcpaths); return rv; } // parse arguments of check command static int32_t runcheck(int argc, char** argv) { bool argbrk = false; const char* path = NULL; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = proccheck(path, oflags, ulogpath, ulim, sid, dbid); return rv; } // parse arguments of bgsinform command static int32_t runbgsinform(int argc, char** argv) { bool argbrk = false; const char* bgspath = NULL; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else { usage(); } } else if (!bgspath) { argbrk = true; bgspath = argv[i]; } else { usage(); } } if (!bgspath) usage(); int32_t rv = procbgsinform(bgspath); return rv; } // perform create command static int32_t proccreate(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OWRITER | kc::BasicDB::OCREATE | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform inform command static int32_t procinform(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool st) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OREADER | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; if (st) { std::map<std::string, std::string> status; if (db.status(&status)) { std::map<std::string, std::string>::iterator it = status.begin(); std::map<std::string, std::string>::iterator itend = status.end(); while (it != itend) { oprintf("%s: %s\n", it->first.c_str(), it->second.c_str()); ++it; } } else { dberrprint(&db, "DB::status failed"); err = true; } } else { oprintf("count: %lld\n", (long long)db.count()); oprintf("size: %lld\n", (long long)db.size()); } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform set command static int32_t procset(const char* path, const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, int32_t mode, int64_t xt) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OWRITER | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; switch (mode) { default: { if (!db.set(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(&db, "DB::set failed"); err = true; } break; } case 'a': { if (!db.add(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(&db, "DB::add failed"); err = true; } break; } case 'r': { if (!db.replace(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(&db, "DB::replace failed"); err = true; } break; } case 'c': { if (!db.append(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(&db, "DB::append failed"); err = true; } break; } case 'i': { int64_t onum = db.increment(kbuf, ksiz, kc::atoi(vbuf), 0, xt); if (onum == kc::INT64MIN) { dberrprint(&db, "DB::increment failed"); err = true; } else { oprintf("%lld\n", (long long)onum); } break; } case 'd': { double onum = db.increment_double(kbuf, ksiz, kc::atof(vbuf), 0, xt); if (kc::chknan(onum)) { dberrprint(&db, "DB::increment_double failed"); err = true; } else { oprintf("%f\n", onum); } break; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform remove command static int32_t procremove(const char* path, const char* kbuf, size_t ksiz, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OWRITER | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; if (!db.remove(kbuf, ksiz)) { dberrprint(&db, "DB::remove failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform get command static int32_t procget(const char* path, const char* kbuf, size_t ksiz, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool rm, bool px, bool pt, bool pz) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } uint32_t omode = rm ? kc::BasicDB::OWRITER : kc::BasicDB::OREADER; if (!db.open(path, omode | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; char* vbuf; size_t vsiz; int64_t xt; if (rm) { vbuf = db.seize(kbuf, ksiz, &vsiz, &xt); } else { vbuf = db.get(kbuf, ksiz, &vsiz, &xt); } if (vbuf) { printdata(vbuf, vsiz, px); if (pt) oprintf("\t%lld", (long long)xt); if (!pz) oprintf("\n"); delete[] vbuf; } else { dberrprint(&db, "DB::get failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform list command static int32_t proclist(const char* path, const char*kbuf, size_t ksiz, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool des, int64_t max, bool rm, bool pv, bool px, bool pt) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } uint32_t omode = rm ? kc::BasicDB::OWRITER : kc::BasicDB::OREADER; if (!db.open(path, omode | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; class VisitorImpl : public kt::TimedDB::Visitor { public: explicit VisitorImpl(bool rm, bool pv, bool px, bool pt) : rm_(rm), pv_(pv), px_(px), pt_(pt) {} private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { printdata(kbuf, ksiz, px_); if (pv_) { oprintf("\t"); printdata(vbuf, vsiz, px_); } if (pt_) oprintf("\t%lld", (long long)*xtp); oprintf("\n"); return rm_ ? REMOVE : NOP; } bool rm_; bool pv_; bool px_; bool pt_; } visitor(rm, pv, px, pt); if (kbuf || des || max >= 0) { if (max < 0) max = kc::INT64MAX; kt::TimedDB::Cursor cur(&db); if (des) { if (kbuf) { if (!cur.jump_back(kbuf, ksiz) && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "Cursor::jump failed"); err = true; } } else { if (!cur.jump_back() && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "Cursor::jump failed"); err = true; } } while (!err && max > 0) { if (!cur.accept(&visitor, rm, true)) { if (db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "Cursor::accept failed"); err = true; } break; } max--; } } else { if (kbuf) { if (!cur.jump(kbuf, ksiz) && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "Cursor::jump failed"); err = true; } } else { if (!cur.jump() && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "Cursor::jump failed"); err = true; } } while (!err && max > 0) { if (!cur.accept(&visitor, rm, true)) { if (db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "Cursor::accept failed"); err = true; } break; } max--; } } } else { if (!db.iterate(&visitor, rm)) { dberrprint(&db, "DB::iterate failed"); err = true; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform clear command static int32_t procclear(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OWRITER | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; if (!db.clear()) { dberrprint(&db, "DB::clear failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform import command static int32_t procimport(const char* path, const char* file, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool sx, int64_t xt) { std::istream *is = &std::cin; std::ifstream ifs; if (file) { ifs.open(file, std::ios_base::in | std::ios_base::binary); if (!ifs) { eprintf("%s: %s: open error\n", g_progname, file); return 1; } is = &ifs; } kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OWRITER | kc::BasicDB::OCREATE | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; int64_t cnt = 0; std::string line; std::vector<std::string> fields; while (!err && mygetline(is, &line)) { cnt++; kc::strsplit(line, '\t', &fields); if (sx) { std::vector<std::string>::iterator it = fields.begin(); std::vector<std::string>::iterator itend = fields.end(); while (it != itend) { size_t esiz; char* ebuf = kc::hexdecode(it->c_str(), &esiz); it->clear(); it->append(ebuf, esiz); delete[] ebuf; ++it; } } switch (fields.size()) { case 2: { if (!db.set(fields[0], fields[1], xt)) { dberrprint(&db, "DB::set failed"); err = true; } break; } case 1: { if (!db.remove(fields[0]) && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "DB::remove failed"); err = true; } break; } } oputchar('.'); if (cnt % 50 == 0) oprintf(" (%d)\n", cnt); } if (cnt % 50 > 0) oprintf(" (%d)\n", cnt); if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform copy command static int32_t proccopy(const char* path, const char* file, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OREADER | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; DotChecker checker(&std::cout, -100); if (!db.copy(file, &checker)) { dberrprint(&db, "DB::copy failed"); err = true; } oprintf(" (end)\n"); if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } if (!err) oprintf("%lld blocks were merged successfully\n", (long long)checker.count()); return err ? 1 : 0; } // perform dump command static int32_t procdump(const char* path, const char* file, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OREADER | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; if (file) { DotChecker checker(&std::cout, 1000); if (!db.dump_snapshot(file, &checker)) { dberrprint(&db, "DB::dump_snapshot"); err = true; } oprintf(" (end)\n"); if (!err) oprintf("%lld records were dumped successfully\n", (long long)checker.count()); } else { if (!db.dump_snapshot(&std::cout)) { dberrprint(&db, "DB::dump_snapshot"); err = true; } } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform load command static int32_t procload(const char* path, const char* file, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OWRITER | kc::BasicDB::OCREATE | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; if (file) { DotChecker checker(&std::cout, -1000); if (!db.load_snapshot(file, &checker)) { dberrprint(&db, "DB::load_snapshot"); err = true; } oprintf(" (end)\n"); if (!err) oprintf("%lld records were loaded successfully\n", (long long)checker.count()); } else { DotChecker checker(&std::cout, -1000); if (!db.load_snapshot(&std::cin)) { dberrprint(&db, "DB::load_snapshot"); err = true; } oprintf(" (end)\n"); if (!err) oprintf("%lld records were loaded successfully\n", (long long)checker.count()); } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform vacuum command static int32_t procvacuum(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OWRITER | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; if (!db.vacuum()) { dberrprint(&db, "DB::vacuum failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform recover command static int32_t procrecover(const char* path, const char* dir, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, uint64_t ts) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OWRITER | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } kt::UpdateLogger ulogsrc; if (!ulogsrc.open(dir, kc::INT64MIN)) { dberrprint(&db, "UpdateLogger::open failed"); return 1; } bool err = false; kt::UpdateLogger::Reader ulrd; if (!ulrd.open(&ulogsrc, ts)) { dberrprint(&db, "UpdateLogger::Reader::open failed"); err = true; } int64_t cnt = 0; while (true) { size_t msiz; uint64_t mts; char* mbuf = ulrd.read(&msiz, &mts); if (mbuf) { size_t rsiz; uint16_t rsid, rdbid; const char* rbuf = DBUpdateLogger::parse(mbuf, msiz, &rsiz, &rsid, &rdbid); if (rbuf) { ulogdb.set_rsid(rsid); if (sid != rsid && dbid == rdbid && !db.recover(rbuf, rsiz)) { dberrprint(&db, "DB::recover failed"); err = true; } ulogdb.clear_rsid(); } else { dberrprint(&db, "DBUpdateLogger::parse failed"); err = true; } delete[] mbuf; } else { break; } cnt++; oputchar('.'); if (cnt % 50 == 0) oprintf(" (%d)\n", cnt); } if (cnt % 50 > 0) oprintf(" (%d)\n", cnt); if (!ulrd.close()) { dberrprint(&db, "DBUpdateLogger::Reader::close failed"); err = true; } if (!ulogsrc.close()) { dberrprint(&db, "DBUpdateLogger::close failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } return err ? 1 : 0; } // perform merge command static int32_t procmerge(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, kt::TimedDB::MergeMode mode, const std::vector<std::string>& srcpaths) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OWRITER | kc::BasicDB::OCREATE | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; kt::TimedDB** srcary = new kt::TimedDB*[srcpaths.size()]; size_t srcnum = 0; std::vector<std::string>::const_iterator it = srcpaths.begin(); std::vector<std::string>::const_iterator itend = srcpaths.end(); while (it != itend) { const std::string srcpath = *it; kt::TimedDB* srcdb = new kt::TimedDB; if (srcdb->open(srcpath, kc::BasicDB::OREADER | oflags)) { srcary[srcnum++] = srcdb; } else { dberrprint(srcdb, "DB::open failed"); err = true; delete srcdb; } ++it; } DotChecker checker(&std::cout, 1000); if (!db.merge(srcary, srcnum, mode, &checker)) { dberrprint(&db, "DB::merge failed"); err = true; } oprintf(" (end)\n"); for (size_t i = 0; i < srcnum; i++) { kt::TimedDB* srcdb = srcary[i]; if (!srcdb->close()) { dberrprint(srcdb, "DB::close failed"); err = true; } delete srcdb; } delete[] srcary; if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } if (!err) oprintf("%lld records were merged successfully\n", (long long)checker.count()); return err ? 1 : 0; } // perform check command static int32_t proccheck(const char* path, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid) { kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cerr)); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, "DB::tune_update_trigger failed"); return 1; } } else { dberrprint(&db, "UpdateLogger::open failed"); return 1; } } if (!db.open(path, kc::BasicDB::OREADER | oflags)) { dberrprint(&db, "DB::open failed"); return 1; } bool err = false; kt::TimedDB::Cursor cur(&db); if (!cur.jump() && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "DB::jump failed"); err = true; } int64_t cnt = 0; while (!err) { size_t ksiz; const char* vbuf; size_t vsiz; char* kbuf = cur.get(&ksiz, &vbuf, &vsiz); if (kbuf) { cnt++; size_t rsiz; char* rbuf = db.get(kbuf, ksiz, &rsiz); if (rbuf) { if (rsiz != vsiz || std::memcmp(rbuf, vbuf, rsiz)) { dberrprint(&db, "DB::get failed"); err = true; } delete[] rbuf; } else { dberrprint(&db, "DB::get failed"); err = true; } delete[] kbuf; if (cnt % 1000 == 0) { oputchar('.'); if (cnt % 50000 == 0) oprintf(" (%lld)\n", (long long)cnt); } } else { if (db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "Cursor::get failed xx"); err = true; } break; } if (!cur.step() && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, "Cursor::step failed"); err = true; } } oprintf(" (end)\n"); kc::File::Status sbuf; if (kc::File::status(path, &sbuf)) { if (!sbuf.isdir && db.size() != sbuf.size) { dberrprint(&db, "DB::size failed"); err = true; } } else { dberrprint(&db, "File::status failed"); err = true; } if (!db.close()) { dberrprint(&db, "DB::close failed"); err = true; } if (ulogpath) { if (!ulog.close()) { dberrprint(&db, "UpdateLogger::close failed"); err = true; } } if (!err) oprintf("%lld records were checked successfully\n", (long long)cnt); return err ? 1 : 0; } // perform bgsinform command static int32_t procbgsinform(const char* bgspath) { kc::File::Status sbuf; if (!kc::File::status(bgspath, &sbuf)) { eprintf("%s: %s: no such file or directory\n", g_progname, bgspath); return 1; } if (sbuf.isdir) { kc::DirStream dir; if (dir.open(bgspath)) { std::string name; while (dir.read(&name)) { const char* nstr = name.c_str(); const char* pv = std::strrchr(nstr, kc::File::EXTCHR); if (*nstr >= '0' && *nstr <= '9' && pv && !kc::stricmp(pv + 1, BGSPATHEXT)) { std::string path; kc::strprintf(&path, "%s%c%s", bgspath, kc::File::PATHCHR, nstr); uint64_t ssts; int64_t sscount, sssize; if (kt::TimedDB::status_snapshot_atomic(path, &ssts, &sscount, &sssize)) oprintf("%d\t%llu\t%lld\t%lld\n", (int)kc::atoi(nstr), (unsigned long long)ssts, (long long)sscount, (long long)sssize); } } dir.close(); } else { eprintf("%s: %s: could not open the directory\n", g_progname, bgspath); return 1; } } else { uint64_t ssts; int64_t sscount, sssize; if (kt::TimedDB::status_snapshot_atomic(bgspath, &ssts, &sscount, &sssize)) { const char* nstr = std::strrchr(bgspath, kc::File::PATHCHR); if (!nstr) nstr = bgspath; oprintf("%d\t%llu\t%lld\t%lld\n", (int)kc::atoi(nstr), (unsigned long long)ssts, (long long)sscount, (long long)sssize); } else { eprintf("%s: %s: could not open the file\n", g_progname, bgspath); return 1; } } return 0; } // END OF FILE �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/man/�����������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11757471566�014014� 5����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/man/kttimedtest.1����������������������������������������������������������������0000644�0001750�0001750�00000010771�11757471566�016445� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH "KTTIMEDTEST" 1 "2012-05-25" "Man Page" "Kyoto Tycoon" .SH NAME kttimedtest \- command line interface to test the timed database .SH DESCRIPTION .PP The command `\fBkttimedtest\fR' is a utility for facility test and performance test of the timed database. This command is used in the following format. `\fIpath\fR' specifies the path of a database file. `\fIrnum\fR' specifies the number of iterations. .PP .RS .br \fBkttimedtest order \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-rnd\fR]\fB \fR[\fB\-set\fR|\fB\-get\fR|\fB\-getw\fR|\fB\-rem\fR|\fB\-etc\fR]\fB \fR[\fB\-tran\fR]\fB \fR[\fB\-oat\fR|\fB\-onl\fR|\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-lv\fR]\fB \fIpath\fB \fIrnum\fB\fR .RS Performs in\-order tests. .RE .br \fBkttimedtest queue \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-it \fInum\fB\fR]\fB \fR[\fB\-rnd\fR]\fB \fR[\fB\-oat\fR|\fB\-onl\fR|\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-lv\fR]\fB \fIpath\fB \fIrnum\fB\fR .RS Performs queuing operations. .RE .br \fBkttimedtest wicked \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-it \fInum\fB\fR]\fB \fR[\fB\-oat\fR|\fB\-onl\fR|\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-lv\fR]\fB \fIpath\fB \fIrnum\fB\fR .RS Performs mixed operations selected at random. .RE .br \fBkttimedtest tran \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-it \fInum\fB\fR]\fB \fR[\fB\-hard\fR]\fB \fR[\fB\-oat\fR|\fB\-onl\fR|\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-lv\fR]\fB \fIpath\fB \fIrnum\fB\fR .RS Performs test of transaction. .RE .br \fBkctimedtest mapred \fR[\fB\-rnd\fR]\fB \fR[\fB\-ru\fR]\fB \fR[\fB\-oat\fR|\fB\-onl\fR|\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-lv\fR]\fB \fR[\fB\-tmp \fIstr\fB\fR]\fB \fR[\fB\-dbnum \fInum\fB\fR]\fB \fR[\fB\-clim \fInum\fB\fR]\fB \fR[\fB\-cbnum \fInum\fB\fR]\fB \fR[\fB\-xnl\fR]\fB \fR[\fB\-xpm\fR]\fB \fR[\fB\-xpr\fR]\fB \fR[\fB\-xpf\fR]\fB \fR[\fB\-xnc\fR]\fB \fIpath\fB \fIrnum\fB\fR .RS Performs MapReduce operations. .RE .br \fBkttimedtest misc \fIpath\fB\fR .RS Performs miscellaneous tests. .RE .RE .PP Options feature the following. .PP .RS \fB\-th \fInum\fR\fR : specifies the number of worker threads. .br \fB\-rnd\fR : performs random test. .br \fB\-set\fR : performs setting operation only. .br \fB\-get\fR : performs getting operation only. .br \fB\-getw\fR : performs getting with a buffer operation only. .br \fB\-rem\fR : performs removing operation only. .br \fB\-etc\fR : performs miscellaneous operations. .br \fB\-tran\fR : performs transaction. .br \fB\-oat\fR : opens the database with the auto transaction option. .br \fB\-oas\fR : opens the database with the auto synchronization option. .br \fB\-onl\fR : opens the database with the no locking option. .br \fB\-otl\fR : opens the database with the try locking option. .br \fB\-onr\fR : opens the database with the no auto repair option. .br \fB\-ulog \fIstr\fR\fR : specifies the update log directory. .br \fB\-ulim \fInum\fR\fR : specifies the limit size of each update log file. .br \fB\-sid \fInum\fR\fR : specifies the server ID number. .br \fB\-dbid \fInum\fR\fR : specifies the database ID number. .br \fB\-lv\fR : reports all errors. .br \fB\-it \fInum\fR\fR : specifies the number of repetition. .br \fB\-hard\fR : performs physical synchronization. .br \fB\-ru\fR : reuses the existing database. .br \fB\-tmp \fIstr\fR\fR : specifies the path of a directory for temporary storage. .br \fB\-dbnum \fInum\fR\fR : specifies the number of temporary databases. .br \fB\-clim \fInum\fR\fR : specifies the limit size of cache memory. .br \fB\-cbnum \fInum\fR\fR : specifies the bucket number of cache memory. .br \fB\-xnl\fR : executes with the no locking option. .br \fB\-xpm\fR : executes with the parallel mapper option. .br \fB\-xpr\fR : executes with the parallel reducer option. .br \fB\-xpf\fR : executes with the parallel flusher option. .br \fB\-xnc\fR : executes with the no compression option. .br .RE .PP This command returns 0 on success, another on failure. .SH SEE ALSO .PP .BR kttimedmgr (1) �������kyototycoon-0.9.56/man/htmltoman��������������������������������������������������������������������0000755�0001750�0001750�00000004360�11442320251�015717� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������#! /usr/bin/awk -f function strip(text){ gsub("^ *<[a-zA-Z0-9]*[^>]*>", "", text) gsub("</[a-zA-Z0-9]*> *$", "", text) return text } function unescape(text){ gsub("<", "<", text) gsub(">", ">", text) gsub(""", "\"", text) gsub("&", "\\&", text) gsub("-", "\\-", text) return text } BEGIN { date = strftime("%Y-%m-%d") printf(".TH \"%s\" %d \"%s\" \"%s\" \"%s\"\n\n", "INTRO", 3, date, "Man Page", "Kyoto Cabinet") } / *<h[1-3] *[^>]*>.*<\/h[1-3]> *$/ { text = $0 text = strip(text) text = unescape(text) text = toupper(text) printf("\n") printf(".SH %s\n", text) } / *<p *[^>]*>.*<\/p> *$/ { text = $0 text = strip(text) text = gensub("<code *[^>]*>([^<]*)</code>", "\\\\fB\\1\\\\fR", "g", text) text = gensub("<var *[^>]*>([^<]*)</var>", "\\\\fI\\1\\\\fR", "g", text) gsub("<[^>]*>", "", text) text = unescape(text) printf(".PP\n") printf("%s\n", text) } / *<dl *[^>]*> *$/ { printf(".PP\n") printf(".RS\n") } / *<\/dl> *$/ { printf(".RE\n") } / *<dt *[^>]*>.*<\/dt> *$/ { text = $0 text = strip(text) text = gensub("<var *[^>]*>([^<]*)</var>", "\\\\fI\\1\\\\fB", "g", text) gsub("<[^>]*>", "", text) gsub("[\\||\\[|\\]]", "\\fR&\\fB", text) text = unescape(text) printf(".br\n") printf("\\fB%s\\fR\n", text) } / *<dd *[^>]*>.*<\/dd> *$/ { text = $0 text = strip(text) text = gensub("<code *[^>]*>([^<]*)</code>", "\\\\fB\\1\\\\fR", "g", text) text = gensub("<var *[^>]*>([^<]*)</var>", "\\\\fI\\1\\\\fR", "g", text) gsub("<[^>]*>", "", text) text = unescape(text) printf(".RS\n") printf("%s\n", text) printf(".RE\n") } / *<ul *[^>]*> *$/ { printf(".PP\n") printf(".RS\n") } / *<\/ul> *$/ { printf(".RE\n") } / *<li *[^>]*>.*<\/li> *$/ { text = $0 text = strip(text) text = gensub("<code *[^>]*>(.*)</code>", "\\\\fB\\1\\\\fR", "g", text) text = gensub("<var *[^>]*>([^<]*)</var>", "\\\\fI\\1\\\\fR", "g", text) gsub("<[^>]*>", "", text) text = unescape(text) printf("%s\n", text) printf(".br\n") } END { printf("\n") printf(".SH SEE ALSO\n") printf(".PP\n") printf(".BR kcutilmgr (1),\n") printf(".BR kcutiltest (1)\n") printf(".PP\n") printf("Please see\n") printf(".I http://fallabs.com/kyotocabinet/\n") printf("for detail.\n") } ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/man/ktserver.1�������������������������������������������������������������������0000644�0001750�0001750�00000015352�11757471566�015751� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH "KTSERVER" 1 "2012-05-25" "Man Page" "Kyoto Tycoon" .SH NAME ktserver \- a lightweight database server .SH DESCRIPTION .PP The command `\fBktserver\fR' runs the server managing database instances. This command is used in the following format. `\fIdb\fR' specifies a database name. If no database is specified, an unnamed on\-memory database is opened. .PP .RS .br \fBktserver \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-log \fIfile\fB\fR]\fB \fR[\fB\-li\fR|\fB\-ls\fR|\fB\-le\fR|\fB\-lz\fR]\fB \fR[\fB\-ulog \fIdir\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-uasi \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-ord\fR]\fB \fR[\fB\-oat\fR|\fB\-oas\fR|\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-asi \fInum\fB\fR]\fB \fR[\fB\-ash\fR]\fB \fR[\fB\-bgs \fIdir\fB\fR]\fB \fR[\fB\-bgsi \fInum\fB\fR]\fB \fR[\fB\-bgc \fIstr\fB\fR]\fB \fR[\fB\-dmn\fR]\fB \fR[\fB\-pid \fIfile\fB\fR]\fB \fR[\fB\-scr \fIfile\fB\fR]\fB \fR[\fB\-mhost \fIstr\fB\fR]\fB \fR[\fB\-mport \fInum\fB\fR]\fB \fR[\fB\-rts \fIfile\fB\fR]\fB \fR[\fB\-riv \fInum\fB\fR]\fB \fR[\fB\-plsv \fIfile\fB\fR]\fB \fR[\fB\-plex \fIstr\fB\fR]\fB \fR[\fB\-pldb \fIfile\fB\fR]\fB \fR[\fB\fIdb\fB...\fR]\fB\fR .RE .PP Options feature the following. .PP .RS \fB\-host \fIstr\fR\fR : specifies the host name of the server. .br \fB\-port \fInum\fR\fR : specifies the port number of the server. .br \fB\-tout \fInum\fR\fR : specifies the timeout in seconds. .br \fB\-th \fInum\fR\fR : specifies the number of worker threads. By default, it is 8. .br \fB\-log \fIfile\fR\fR : specifies the path of the log file. By default, logs are written into the standard output. .br \fB\-li\fR : sets the logging level "INFO". .br \fB\-ls\fR : sets the logging level "SYSTEM". .br \fB\-le\fR : sets the logging level "ERROR". .br \fB\-lz\fR : sets the logging level "NONE". .br \fB\-ulog \fIdir\fR\fR : specifies the path of the update log directory. By default, it is disabled. .br \fB\-ulim \fInum\fR\fR : specifies the limit size of each update log file. .br \fB\-uasi \fInum\fR\fR : specifies the interval of synchronization of update log files. By default, it is disabled. .br \fB\-sid \fInum\fR\fR : specifies the server ID number. .br \fB\-ord\fR : opens the database as a reader. .br \fB\-oat\fR : opens the database with the auto transaction option. .br \fB\-oas\fR : opens the database with the auto synchronization option. .br \fB\-onl\fR : opens the database with the no locking option. .br \fB\-otl\fR : opens the database with the try locking option. .br \fB\-onr\fR : opens the database with the no auto repair option. .br \fB\-asi \fInum\fR\fR : specifies the interval of auto synchronization. By default, it is disabled. .br \fB\-ash\fR : does physical synchronization while auto synchronization. .br \fB\-bgs \fIdir\fR\fR : specifies the path of the background snapshot directory. By default, it is disabled. .br \fB\-bgsi \fInum\fR\fR : specifies the interval of background snapshotting. By default, it is 180. .br \fB\-bgsc \fIstr\fR\fR : specifies the compression algorithm of the snapshot. "zlib", "lzo", are "lzma" are supported. .br \fB\-dmn\fR : switches to a daemon process. .br \fB\-pid \fIfile\fR\fR : specifies the file to contain the process ID to send signals by. .br \fB\-cmd \fIdir\fR\fR : specifies the command search path for outer commands. By default, it is the current directroy. .br \fB\-scr \fIfile\fR\fR : specifies the script file for the scripting extention. .br \fB\-mhost \fIstr\fR\fR : specifies the host name of the master server of replication. .br \fB\-mport \fInum\fR\fR : specifies the port number of the master server of replication. .br \fB\-rts \fIfile\fR\fR : specifies the file to contain the replication time stamp. .br \fB\-riv \fInum\fR\fR : specifies the interval of each replication operation in milliseconds. By default, it is 0.04. .br \fB\-plsv \fIfile\fR\fR : specifies the shared library file of a pluggable server. .br \fB\-plex \fIstr\fR\fR : specifies the configuration expression of a pluggable server. .br \fB\-pldb \fIfile\fR\fR : specifies the shared library file of a pluggable database. .br .RE .PP This command returns 0 on success, another on failure. .PP To finish the server process running on foreground, input `\fBCtrl\-C\fR' on the terminal. To finish the server process running as a daemon, send a termination signal such as SIGTERM by the `\fBkill\fR' command. If a daemon process catches SIGHUP, the server restarts and the log file is re\-opened. Because thr current directory of a daemon process is changed to the root directory, paths of related files should be described as their absolute paths. .PP The naming convention of database name is the same as polymorphic database of Kyoto Cabinet. If it is "\-", the database will be a prototype hash database. If it is "+", the database will be a prototype tree database. If it is ":", the database will be a stash database. If it is "*", the database will be a cache hash database. If it is "%", the database will be a cache tree database. If its suffix is ".kch", the database will be a file hash database. If its suffix is ".kct", the database will be a file tree database. If its suffix is ".kcd", the database will be a directory hash database. If its suffix is ".kcf", the database will be a directory tree database. Tuning parameters can trail the name, separated by "#". Each parameter is composed of the name and the value, separated by "=". If the "type" parameter is specified, the database type is determined by the value in "\-", "+", ":", "*", "%", "kch", "kct", "kcd", and "kcf". All database types support the logging parameters of "log", "logkinds", and "logpx". The prototype hash database and the prototype tree database do not support any other tuning parameter. The stash database supports "bnum". The cache hash database supports "opts", "bnum", "zcomp", "capcnt", "capsiz", and "zkey". The cache tree database supports all parameters of the cache hash database except for capacity limitation, and supports "psiz", "rcomp", "pccap" in addition. The file hash database supports "apow", "fpow", "opts", "bnum", "msiz", "dfunit", "zcomp", and "zkey". The file tree database supports all parameters of the file hash database and "psiz", "rcomp", "pccap" in addition. The directory hash database supports "opts", "zcomp", and "zkey". The directory tree database supports all parameters of the directory hash database and "psiz", "rcomp", "pccap" in addition. .PP Furthermore, several parameters are added by Kyoto Tycoon. "ktopts" sets options and the value can contain "p" for the persistent option. "ktcapcnt" sets the capacity by record number. "ktcapsiz" sets the capacity by database size. .SH SEE ALSO .PP .BR ktremotetest (1), .BR ktremotemgr (1) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/man/ktremotetest.1���������������������������������������������������������������0000644�0001750�0001750�00000005363�11757471566�016637� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH "KTREMOTETEST" 1 "2012-05-25" "Man Page" "Kyoto Tycoon" .SH NAME ktremotetest \- command line interface to test the remote database .SH DESCRIPTION .PP The command `\fBktremotetest\fR' is a utility for facility test and performance test of the remote database. This command is used in the following format. `\fIrnum\fR' specifies the number of iterations. .PP .RS .br \fBktremotetest order \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-rnd\fR]\fB \fR[\fB\-set\fR|\fB\-get\fR|\fB\-rem\fR|\fB\-etc\fR]\fB \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fIrnum\fB\fR .RS Performs in\-order tests. .RE .br \fBktremotetest bulk \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-bin\fR]\fB \fR[\fB\-rnd\fR]\fB \fR[\fB\-set\fR|\fB\-get\fR|\fB\-rem\fR|\fB\-etc\fR]\fB \fR[\fB\-bulk \fInum\fB\fR]\fB \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-bnr\fR]\fB \fIrnum\fB\fR .RS Performs bulk operation tests. .RE .br \fBktremotetest wicked \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-it \fInum\fB\fR]\fB \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fIrnum\fB\fR .RS Performs mixed operations selected at random. .RE .br \fBktremotetest usual \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-it \fInum\fB\fR]\fB \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-kp \fInum\fB\fR]\fB \fR[\fB\-vs \fInum\fB\fR]\fB \fR[\fB\-xt \fInum\fB\fR]\fB \fR[\fB\-iv \fInum\fB\fR]\fB \fIrnum\fB\fR .RS Performs mixed operations to simulate usual use cases. .RE .RE .PP Options feature the following. .PP .RS \fB\-th \fInum\fR\fR : specifies the number of worker threads. .br \fB\-rnd\fR : performs random test. .br \fB\-set\fR : performs setting operation only. .br \fB\-get\fR : performs getting operation only. .br \fB\-rem\fR : performs removing operation only. .br \fB\-etc\fR : performs miscellaneous operations. .br \fB\-host \fIstr\fR\fR : specifies the host name of the server. .br \fB\-port \fInum\fR\fR : specifies the port number of the server. .br \fB\-tout \fInum\fR\fR : specifies the timeout in seconds. .br \fB\-bin\fR : uses the binary protocol. .br \fB\-bulk \fInum\fR\fR : specifies the number of records in a bulk operation. .br \fB\-bnr\fR : enables the no\-reply option in the binary protocol. .br \fB\-it \fInum\fR\fR : specifies the number of repetition. .br \fB\-kp \fInum\fR\fR : specifies the number of patterns of keys. .br \fB\-vs \fInum\fR\fR : specifies the size of each value. .br \fB\-xt \fInum\fR\fR : specifies the expiration date. .br \fB\-iv \fInum\fR\fR : specifies the interval of each operation in milliseconds. .br .RE .PP This command returns 0 on success, another on failure. .SH SEE ALSO .PP .BR ktremotemgr (1) �����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/man/ktutiltest.1�����������������������������������������������������������������0000644�0001750�0001750�00000004527�11757471566�016322� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH "KTUTILTEST" 1 "2012-05-25" "Man Page" "Kyoto Tycoon" .SH NAME ktutiltest \- command line interface to test the utility functions .SH DESCRIPTION .PP The command `\fBktutiltest\fR' is a utility for facility test and performance test of the utility functions. This command is used in the following format. `\fIurl\fR' specifies the target URL. `\fIrnum\fR' specifies the number of iterations. `\fIproc\fR' specifies the name of the procedure to call. `\fIname\fR' and `\fIvalue\fR' specify a pair of the key and the value of an input parameter. `\fIpath\fR' specifies the path of a repository. .PP .RS .br \fBktutiltest http \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-get\fR|\fB\-head\fR|\fB\-post\fR|\fB\-put\fR|\fB\-delete\fR]\fB \fR[\fB\-body \fIfile\fB\fR]\fB \fR[\fB\-ah \fIname\fB \fIvalue\fB\fR]\fB \fR[\fB\-qs \fIname\fB \fIvalue\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-ka\fR]\fB \fIurl\fB \fIrnum\fB\fR .RS Performs test of HTTP sessions. .RE .br \fBktutiltest rpc \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fIproc\fB \fIrnum\fB \fR[\fB\fIname\fB \fIvalue\fB ...\fR]\fB\fR .RS Performs test of RPC sessions. .RE .br \fBktutiltest ulog \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fIpath\fB \fIrnum\fB \fR[\fB\fIname\fB \fIvalue\fB ...\fR]\fB\fR .RS Performs test of update logging. .RE .RE .PP Options feature the following. .PP .RS \fB\-th \fInum\fR\fR : specifies the number of worker threads. .br \fB\-get\fR : uses the GET method. .br \fB\-head\fR : uses the HEAD method. .br \fB\-post\fR : uses the POST method. .br \fB\-put\fR : uses the PUT method. .br \fB\-delete\fR : uses the DELETE method. .br \fB\-body \fIfile\fR\fR : sends the entity body of the content the file. .br \fB\-ah \fIname\fR \fIvalue\fR\fR : adds an HTTP header. .br \fB\-qs \fIname\fR \fIvalue\fR\fR : adds a key/value pair to the query string. .br \fB\-tout \fInum\fR\fR : specifies the timeout in seconds. .br \fB\-ka\fR : use keep\-alive connection. .br \fB\-host \fIstr\fR\fR : specifies the host name of the server. .br \fB\-port \fInum\fR\fR : specifies the port number of the server. .br \fB\-ulim \fInum\fR\fR : specifies the limit size of each update log file. .br .RE .PP This command returns 0 on success, another on failure. .SH SEE ALSO .PP .BR ktutilmgr (1), .BR ktutilserv (1) �������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/man/ktutilserv.1�����������������������������������������������������������������0000644�0001750�0001750�00000003607�11757471566�016320� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH "KTUTILSERV" 1 "2012-05-25" "Man Page" "Kyoto Tycoon" .SH NAME ktutilserv \- server implementations to test miscellaneous utilities .SH DESCRIPTION .PP The command `\fBktutilserv\fR' is a utility for facility test and performance test of the server tool kit. This command is used in the following format. `\fIbasedir\fR' specifies the document root directory. .PP .RS .br \fBktutilserv echo \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB\fR .RS Runs the single\-threaded echo server. .RE .br \fBktutilserv mtecho \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-li\fR|\fB\-ls\fR|\fB\-le\fR|\fB\-lz\fR]\fB\fR .RS Runs the multi\-threaded echo server. .RE .br \fBktutilserv http \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-li\fR|\fB\-ls\fR|\fB\-le\fR|\fB\-lz\fR]\fB \fR[\fB\fIbasedir\fB\fR]\fB\fR .RS Runs the HTTP server. .RE .br \fBktutilserv rpc \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-th \fInum\fB\fR]\fB \fR[\fB\-li\fR|\fB\-ls\fR|\fB\-le\fR|\fB\-lz\fR]\fB\fR .RS Runs the RPC server. .RE .RE .PP Options feature the following. .PP .RS \fB\-host \fIstr\fR\fR : specifies the host name of the server. .br \fB\-port \fInum\fR\fR : specifies the port number of the server. .br \fB\-tout \fInum\fR\fR : specifies the timeout in seconds. .br \fB\-th \fInum\fR\fR : specifies the number of worker threads. By default, it is 8. .br \fB\-li\fR : sets the logging level "INFO". .br \fB\-ls\fR : sets the logging level "SYSTEM". .br \fB\-le\fR : sets the logging level "ERROR". .br \fB\-lz\fR : sets the logging level "NONE". .br .RE .PP This command returns 0 on success, another on failure. .SH SEE ALSO .PP .BR ktutiltest (1), .BR ktutilmgr (1) �������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/man/kttimedmgr.1�����������������������������������������������������������������0000644�0001750�0001750�00000015102�11757471566�016244� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH "KTTIMEDMGR" 1 "2012-05-25" "Man Page" "Kyoto Tycoon" .SH NAME kttimedmgr \- command line interface to manage the timed database .SH DESCRIPTION .PP The command `\fBkttimedmgr\fR' is a utility for test and debugging of the timed database and its applications. `\fIpath\fR' specifies the path of a database file. `\fIkey\fR' specifies the key of a record. `\fIvalue\fR' specifies the value of a record. `\fIfile\fR' specifies the input/output file. `\fIdir\fR' specifies the input/output directory. `\fIsrc\fR' specifies other database files. .PP .RS .br \fBkttimedmgr create \fR[\fB\-otr\fR]\fB \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fIpath\fB\fR .RS Creates a database file. .RE .br \fBkttimedmgr inform \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-st\fR]\fB \fIpath\fB\fR .RS Prints status information. .RE .br \fBkttimedmgr set \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-add\fR|\fB\-app\fR|\fB\-rep\fR|\fB\-inci\fR|\fB\-incd\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-xt \fInum\fB\fR]\fB \fIpath\fB \fIkey\fB \fIvalue\fB\fR .RS Stores a record. .RE .br \fBkttimedmgr remove \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-sx\fR]\fB \fIpath\fB \fIkey\fB\fR .RS Removes a record. .RE .br \fBkttimedmgr get \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-rm\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-px\fR]\fB \fR[\fB\-pt\fR]\fB \fR[\fB\-pz\fR]\fB \fIpath\fB \fIkey\fB\fR .RS Prints the value of a record. .RE .br \fBkttimedmgr list \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-des\fR]\fB \fR[\fB\-max \fInum\fB\fR]\fB \fR[\fB\-rm\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-pv\fR]\fB \fR[\fB\-px\fR]\fB \fR[\fB\-pt\fR]\fB \fIpath\fB \fR[\fB\fIkey\fB\fR]\fB\fR .RS Prints keys of all records, separated by line feeds. .RE .br \fBkttimedmgr clear \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fIpath\fB\fR .RS Removes all records of a database. .RE .br \fBkttimedmgr import \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-xt \fInum\fB\fR]\fB \fIpath\fB \fR[\fB\fIfile\fB\fR]\fB\fR .RS Imports records from a TSV file. .RE .br \fBkttimedmgr copy \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fIpath\fB \fIfile\fB\fR .RS Copies the whole database. .RE .br \fBkttimedmgr dump \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fIpath\fB \fR[\fB\fIfile\fB\fR]\fB\fR .RS Dumps records into a snapshot file. .RE .br \fBkttimedmgr load \fR[\fB\-otr\fR]\fB \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fIpath\fB \fR[\fB\fIfile\fB\fR]\fB\fR .RS Loads records from a snapshot file. .RE .br \fBkttimedmgr vacuum \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fIpath\fB\fR .RS Eliminates regions of expired records. .RE .br \fBkttimedmgr recover \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-ts \fInum\fB\fR]\fB \fIpath\fB \fIdir\fB\fR .RS Recover the database with update log data. .RE .br \fBkttimedmgr merge \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fR[\fB\-add\fR|\fB\-app\fR|\fB\-rep\fR]\fB \fIpath\fB \fIsrc\fB...\fR .RS Merge records from other databases. .RE .br \fBkttimedmgr check \fR[\fB\-onl\fR|\fB\-otl\fR|\fB\-onr\fR]\fB \fR[\fB\-ulog \fIstr\fB\fR]\fB \fR[\fB\-ulim \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-dbid \fInum\fB\fR]\fB \fIpath\fB\fR .RS Checks consistency. .RE .br \fBkttimedmgr bgsinform \fIfile\fB\fR .RS Prints status information of background snapshot files. .RE .RE .PP Options feature the following. .PP .RS \fB\-otr\fR : opens the database with the truncation option. .br \fB\-onl\fR : opens the database with the no locking option. .br \fB\-otl\fR : opens the database with the try locking option. .br \fB\-onr\fR : opens the database with the no auto repair option. .br \fB\-ulog \fIstr\fR\fR : specifies the update log directory. .br \fB\-ulim \fInum\fR\fR : specifies the limit size of each update log file. .br \fB\-sid \fInum\fR\fR : specifies the server ID number. .br \fB\-dbid \fInum\fR\fR : specifies the database ID number. .br \fB\-st\fR : prints miscellaneous information. .br \fB\-add\fR : performs adding operation. .br \fB\-app\fR : performs appending operation. .br \fB\-rep\fR : performs replacing operation. .br \fB\-inci\fR : performs integer increment operation. .br \fB\-incd\fR : performs real number increment operation. .br \fB\-sx\fR : the input data is evaluated as a hexadecimal data string. .br \fB\-xt \fInum\fR\fR : specifies the expiration time. .br \fB\-rm\fR : removes the record. .br \fB\-px\fR : the output data is converted into a hexadecimal data string. .br \fB\-pt\fR : prints the expiration time also. .br \fB\-pz\fR : does not append line feed at the end of the output. .br \fB\-des\fR : visits records in descending order. .br \fB\-max \fInum\fR\fR : specifies the maximum number of shown records. .br \fB\-pv\fR : prints values of records also. .br \fB\-ts \fInum\fR\fR : specifies the maximum time stamp of already read logs. "now" means the current time stamp. .br .RE .PP This command returns 0 on success, another on failure. .SH SEE ALSO .PP .BR kttimedtest (1) ��������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/man/ktremotemgr.1����������������������������������������������������������������0000644�0001750�0001750�00000020516�11757471566�016442� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH "KTREMOTEMGR" 1 "2012-05-25" "Man Page" "Kyoto Tycoon" .SH NAME ktremotemgr \- command line interface to manage the remote database .SH DESCRIPTION .PP The command `\fBktremotedmgr\fR' is a utility for test and debugging of the remote database and its applications. `\fIproc\fR' specifies the name of a procedure. `\fIparams\fR' specifies arbitrary parameters. `\fImhost\fR' specifies the host name of the master server. `\fIkey\fR' specifies the key of a record. `\fIvalue\fR' specifies the value of a record. .PP .RS .br \fBktremotemgr report \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB\fR .RS Prints statistics of the server. .RE .br \fBktremotemgr script \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-bin\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fIproc\fB \fR[\fB\fIparams\fB...\fR]\fB\fR .RS Calls a procedure of the scripting extension. .RE .br \fBktremotemgr tunerepl \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-mport \fIstr\fB\fR]\fB \fR[\fB\-ts \fInum\fB\fR]\fB \fR[\fB\-iv \fInum\fB\fR]\fB \fR[\fB\fImhost\fB\fR]\fB\fR .RS Sets the replication configuration. .RE .br \fBktremotemgr inform \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-st\fR]\fB\fR .RS Prints status information of a database. .RE .br \fBktremotemgr clear \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB\fR .RS Removes all records of a database. .RE .br \fBktremotemgr sync \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-hard\fR]\fB \fR[\fB\-cmd \fIstr\fB\fR]\fB\fR .RS Synchronizes updated contents with the file and the device. .RE .br \fBktremotemgr set \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-add\fR|\fB\-rep\fR|\fB\-app\fR|\fB\-inci\fR|\fB\-incd\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-xt \fInum\fB\fR]\fB \fIkey\fB \fIvalue\fB\fR .RS Stores a record. .RE .br \fBktremotemgr remove \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-sx\fR]\fB \fIkey\fB\fR .RS Removes a record. .RE .br \fBktremotemgr get \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-rm\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-px\fR]\fB \fR[\fB\-pt\fR]\fB \fR[\fB\-pz\fR]\fB \fIkey\fB\fR .RS Prints the value of a record. .RE .br \fBktremotemgr list \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-des\fR]\fB \fR[\fB\-max \fInum\fB\fR]\fB \fR[\fB\-rm\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-pv\fR]\fB \fR[\fB\-px\fR]\fB \fR[\fB\-pt\fR]\fB \fR[\fB\fIkey\fB\fR]\fB\fR .RS Prints keys of all records, separated by line feeds. .RE .br \fBktremotemgr import \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-xt \fInum\fB\fR]\fB \fR[\fB\fIfile\fB\fR]\fB\fR .RS Imports records from a TSV file. .RE .br \fBktremotemgr vacuum \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-step \fInum\fB\fR]\fB \fIpath\fB\fR .RS Eliminates regions of expired records. .RE .br \fBktremotemgr slave \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-ts \fInum\fB\fR]\fB \fR[\fB\-sid \fInum\fB\fR]\fB \fR[\fB\-ux\fR]\fB \fR[\fB\-uw\fR]\fB \fR[\fB\-uf\fR]\fB \fR[\fB\-ur\fR]\fB\fR .RS Simulates a client of replication and prints update logs. .RE .br \fBktremotemgr setbulk \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-bin\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-xt \fInum\fB\fR]\fB \fIkey\fB \fIvalue\fB ...\fR .RS Store records at once. .RE .br \fBktremotemgr removebulk \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-bin\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-sx\fR]\fB \fIkey\fB ...\fR .RS Remove records at once. .RE .br \fBktremotemgr getbulk \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-bin\fR]\fB \fR[\fB\-swname \fIstr\fB\fR]\fB \fR[\fB\-swtime \fInum\fB\fR]\fB \fR[\fB\-ssname \fIstr\fB\fR]\fB \fR[\fB\-ssbrd\fR]\fB \fR[\fB\-db \fIstr\fB\fR]\fB \fR[\fB\-sx\fR]\fB \fR[\fB\-px\fR]\fB \fIkey\fB ...\fR .RS Retrieve records at once. .RE .RE .PP Options feature the following. .PP .RS \fB\-host \fIstr\fR\fR : specifies the host name of the server. .br \fB\-port \fInum\fR\fR : specifies the port number of the server. .br \fB\-tout \fInum\fR\fR : specifies the timeout in seconds. .br \fB\-swname \fIstr\fR\fR : waits for a signal by a named condition variable. .br \fB\-swtime \fInum\fR\fR : specifies the timeout of signal waiting in seconds. .br \fB\-ssname \fIstr\fR\fR : sends a signal to a named condition variable. .br \fB\-ssbrd\fR : switches signal sending to broadcasting. .br \fB\-bin\fR : uses the binary protocol. .br \fB\-mport \fInum\fR\fR : specifies the port number of the master server. .br \fB\-ts \fInum\fR\fR : specifies the maximum time stamp of already read logs. "now" means the current time stamp. .br \fB\-iv \fInum\fR\fR : specifies the interval of each replication operation in milliseconds. .br \fB\-db \fIstr\fR\fR : specifies the target database. .br \fB\-st\fR : prints miscellaneous information. .br \fB\-hard\fR : performs physical synchronization with the device. .br \fB\-cmd \fIstr\fR\fR : specifies an outer command for postprocessing. .br \fB\-add\fR : performs adding operation. .br \fB\-app\fR : performs appending operation. .br \fB\-rep\fR : performs replacing operation. .br \fB\-inci\fR : performs integer increment operation. .br \fB\-incd\fR : performs real number increment operation. .br \fB\-sx\fR : the input data is evaluated as a hexadecimal data string. .br \fB\-xt \fInum\fR\fR : specifies the expiration time. .br \fB\-rm\fR : removes the record. .br \fB\-px\fR : the output data is converted into a hexadecimal data string. .br \fB\-pt\fR : prints the expiration time also. .br \fB\-pz\fR : does not append line feed at the end of the output. .br \fB\-des\fR : visits records in descending order. .br \fB\-max \fInum\fR\fR : specifies the maximum number of shown records. .br \fB\-pv\fR : prints values of records also. .br \fB\-step \fInum\fR\fR : specifies the number of steps. .br \fB\-sid \fInum\fR\fR : specifies the server ID number. .br \fB\-ux\fR : fetches update logs of the specified server ID number only. .br \fB\-uw\fR : waits for update forever. .br \fB\-uf\fR : prints status of each update log file. .br \fB\-ur\fR : remove old update log files. .br .RE .PP This command returns 0 on success, another on failure. .SH SEE ALSO .PP .BR ktremotetest (1) ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/man/ktutilmgr.1������������������������������������������������������������������0000644�0001750�0001750�00000006552�11757471566�016130� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������.TH "KTUTILMGR" 1 "2012-05-25" "Man Page" "Kyoto Tycoon" .SH NAME ktutilmgr \- command line interface of miscellaneous utilities .SH DESCRIPTION .PP The command `\fBktutilmgr\fR' is a tool of miscellaneous utilities, and to show the configuration. This command is used in the following format. `\fIurl\fR' specifies the target URL. `\fIproc\fR' specifies the name of the procedure to call. `\fIname\fR' and `\fIvalue\fR' specify a pair of the key and the value of an input parameter. `\fIpath\fR' specifies the path of a repository. .PP .RS .br \fBktutilmgr date \fR[\fB\-ds \fIstr\fB\fR]\fB \fR[\fB\-jl \fInum\fB\fR]\fB \fR[\fB\-wf\fR]\fB \fR[\fB\-rf\fR]\fB\fR .RS Prints date information. By default, prints the current UNIX time. .RE .br \fBktutilmgr http \fR[\fB\-get\fR|\fB\-head\fR|\fB\-post\fR|\fB\-put\fR|\fB\-delete\fR]\fB \fR[\fB\-body \fIfile\fB\fR]\fB \fR[\fB\-ah \fIname\fB \fIvalue\fB\fR]\fB \fR[\fB\-qs \fIname\fB \fIvalue\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-ph\fR]\fB \fR[\fB\-ec \fInum\fB\fR]\fB \fIurl\fB\fR .RS Performs an HTTP session. .RE .br \fBktutilmgr rpc \fR[\fB\-host \fIstr\fB\fR]\fB \fR[\fB\-port \fInum\fB\fR]\fB \fR[\fB\-tout \fInum\fB\fR]\fB \fR[\fB\-ienc \fIstr\fB\fR]\fB \fR[\fB\-oenc \fIstr\fB\fR]\fB \fIproc\fB \fR[\fB\fIname\fB \fIvalue\fB ...\fR]\fB\fR .RS Performs an RPC session. .RE .br \fBktutilmgr ulog \fR[\fB\-ts \fInum\fB\fR]\fB \fR[\fB\-uw\fR]\fB \fR[\fB\-uf\fR]\fB \fIpath\fB\fR .RS Prints update logs. .RE .br \fBktutilmgr conf \fR[\fB\-v\fR|\fB\-i\fR|\fB\-l\fR|\fB\-p\fR]\fB\fR .RS Shows the configuration of Kyoto Tycoon. .RE .br \fBktutilmgr version\fR .RS Shows the version information of Kyoto Tycoon. .RE .RE .PP Options feature the following. .PP .RS \fB\-ds \fIstr\fR\fR : specifies the datetime string. .br \fB\-jl \fInum\fR\fR : specifies the jet lag. .br \fB\-wf\fR : formats the output in W3CDTF. .br \fB\-rf\fR : formats the output in RFC 1123 format. .br \fB\-get\fR : uses the GET method. .br \fB\-head\fR : uses the HEAD method. .br \fB\-post\fR : uses the POST method. .br \fB\-put\fR : uses the PUT method. .br \fB\-delete\fR : uses the DELETE method. .br \fB\-body \fIfile\fR\fR : sends the entity body of the content the file. .br \fB\-ah \fIname\fR \fIvalue\fR\fR : adds an HTTP header. .br \fB\-qs \fIname\fR \fIvalue\fR\fR : adds a key/value pair to the query string. .br \fB\-tout \fInum\fR\fR : specifies the timeout in seconds. .br \fB\-ph\fR : prints response headers. .br \fB\-ec \fInum\fR\fR : reports error if the response code is not the same as the expected. .br \fB\-host \fIstr\fR\fR : specifies the host name of the server. .br \fB\-port \fInum\fR\fR : specifies the port number of the server. .br \fB\-ienc \fIstr\fR\fR : specifies the encoding of the input data. .br \fB\-oenc \fIstr\fR\fR : specifies the encoding of the output data. .br \fB\-ts \fInum\fR\fR : specifies the maximum time stamp of already read logs. "now" means the current time stamp. .br \fB\-uw\fR : waits for update forever. .br \fB\-uf\fR : prints status of each update log file. .br \fB\-v\fR : show the version number of Kyoto Tycoon. .br \fB\-i\fR : show options to include the headers of Tokyo Tycoon. .br \fB\-l\fR : show options to link the library of Tokyo Tycoon. .br \fB\-p\fR : show the directory path of the commands. .br .RE .PP This command returns 0 on success, another on failure. .SH SEE ALSO .PP .BR ktutiltest (1), .BR ktutilserv (1) ������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/kyototycoon-doc.lua��������������������������������������������������������������0000644�0001750�0001750�00000112646�11757471566�017122� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������--------------------------------------------------------------------------------------------------- -- Scripting extension of Kyoto Tycoon -- Copyright (C) 2009-2012 FAL Labs -- This file is part of Kyoto Tycoon. -- This program is free software: you can redistribute it and/or modify it under the terms of -- the GNU General Public License as published by the Free Software Foundation, either version -- 3 of the License, or any later version. -- This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; -- without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- See the GNU General Public License for more details. -- You should have received a copy of the GNU General Public License along with this program. -- If not, see <http://www.gnu.org/licenses/>. --------------------------------------------------------------------------------------------------- --- -- The scripting extension of Kyoto Tycoon. -- module("kyototycoon", package.seeall) --- -- Running environment. -- @class table -- @name __kyototycoon__ -- @field RVSUCCESS status code: success -- @field RVENOIMPL status code: not implemented -- @field RVEINVALID status code: invalid operation -- @field RVELOGIC status code: logical inconsistency -- @field RVEINTERNAL status code: internal error -- @field VERSION the version information -- @field thid the ID number of the worker thread -- @field db the primary database object -- @field dbs an array of database objects -- __kyototycoon__ = { RVSUCCESS = 0, RVENOIMPL = 1, RVEINVALID = 2, RVELOGIC = 3, RVEINTERNAL = 4, VERSION = "x.y.z", thid = 0, db = {}, dbs = {}, } --- Log a message -- @param kind the kind of the event. "debug" for debugging, "info" for normal information, "system" for system information, and "error" for fatal error. -- @param message the supplement message. -- @return always nil. function log(kind, message) end --- Convert a string to an integer. -- @param str the string. -- @return the integer. If the string does not contain numeric expression, 0 is returned. function atoi(str) end --- Convert a string with a metric prefix to an integer. -- @param str the string, which can be trailed by a binary metric prefix. "K", "M", "G", "T", "P", and "E" are supported. They are case-insensitive. -- @return the integer. If the string does not contain numeric expression, 0 is returned. If the integer overflows the domain, INT64_MAX or INT64_MIN is returned according to the sign. function atoix(str) end --- Convert a string to a real number. -- @param str the string. -- @return the real number. If the string does not contain numeric expression, 0.0 is returned. function atof(str) end --- Get the hash value of a string by MurMur hashing. -- @param str the string. -- @return the hash value. function hash_murmur(str) end --- Get the hash value of a string by FNV hashing. -- @param str the string. -- @return the hash value. function hash_fnv(str) end --- Calculate the levenshtein distance of two strings. -- @param a one string. -- @param b the other string. -- @param utf flag to treat keys as UTF-8 strings. If it is omitted, false is specified. -- @return the levenshtein distance. function levdist(a, b, utf) end --- Get the time of day in seconds. -- @return the time of day in seconds. The accuracy is in microseconds. function time() end --- Suspend execution of the current thread. -- @param sec the interval of the suspension in seconds. If it is omitted, the processor is yielded from the current thread. function sleep(sec) end --- Serialize an array of numbers into a string. -- @param format the format string. It should be composed of conversion characters. "c" for int8_t, "C" for uint8_t, "s" for int16_t, "S" for uint16_t, "i" for int32_t, "I" for uint32_t, "l" for int64_t, "L" for uint64_t, "f" for float, "d" for double, "n" for uint16_t in network byte order, "N" for uint32_t in network byte order, "M" for uint64_t in network byte order, and "w" for BER encoding. They can be trailed by a numeric expression standing for the iteration count or by "*" for the rest all iteration. -- @param ary the array of numbers. It can be trailed optional arguments, which are treated as additional elements of the array. -- @return the serialized string. function pack(format, ary, ...) end --- Deserialize a binary string into an array of numbers. -- @param format the format string. It should be composed of conversion characters as with the pack function. -- @param str the binary string. -- @return the deserialized array. function unpack(format, str) end --- Split a string into substrings. -- @param str the string -- @param delims a string including separator characters. If it is omitted, the zero code is specified. -- @return an array of substrings. function split(str, delims) end --- Encode or decode a string. -- @param mode the encoding method; "url" for URL encoding, "~url" for URL decoding, "base" for Base64 encoding, "~base" for Base64 decoding, "hex" for hexadecimal encoding, "~hex" for hexadecimal decoding, "zlib" for ZLIB raw compressing, "~zlib" for ZLIB raw decompressing, "deflate" for ZLIB deflate compressing, "~deflate" for ZLIB deflate decompressing, "gzip" for ZLIB gzip compressing, "~gzip" for ZLIB gzip decompressing. -- @param str the string. -- @return the result string. function codec(mode, str) end --- Perform bit operation of an integer. -- @param mode the operator; "and" for bitwise-and operation, "or" for bitwise-or operation, "xor" for bitwise-xor operation, "not" for bitwise-not operation, "left" for left shift operation, "right" for right shift operation. -- @param num the integer, which is treated as an unsigned 32-bit integer. -- @param aux the auxiliary operand for some operators. -- @return the result value. function bit(mode, num, aux) end --- Perform substring matching or replacement without evaluating any meta character. -- @param str the source string. -- @param pattern the matching pattern. -- @param alt the alternative string corresponding for the pattern. If it is omitted, matching check is performed. -- @return If the alternative string is specified, the converted string is returned. If the alternative string is not specified, the index of the substring matching the given pattern or 0 is returned. function strstr(str, pattern, alt) end --- Perform forward matching without evaluating any meta character. -- @param str the source string. -- @param pattern the matching pattern. -- @return true if they matches, or false if not. function strfwm(str, pattern) end --- Perform backward matching without evaluating any meta character. -- @param str the source string. -- @param pattern the matching pattern. -- @return true if they matches, or false if not. function strbwm(str, pattern) end --- Perform pattern matching or replacement with regular expressions. -- @param str the source string. -- @param pattern the pattern of regular expressions. -- @param alt the alternative string corresponding for the pattern. If it is not defined, matching check is performed. -- @return If the alternative string is specified, the converted string is returned. If the alternative string is not specified, the boolean value of whether the source string matches the pattern is returned. function regex(str, pattern, alt) end --- Serialize an array into a string. -- @param src the source table. -- @return the result string. function arraydump(src) end --- Deserialize a string into an array. -- @param src the source string. -- @return the result map. function arrayload(src) end --- Serialize a map into a string. -- @param src the source table. -- @return the result string. function mapdump(src) end --- Deserialize a string into a map. -- @param src the source string. -- @return the result map. function mapload(src) end --- -- Error data. -- @class table -- @name Error -- @field SUCCESS error code: success -- @field NOIMPL error code: not implemented -- @field INVALID error code: invalid operation -- @field NOREPOS error code: no repository -- @field NOPERM error code: no permission -- @field BROKEN error code: broken file -- @field DUPREC error code: record duplication -- @field NOREC error code: no record -- @field LOGIC error code: logical inconsistency -- @field SYSTEM error code: system error -- @field MISC error code: miscellaneous error -- Error = { SUCCESS = 0, NOIMPL = 1, INVALID = 2, NOREPOS = 3, NOPERM = 4, BROKEN = 5, DUPREC = 6, NOREC = 7, LOGIC = 8, SYSTEM = 9, MISC = 15, } error = {} --- Create an error object. -- @param code the error code. -- @param message the supplement message. -- @return the error object. function Error:new(code, message) end --- Set the error information. -- @param code the error code. -- @param message the supplement message. -- @return always nil. function error:set(code, message) end --- Get the error code. -- @return the error code. function error:code() end --- Get the readable string of the code. -- @return the readable string of the code. function error:name() end --- Get the supplement message. -- @return the supplement message. function error:message() end --- Get the string expression. -- @return the string expression. function error:__tostring() end --- -- Interface to access a record. -- @class table -- @name Visitor -- @field NOP magic data: no operation -- @field REMOVE magic data: remove the record -- Visitor = { NOP = "(magic data)", REMOVE = "(magic data)", } visitor = {} --- Create a visitor object. -- @return the visitor object. function Visitor:new() end --- Visit a record. -- @param key the key. -- @param value the value. -- @param xt the absolute expiration time. -- @return If it is a string, the value is replaced by the content. If it is Visitor.NOP, nothing is modified. If it is Visitor.REMOVE, the record is removed. The expiration time can be also returned as the second value. function visitor:visit_full(key, value, xt) end --- Visit a empty record space. -- @param key the key. -- @return If it is a string, the value is replaced by the content. If it is Visitor.NOP or Visitor.REMOVE, nothing is modified. The expiration time can be also returned as the second value. function visitor:visit_empty(key) end --- Preprocess the main operations. function visitor:visit_before() end --- Postprocess the main operations. function visitor:visit_after() end --- -- Interface to process the database file. -- @class table -- @name FileProcessor -- FileProcessor = {} fileprocessor = {} --- Create a file processor object. -- @return the file processor object. function FileProcessor:new() end --- Process the database file. -- @param path the path of the database file. -- @param count the number of records. -- @param size the size of the available region. -- @return true on success, or false on failure. function fileprocessor:process(path, count, size) end --- -- Interface of cursor to indicate a record. -- @class table -- @name Cursor Cursor = {} cursor = {} --- Get the string expression. -- @return the string expression. function cursor:__tostring() end --- Get a pair of the key and the value of the current record. -- @param db ignored. This is just for compatibility with the "next" function for the generic "for" loop. -- @return a pair of the key and the value of the current record, or nil on failure. -- @usage If the cursor is invalidated, nil is returned. function cursor:__call(db) end --- Disable the cursor. -- @return always nil. -- @usage This method should be called explicitly when the cursor is no longer in use. function cursor:disable() end --- Accept a visitor to the current record. -- @param visitor a visitor object which implements the Visitor interface, or a function object which receives the key and the value. -- @param writable true for writable operation, or false for read-only operation. If it is omitted, true is specified. -- @param step true to move the cursor to the next record, or false for no move. If it is omitted, false is specified. -- @return true on success, or false on failure. -- @usage The operation for each record is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this method. function cursor:accept(visitor, writable, step) end --- Set the value of the current record. -- @param value the value. -- @param xt the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified. -- @param step true to move the cursor to the next record, or false for no move. If it is omitted, false is specified. -- @return true on success, or false on failure. function cursor:set_value(value, xt, step) end --- Remove the current record. -- @return true on success, or false on failure. -- @usage If no record corresponds to the key, false is returned. The cursor is moved to the next record implicitly. function cursor:remove() end --- Get the key of the current record. -- @param step true to move the cursor to the next record, or false for no move. If it is omitted, false is specified. -- @return the key of the current record, or nil on failure. -- @usage If the cursor is invalidated, nil is returned. function cursor:get_key(step) end --- Get the value of the current record. -- @param step true to move the cursor to the next record, or false for no move. If it is omitted, false is specified. -- @return the value of the current record, or nil on failure. -- @usage If the cursor is invalidated, nil is returned. function cursor:get_value(step) end --- Get a pair of the key and the value of the current record. -- @param step true to move the cursor to the next record, or false for no move. If it is omitted, false is specified. -- @return a trio of the key and the value and the expiration time of the current record, or nil on failure. -- @usage If the cursor is invalidated, nil is returned. function cursor:get(step) end --- Get a pair of the key and the value of the current record and remove it atomically. -- @return a trio of the key and the value and the expiration time of the current record, or nil on failure. -- @usage If the cursor is invalidated, nil is returned. The cursor is moved to the next record implicitly. function cursor:seize() end --- Jump the cursor to a record for forward scan. -- @param key the key of the destination record. if it is omitted, the destination is the first record. -- @return true on success, or false on failure. function cursor:jump(key) end --- Jump the cursor to a record for backward scan. -- @param key the key of the destination record. if it is omitted, the destination is the last record. -- @return true on success, or false on failure. -- @usage This method is dedicated to tree databases. Some database types, especially hash databases, will provide a dummy implementation. function cursor:jump_back(key) end --- Step the cursor to the next record. -- @return true on success, or false on failure. function cursor:step() end --- Step the cursor to the previous record. -- @return true on success, or false on failure. -- @usage This method is dedicated to tree databases. Some database types, especially hash databases, will provide a dummy implementation. function cursor:step_back() end --- Get the database object. -- @return the database object. function cursor:db() end --- Get the last happened error. -- @return the last happened error. function cursor:error() end --- -- Interface of database abstraction. -- @class table -- @name DB -- @field OREADER open mode: open as a reader -- @field OWRITER open mode: open as a writer -- @field OCREATE open mode: writer creating -- @field OTRUNCATE open mode: writer truncating -- @field OAUTOTRAN open mode: auto transaction -- @field OAUTOSYNC open mode: auto synchronization -- @field ONOLOCK open mode: open without locking -- @field OTRYLOCK open mode: lock without blocking -- @field ONOREPAIR open mode: open without auto repair -- @field MSET merge mode: overwrite the existing value -- @field MADD merge mode: keep the existing value -- @field MREPLACE merge mode: modify the existing record only -- @field MAPPEND merge mode: append the new value -- @field XNOLOCK mapreduce option: avoid locking against update operations -- @field XNOCOMP mapreduce option: avoid compression of temporary databases -- DB = { OREADER = 1, OWRITER = 2, OCREATE = 4, OTRUNCATE = 8, OAUTOTRAN = 16, OAUTOSYNC = 32, ONOLOCK = 64, OTRYLOCK = 128, ONOREPAIR = 256, MSET = 0, MADD = 1, MREPLACE = 2, MAPPEND = 3, XNOLOCK = 1, XNOCOMP = 256, } db = {} --- Create a database object. -- @param ptr a light user data of the pointer to a database object to use internally. If it is omitted, the internal database object is created and destroyed implicitly. -- @return the database object. function DB:new(ptr) end --- Create a database object. -- @return a light user data of the pointer to the created database object. It should be released with the delete_ptr method when it is no longer in use. function DB:new_ptr() end --- Delete a database object. -- @param ptr a light user data of the pointer to the database object. -- @return always nil. function DB:delete_ptr() end --- Process a database by a functor. -- @param proc the functor to process the database, whose object is passd as the parameter. -- @param path the same to the one of the open method. -- @param mode the same to the one of the open method. -- @return nil on success, or an error object on failure. function DB:process(proc, path, mode) end --- Get the string expression. -- @return the string expression. function db:__tostring() end --- Retrieve the value of a record. -- @param key the key. -- @return the value of the corresponding record, or nil on failure. function db:__index(key) end --- Set the value of a record. -- @param key the key. -- @param value the value. If it is nil, the record is removed. -- @return true on success, or false on failure. -- @usage If no record corresponds to the key, a new record is created. If the corresponding record exists, the value is overwritten. function db:__newindex(key, value) end --- Open a database file. -- @param path the path of a database file. If it is "-", the database will be a prototype hash database. If it is "+", the database will be a prototype tree database. If it is ":", the database will be a stash database. If it is "*", the database will be a cache hash database. If it is "%", the database will be a cache tree database. If its suffix is ".kch", the database will be a file hash database. If its suffix is ".kct", the database will be a file tree database. If its suffix is ".kcd", the database will be a directory hash database. If its suffix is ".kcf", the database will be a directory tree database. If its suffix is ".kcx", the database will be a plain text database. Otherwise, this function fails. Tuning parameters can trail the name, separated by "#". Each parameter is composed of the name and the value, separated by "=". If the "type" parameter is specified, the database type is determined by the value in "-", "+", ":", "*", "%", "kch", "kct", "kcd", kcf", and "kcx". All database types support the logging parameters of "log", "logkinds", and "logpx". The prototype hash database and the prototype tree database do not support any other tuning parameter. The stash database supports "bnum". The cache hash database supports "opts", "bnum", "zcomp", "capcnt", "capsiz", and "zkey". The cache tree database supports all parameters of the cache hash database except for capacity limitation, and supports "psiz", "rcomp", "pccap" in addition. The file hash database supports "apow", "fpow", "opts", "bnum", "msiz", "dfunit", "zcomp", and "zkey". The file tree database supports all parameters of the file hash database and "psiz", "rcomp", "pccap" in addition. The directory hash database supports "opts", "zcomp", and "zkey". The directory tree database supports all parameters of the directory hash database and "psiz", "rcomp", "pccap" in addition. The plain text database does not support any other tuning parameter. -- @param mode the connection mode. DB.OWRITER as a writer, DB.OREADER as a reader. The following may be added to the writer mode by bitwise-or: DB.OCREATE, which means it creates a new database if the file does not exist, DB.OTRUNCATE, which means it creates a new database regardless if the file exists, DB.OAUTOTRAN, which means each updating operation is performed in implicit transaction, DB.OAUTOSYNC, which means each updating operation is followed by implicit synchronization with the file system. The following may be added to both of the reader mode and the writer mode by bitwise-or: DB.ONOLOCK, which means it opens the database file without file locking, DB.OTRYLOCK, which means locking is performed without blocking, DB.ONOREPAIR, which means the database file is not repaired implicitly even if file destruction is detected. If it is omitted, DB.OWRITER + DB.OCREATE is specified. -- @return true on success, or false on failure. -- @usage The tuning parameter "log" is for the original "tune_logger" and the value specifies the path of the log file, or "-" for the standard output, or "+" for the standard error. "logkinds" specifies kinds of logged messages and the value can be "debug", "info", "warn", or "error". "logpx" specifies the prefix of each log message. "opts" is for "tune_options" and the value can contain "s" for the small option, "l" for the linear option, and "c" for the compress option. "bnum" corresponds to "tune_bucket". "zcomp" is for "tune_compressor" and the value can be "zlib" for the ZLIB raw compressor, "def" for the ZLIB deflate compressor, "gz" for the ZLIB gzip compressor, "lzo" for the LZO compressor, "lzma" for the LZMA compressor, or "arc" for the Arcfour cipher. "zkey" specifies the cipher key of the compressor. "capcnt" is for "cap_count". "capsiz" is for "cap_size". "psiz" is for "tune_page". "rcomp" is for "tune_comparator" and the value can be "lex" for the lexical comparator or "dec" for the decimal comparator. "pccap" is for "tune_page_cache". "apow" is for "tune_alignment". "fpow" is for "tune_fbp". "msiz" is for "tune_map". "dfunit" is for "tune_defrag". Every opened database must be closed by the DB::close method when it is no longer in use. It is not allowed for two or more database objects in the same process to keep their connections to the same database file at the same time. function db:open(path, mode) end --- Close the database file. -- @return true on success, or false on failure. function db:close() end --- Accept a visitor to a record. -- @param key the key. -- @param visitor a visitor object which implements the Visitor interface, or a function object which receives the key and the value. -- @param writable true for writable operation, or false for read-only operation. If it is omitted, true is specified. -- @return true on success, or false on failure. -- @usage The operation for each record is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this method. function db:accept(key, visitor, writable) end --- Accept a visitor to multiple records at once. -- @param keys specifies an array of the keys. -- @param visitor a visitor object which implements the Visitor interface, or a function object which receives the key and the value. -- @param writable true for writable operation, or false for read-only operation. If it is omitted, true is specified. -- @return true on success, or false on failure. -- @usage The operations for specified records are performed atomically and other threads accessing the same records are blocked. To avoid deadlock, any explicit database operation must not be performed in this method. function db:accept_bulk(keys, visitor, writable) end --- Iterate to accept a visitor for each record. -- @param visitor a visitor object which implements the Visitor interface, or a function object which receives the key and the value. -- @param writable true for writable operation, or false for read-only operation. If it is omitted, true is specified. -- @return true on success, or false on failure. -- @usage The whole iteration is performed atomically and other threads are blocked. To avoid deadlock, any explicit database operation must not be performed in this method. function db:iterate(visitor, writable) end --- Set the value of a record. -- @param key the key. -- @param value the value. -- @param xt the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified. -- @return true on success, or false on failure. -- @usage If no record corresponds to the key, a new record is created. If the corresponding record exists, the value is overwritten. function db:set(key, value, xt) end --- Add a record. -- @param key the key. -- @param value the value. -- @param xt the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified. -- @return true on success, or false on failure. -- @usage If no record corresponds to the key, a new record is created. If the corresponding record exists, the record is not modified and false is returned. function db:add(key, value, xt) end --- Replace the value of a record. -- @param key the key. -- @param value the value. -- @param xt the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified. -- @return true on success, or false on failure. -- @usage If no record corresponds to the key, no new record is created and false is returned. If the corresponding record exists, the value is modified. function db:replace(key, value, xt) end --- Append the value of a record. -- @param key the key. -- @param value the value. -- @param xt the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified. -- @return true on success, or false on failure. -- @usage If no record corresponds to the key, a new record is created. If the corresponding record exists, the given value is appended at the end of the existing value. function db:append(key, value, xt) end --- Add a number to the numeric integer value of a record. -- @param key the key. -- @param num the additional number. if it is omitted, 0 is specified. -- @param orig the origin number if no record corresponds to the key. If it is omitted, 0 is specified. If it is negative infinity and no record corresponds, this method fails. If it is positive infinity, the value is set as the additional number regardless of the current value. -- @param xt the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified. -- @return the result value, or nil on failure. -- @usage The value is serialized as an 8-byte binary integer in big-endian order, not a decimal string. If existing value is not 8-byte, this method fails. function db:increment(key, num, orig, xt) end --- Add a number to the numeric double value of a record. -- @param key the key. -- @param num the additional number. if it is omitted, 0 is specified. -- @param orig the origin number if no record corresponds to the key. If it is omitted, 0 is specified. If it is negative infinity and no record corresponds, this method fails. If it is positive infinity, the value is set as the additional number regardless of the current value. -- @param xt the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified. -- @return the result value, or nil on failure. -- @usage The value is serialized as an 16-byte binary fixed-point number in big-endian order, not a decimal string. If existing value is not 16-byte, this method fails. function db:increment_double(key, num, orig, xt) end --- Perform compare-and-swap. -- @param key the key. -- @param oval the old value. nil means that no record corresponds. -- @param nval the new value. nil means that the record is removed. -- @param xt the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified. -- @return true on success, or false on failure. function db:cas(key, oval, nval, xt) end --- Remove a record. -- @param key the key. -- @return true on success, or false on failure. -- @usage If no record corresponds to the key, false is returned. function db:remove(key) end --- Retrieve the value of a record. -- @param key the key. -- @return the value of the corresponding record, or nil on failure. The absolute expiration time is also returned as the second value. function db:get(key) end --- Check the existence of a record. -- @param key the key. -- @return the size of the value, or -1 on failure. function db:check(key) end --- Retrieve the value of a record and remove it atomically. -- @param key the key. -- @return the value of the corresponding record, or nil on failure. The absolute expiration time is also returned as the second value. function db:seize(key) end --- Store records at once. -- @param recs a table of the records to store. -- @param xt the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified. -- @param atomic true to perform all operations atomically, or false for non-atomic operations. If it is omitted, true is specified. -- @return the number of stored records, or -1 on failure. function db:set_bulk(recs, atomic) end --- Remove records at once. -- @param keys an array of the keys of the records to remove. -- @param atomic true to perform all operations atomically, or false for non-atomic operations. If it is omitted, true is specified. -- @return the number of removed records, or -1 on failure. function db:remove_bulk(keys, atomic) end --- Retrieve records at once. -- @param keys an array of the keys of the records to retrieve. -- @param atomic true to perform all operations atomically, or false for non-atomic operations. If it is omitted, true is specified. -- @return a table of retrieved records, or nil on failure. function db:get_bulk(keys, atomic) end --- Remove all records. -- @return true on success, or false on failure. function db:clear() end --- Synchronize updated contents with the file and the device. -- @param hard true for physical synchronization with the device, or false for logical synchronization with the file system. If it is omitted, false is specified. -- @param proc a postprocessor object which implements the FileProcessor interface, or a function object which receives the same parameters. If it is omitted or nil, no postprocessing is performed. -- @return true on success, or false on failure. -- @usage The operation of the processor is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this method. function db:synchronize(hard, proc) end --- Occupy database by locking and do something meanwhile. -- @param writable true to use writer lock, or false to use reader lock. If it is omitted, false is specified. -- @param proc a processor object which implements the FileProcessor interface, or a function object which receives the same parameters. If it is omitted or nil, no processing is performed. -- @return true on success, or false on failure. -- @usage The operation of the processor is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this method. function db:occupy(writable, proc) end --- Create a copy of the database file. -- @param dest the path of the destination file. -- @return true on success, or false on failure. function db:copy(dest) end --- Begin transaction. -- @param hard true for physical synchronization with the device, or false for logical synchronization with the file system. If it is omitted, false is specified. -- @return true on success, or false on failure. function db:begin_transaction(hard) end --- End transaction. -- @param commit true to commit the transaction, or false to abort the transaction. If it is omitted, true is specified. -- @return true on success, or false on failure. function db:end_transaction(commit) end --- Perform entire transaction by a functor. -- @param proc the functor of operations during transaction. If the function returns true, the transaction is committed. If the function returns false or an exception is thrown, the transaction is aborted. -- @param hard true for physical synchronization with the device, or false for logical synchronization with the file system. If it is omitted, false is specified. -- @return true on success, or false on failure. function db:transaction(proc, hard) end --- Dump records into a snapshot file. -- @param dest the name of the destination file. -- @return true on success, or false on failure. function db:dump_snapshot(dest) end --- Load records from a snapshot file. -- @param src the name of the source file. -- @return true on success, or false on failure. function db:load_snapshot(src) end --- Get the number of records. -- @return the number of records, or -1 on failure. function db:count() end --- Get the size of the database file. -- @return the size of the database file in bytes, or -1 on failure. function db:size() end --- Get the path of the database file. -- @return the path of the database file, or nil on failure. function db:path() end --- Get the miscellaneous status information. -- @return a table of the status information, or nil on failure. function db:status() end --- Get keys matching a prefix string. -- @param prefix the prefix string. -- @param max the maximum number to retrieve. If it is omitted or negative, no limit is specified. -- @return an array of matching keys, or nil on failure. function db:match_prefix(prefix, max) end --- Get keys matching a regular expression string. -- @param regex the regular expression string. -- @param max the maximum number to retrieve. If it is omitted or negative, no limit is specified. -- @return an array of matching keys, or nil on failure. function db:match_regex(regex, max) end --- Get keys similar to a string in terms of the levenshtein distance. -- @param origin the origin string. -- @param range the maximum distance of keys to adopt. If it is omitted, 1 is specified. -- @param utf flag to treat keys as UTF-8 strings. If it is omitted, false is specified. -- @param max the maximum number to retrieve. If it is omitted or negative, no limit is specified. -- @return an array of matching keys, or nil on failure. function db:match_similar(origin, range, utf, max) end --- Merge records from other databases. -- @param srcary an array of the source detabase objects. -- @param mode the merge mode. DB.MSET to overwrite the existing value, DB.MADD to keep the existing value, DB.MAPPEND to append the new value. If it is omitted, DB.MSET is specified. -- @return true on success, or false on failure. function db:merge(srcary, mode) end --- Execute a MapReduce process. -- @param map a function to map a record data. It is called for each record in the database and receives the key, the value, and a function to emit the mapped records. The emitter function receives a key and a value. The mapper function should return true normally or false on failure. -- @param reduce a function to reduce a record data. It is called for each record generated by emitted records by the map function and receives the key and a function to iterate to get each value. The reducer function should return true normally or false on failure. -- @param tmppath the path of a directory for the temporary data storage. If it is omitted, temporary data are handled on memory. -- @param opts the optional features by bitwise-or: DB.XNOLOCK to avoid locking against update operations by other threads, DB.XNOCOMP to avoid compression of temporary databases. -- @param dbnum the number of temporary databases. If it is omitted, the default setting is specified. -- @param clim the limit size of the internal cache. If it is omitted, the default setting is specified. -- @param cbnum the bucket number of the internal cache. If it is omitted, the default setting is specified. -- @param log a function to log each progression message. If it is omitted, log messages are ignored. -- @param proc a function called before the mapper, between the mapper and the reducer, and after the reducer. In the first two calls, the function receives a function to emit the mapped records. If it is omitted, such triggers are ignored. -- @return true on success, or false on failure. function db:mapreduce(map, reduce, tmppath, opts, dbnum, clim, cbnum, log, proc) end --- Create a cursor object. -- @return the return value is the created cursor object. Each cursor should be disabled with the Cursor#disable method when it is no longer in use. function db:cursor() end --- Process a cursor by a functor. -- @param proc the functor of operations for the cursor. The cursor is disabled implicitly after the block. -- @return always nil. function db:cursor_process(proc) end --- Create three objects for the generic "for" loop. -- @return multiple values composed of the "next" functor, the database object itself, and nil. function db:pairs() end -- END OF FILE ������������������������������������������������������������������������������������������kyototycoon-0.9.56/cmdcommon.h����������������������������������������������������������������������0000644�0001750�0001750�00000027671�11757471602�015372� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/************************************************************************************************* * Common symbols for command line utilities * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see <http://www.gnu.org/licenses/>. *************************************************************************************************/ #ifndef _CMDCOMMON_H // duplication check #define _CMDCOMMON_H #include <ktcommon.h> #include <ktutil.h> #include <ktsocket.h> #include <ktthserv.h> #include <kthttp.h> #include <ktrpc.h> #include <ktulog.h> #include <ktshlib.h> #include <kttimeddb.h> #include <ktdbext.h> #include <ktremotedb.h> #include <ktplugserv.h> #include <ktplugdb.h> #include "myscript.h" namespace kc = kyotocabinet; namespace kt = kyototycoon; // constants const int32_t OPENDBMAX = 200; // maximum number of open databases const int32_t THREADMAX = 64; // maximum number of threads const size_t RECBUFSIZ = 64; // buffer size for a record const size_t RECBUFSIZL = 1024; // buffer size for a long record const size_t LINEBUFSIZ = 8192; // buffer size for a line const double DEFTOUT = 30; // default networking timeout const int32_t DEFTHNUM = 16; // default number of threads const double DEFRIV = 0.04; // default interval of replication const int64_t DEFULIM = 256LL << 20; // default limit size of update log file const double DEFBGSI = 180; // default interval of background saver const char* const BGSPATHEXT = "ktss"; // extension of a snapshot file // global variables uint64_t g_rnd_x = 123456789; uint64_t g_rnd_y = 362436069; uint64_t g_rnd_z = 521288629; uint64_t g_rnd_w = 88675123; // function prototypes void mysrand(int64_t seed); int64_t myrand(int64_t range); int64_t memusage(); void oprintf(const char* format, ...); void oputchar(char c); void eprintf(const char* format, ...); void printversion(); void printdata(const char* buf, int32_t size, bool px); bool mygetline(std::istream* is, std::string* str); std::string unitnumstr(int64_t num); std::string unitnumstrbyte(int64_t num); kt::RPCServer::Logger* stdlogger(const char* prefix, std::ostream* strm); kc::BasicDB::Logger* stddblogger(const char* prefix, std::ostream* strm); void printdb(kc::BasicDB* db, bool px = false); // checker to show progress by printing dots class DotChecker : public kc::BasicDB::ProgressChecker { public: explicit DotChecker(std::ostream* strm, int64_t freq) : strm_(strm), freq_(freq), cnt_(0) {} int64_t count() { return cnt_; } private: bool check(const char* name, const char* message, int64_t curcnt, int64_t allcnt) { if (std::strcmp(message, "processing") || freq_ == 0) return true; if (freq_ < 0) { cnt_++; if (cnt_ % -freq_ == 0) { oputchar('.'); if (cnt_ % (-freq_ * 50) == 0) oprintf(" (%lld)\n", (long long)cnt_); } } else { if (curcnt > cnt_) { cnt_ = curcnt; if (cnt_ % freq_ == 0) { oputchar('.'); if (cnt_ % (freq_ * 50) == 0) oprintf(" (%lld)\n", (long long)cnt_); } } } return true; } std::ostream* strm_; int64_t freq_; int64_t cnt_; }; // update logger for timed database. class DBUpdateLogger : public kt::TimedDB::UpdateTrigger { public: explicit DBUpdateLogger() : ulog_(NULL), sid_(0), dbid_(0), rsid_(), tran_(false), trlock_(), trcache_() {} void initialize(kt::UpdateLogger* ulog, uint16_t sid, uint16_t dbid) { ulog_ = ulog; sid_ = sid; dbid_ = dbid; } void trigger(const char* mbuf, size_t msiz) { int32_t rsid = (int32_t)(intptr_t)rsid_.get(); uint16_t sid = rsid == 0 ? sid_ : (uint16_t)(rsid - 1); size_t nsiz = sizeof(sid) + sizeof(dbid_) + msiz; char* nbuf = new char[nsiz]; char* wp = nbuf; kc::writefixnum(wp, sid, sizeof(sid)); wp += sizeof(sid); kc::writefixnum(wp, dbid_, sizeof(dbid_)); wp += sizeof(dbid_); std::memcpy(wp, mbuf, msiz); if (tran_) { trlock_.lock(); trcache_.push_back(std::string(nbuf, nsiz)); delete[] nbuf; trlock_.unlock(); } else { ulog_->write_volatile(nbuf, nsiz); } } void begin_transaction() { tran_ = true; } void end_transaction(bool commit) { if (commit && !trcache_.empty()) ulog_->write_bulk(trcache_); trcache_.clear(); tran_ = false; } void set_rsid(uint16_t sid) { rsid_.set((void*)(intptr_t)(sid + 1)); } void clear_rsid() { rsid_.set(0); } static const char* parse(const char* mbuf, size_t msiz, size_t* sp, uint16_t* sidp, uint16_t* dbidp) { if (msiz < sizeof(uint16_t) + sizeof(uint16_t)) return NULL; const char* rp = mbuf; *sidp = kc::readfixnum(rp, sizeof(uint16_t)); rp += sizeof(uint16_t); *dbidp = kc::readfixnum(rp, sizeof(uint16_t)); rp += sizeof(uint16_t); *sp = msiz - sizeof(uint16_t) - sizeof(uint16_t); return rp; } private: kt::UpdateLogger* ulog_; uint16_t sid_; uint16_t dbid_; kc::TSDKey rsid_; bool tran_; kc::SpinLock trlock_; std::vector<std::string> trcache_; }; // get the random seed inline void mysrand(int64_t seed) { g_rnd_x = seed; for (int32_t i = 0; i < 16; i++) { myrand(1); } } // get a random number inline int64_t myrand(int64_t range) { uint64_t t = g_rnd_x ^ (g_rnd_x << 11); g_rnd_x = g_rnd_y; g_rnd_y = g_rnd_z; g_rnd_z = g_rnd_w; g_rnd_w = (g_rnd_w ^ (g_rnd_w >> 19)) ^ (t ^ (t >> 8)); return (g_rnd_w & kc::INT64MAX) % range; } // get the current memory usage inline int64_t memusage() { std::map<std::string, std::string> info; kc::getsysinfo(&info); return kc::atoi(info["mem_rss"].c_str()); } // print formatted information string and flush the buffer inline void oprintf(const char* format, ...) { std::string msg; va_list ap; va_start(ap, format); kc::vstrprintf(&msg, format, ap); va_end(ap); std::cout << msg; std::cout.flush(); } // print a character and flush the buffer inline void oputchar(char c) { std::cout << c; std::cout.flush(); } // print formatted error string and flush the buffer inline void eprintf(const char* format, ...) { std::string msg; va_list ap; va_start(ap, format); kc::vstrprintf(&msg, format, ap); va_end(ap); std::cerr << msg; std::cerr.flush(); } // print the versin information inline void printversion() { oprintf("Kyoto Tycoon %s (%d.%d) on %s (Kyoto Cabinet %s)\n", kt::VERSION, kt::LIBVER, kt::LIBREV, kc::OSNAME, kc::VERSION); } // print record data inline void printdata(const char* buf, int32_t size, bool px) { size_t cnt = 0; char numbuf[kc::NUMBUFSIZ]; while (size-- > 0) { if (px) { if (cnt++ > 0) putchar(' '); std::sprintf(numbuf, "%02X", *(unsigned char*)buf); std::cout << numbuf; } else { std::cout << *buf; } buf++; } } // read a line from a file descriptor inline bool mygetline(std::istream* is, std::string* str) { str->clear(); bool hit = false; char c; while (is->get(c)) { hit = true; if (c == '\0' || c == '\r') continue; if (c == '\n') break; str->append(1, c); } return hit; } // convert a number into the string with the decimal unit inline std::string unitnumstr(int64_t num) { if (num >= std::pow(1000.0, 6)) { return kc::strprintf("%.3Lf quintillion", (long double)num / std::pow(1000.0, 6)); } else if (num >= std::pow(1000.0, 5)) { return kc::strprintf("%.3Lf quadrillion", (long double)num / std::pow(1000.0, 5)); } else if (num >= std::pow(1000.0, 4)) { return kc::strprintf("%.3Lf trillion", (long double)num / std::pow(1000.0, 4)); } else if (num >= std::pow(1000.0, 3)) { return kc::strprintf("%.3Lf billion", (long double)num / std::pow(1000.0, 3)); } else if (num >= std::pow(1000.0, 2)) { return kc::strprintf("%.3Lf million", (long double)num / std::pow(1000.0, 2)); } else if (num >= std::pow(1000.0, 1)) { return kc::strprintf("%.3Lf thousand", (long double)num / std::pow(1000.0, 1)); } return kc::strprintf("%lld", (long long)num); } // convert a number into the string with the byte unit inline std::string unitnumstrbyte(int64_t num) { if ((unsigned long long)num >= 1ULL << 60) { return kc::strprintf("%.3Lf EiB", (long double)num / (1ULL << 60)); } else if ((unsigned long long)num >= 1ULL << 50) { return kc::strprintf("%.3Lf PiB", (long double)num / (1ULL << 50)); } else if ((unsigned long long)num >= 1ULL << 40) { return kc::strprintf("%.3Lf TiB", (long double)num / (1ULL << 40)); } else if ((unsigned long long)num >= 1ULL << 30) { return kc::strprintf("%.3Lf GiB", (long double)num / (1ULL << 30)); } else if ((unsigned long long)num >= 1ULL << 20) { return kc::strprintf("%.3Lf MiB", (long double)num / (1ULL << 20)); } else if ((unsigned long long)num >= 1ULL << 10) { return kc::strprintf("%.3Lf KiB", (long double)num / (1ULL << 10)); } return kc::strprintf("%lld B", (long long)num); } // get the logger into the standard stream inline kt::RPCServer::Logger* stdlogger(const char* prefix, std::ostream* strm) { class LoggerImpl : public kt::RPCServer::Logger { public: explicit LoggerImpl(std::ostream* strm, const char* prefix) : strm_(strm), prefix_(prefix) {} void log(Kind kind, const char* message) { const char* kstr = "MISC"; switch (kind) { case kt::RPCServer::Logger::DEBUG: kstr = "DEBUG"; break; case kt::RPCServer::Logger::INFO: kstr = "INFO"; break; case kt::RPCServer::Logger::SYSTEM: kstr = "SYSTEM"; break; case kt::RPCServer::Logger::ERROR: kstr = "ERROR"; break; } *strm_ << prefix_ << ": [" << kstr << "]: " << message << std::endl; } private: std::ostream* strm_; const char* prefix_; }; static LoggerImpl logger(strm, prefix); return &logger; } // get the database logger into the standard stream inline kc::BasicDB::Logger* stddblogger(const char* prefix, std::ostream* strm) { class LoggerImpl : public kc::BasicDB::Logger { public: explicit LoggerImpl(std::ostream* strm, const char* prefix) : strm_(strm), prefix_(prefix) {} void log(const char* file, int32_t line, const char* func, Kind kind, const char* message) { const char* kstr = "MISC"; switch (kind) { case kc::BasicDB::Logger::DEBUG: kstr = "DEBUG"; break; case kc::BasicDB::Logger::INFO: kstr = "INFO"; break; case kc::BasicDB::Logger::WARN: kstr = "WARN"; break; case kc::BasicDB::Logger::ERROR: kstr = "ERROR"; break; } *strm_ << prefix_ << ": [" << kstr << "]: " << file << ": " << line << ": " << func << ": " << message << std::endl; } private: std::ostream* strm_; const char* prefix_; }; static LoggerImpl logger(strm, prefix); return &logger; } // print all record of a database inline void printdb(kc::BasicDB* db, bool px) { class Printer : public kc::DB::Visitor { public: explicit Printer(bool px) : px_(px) {} private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp) { printdata(kbuf, ksiz, px_); oputchar('\t'); printdata(vbuf, vsiz, px_); oputchar('\n'); return NOP; } bool px_; } printer(px); db->iterate(&printer, false); } #endif // duplication check // END OF FILE �����������������������������������������������������������������������kyototycoon-0.9.56/doc/�����������������������������������������������������������������������������0000755�0001750�0001750�00000000000�11757471600�013773� 5����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/doc/common.css�������������������������������������������������������������������0000644�0001750�0001750�00000006050�11607337351�015774� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������/* * Style Sheets commonly used by documents of Kyoto Cabinet */ html { margin: 0ex 0ex; padding: 0ex 0ex; text-align:center; background: #f8f8f8 none; } body { display: inline-block; text-align: left; max-width: 100ex; margin: 1ex 1ex; padding: 0ex 0ex; color: #111111; } hr { margin: 4.0ex 0ex 1.5ex 0ex; height: 1px; border: none; background: #999999 none; color: #999999; } h1,h2,h3,h4,h5,h6 { font-weight: bold; } h1 { margin: 2.0ex 0ex 1.3ex 0ex; padding: 0ex 0ex; font-size: 130%; color: #000000; } h2 { margin: 2.0ex 0ex 1.0ex 0.2ex; padding: 0.5ex 0.8ex; border-left: solid 0.8ex #889999; border-bottom: solid 1px #cccccc; font-size: 125%; color: #000011; } h3 { margin: 1.6ex 0ex 0.5ex 0.2ex; padding: 0ex 0ex; font-size: 105%; color: #001111; } p { margin: 0.8ex 0ex; line-height: 140%; text-indent: 1.4ex; } div,pre,table { margin: 0.8ex 1.5ex; } div.note,div.navi { text-align: right; margin: 0ex 0.5ex; color: #333333; } span.void { color: #888888; } div.logo { text-align: center; margin: 4ex 0ex; } div.logo img { border: inset 2px #ccccdd; } div.illust { margin: 1ex 0ex; text-align: center; } div.illust img { border: solid 1px #ccccdd; } pre { padding: 0.2ex; background-color: #eeeef8; border: 1px solid #ddddee; font-size: 90%; } li,dt,dd { line-height: 130%; } dt { margin-left: 2.0ex; } dd { margin-left: 4.0ex; text-indent: -0.5ex; } dl.api dd { margin-left: 5.0ex; font-size: 95%; color: #333333; } ul { margin: 0.8ex 4.0ex; padding: 0ex; } ul.options { list-style-type: none; margin: 0.8ex 3.0ex; font-size: 95%; color: #333333; } ul ul { margin-top: 0ex; margin-bottom: 0ex; } table { border-collapse: collapse; } th,td { text-align: left; vertical-align: top; padding: 0.2ex 0.8ex; } td { border: solid 1px #aaaabb; font-size: 95%; } td.label { border: none; font-size: 80%; color: #333333; } td.number { text-align: right; } td div { margin: 0ex; } a { color: #0022aa; text-decoration: none; } a:hover,a:focus { color: #0033ee; text-decoration: underline; } code,kbd { font-style: normal; font-weight: bold; font-size: 100%; color: #001111; } var { padding: 0ex 0.25ex 0ex 0ex; font-style: italic; color: #001122; } @media (max-device-width:480px) { body { max-width: none; margin: 2ex 2ex; } } @media print { html,body { margin: 0ex 0ex; background-color: #ffffff; color: #000000; } h1 { padding: 8ex 0ex 0.5ex 0ex; text-align: center; } h2 { page-break-before: always; } div.note { text-align: center; } div.navi,div.logo { display: none; } hr { display: none; } pre { margin: 1.2ex 1.2ex; background-color: #ffffff; border: 1px solid #cccccc; } a,code,kbd { color: #000000; text-decoration: none; } h1,h2,h3 { font-family: sans-serif; } p,div,li,dt,dd { font-family: serif; } pre,code,kbd { font-family: monospace; } dd { font-size: 90%; } } /* END OF FILE */ ����������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������kyototycoon-0.9.56/doc/command.html�����������������������������������������������������������������0000644�0001750�0001750�00000111120�11757471566�016306� 0����������������������������������������������������������������������������������������������������ustar �mikio���������������������������mikio������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������������<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"> <head> <meta http-equiv="Content-Language" content="en" /> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Content-Style-Type" content="text/css" /> <meta name="author" content="FAL Labs" /> <meta name="keywords" content="Kyoto Tycoon, kyototycoon, database, DBM" /> <meta name="description" content="Specifications of command line utilities" /> <link rel="contents" href="./" /> <link rel="stylesheet" href="common.css" /> <link rel="icon" href="icon16.png" /> <link rev="made" href="mailto:info@fallabs.com" /> <title>Kyoto Tycoon

Specificatoins of Command Line Utilities of Kyoto Tycoon

Copyright (C) 2009-2012 FAL Labs
Last Update: Fri, 25 May 2012 02:44:22 +0900

This document describes how to use command line utilities. They are useful to manage database contents and to test the library and its applications.

  1. ktserver : to run the database server.
  2. ktutiltest : to test the utility functions.
  3. ktutilmgr : miscellaneous utilities.
  4. ktutilserv : to test the server tool kit.
  5. kctimedtest : to test the timed database.
  6. kctimedmgr : to manage the timed database.
  7. ktremotetest : to test the remote database.
  8. ktremotemgr : to manage the remote database.

ktserver

The command `ktserver' runs the server managing database instances. This command is used in the following format. `db' specifies a database name. If no database is specified, an unnamed on-memory database is opened.

ktserver [-host str] [-port num] [-tout num] [-th num] [-log file] [-li|-ls|-le|-lz] [-ulog dir] [-ulim num] [-uasi num] [-sid num] [-ord] [-oat|-oas|-onl|-otl|-onr] [-asi num] [-ash] [-bgs dir] [-bgsi num] [-bgc str] [-dmn] [-pid file] [-scr file] [-mhost str] [-mport num] [-rts file] [-riv num] [-plsv file] [-plex str] [-pldb file] [db...]

Options feature the following.

  • -host str : specifies the host name of the server.
  • -port num : specifies the port number of the server.
  • -tout num : specifies the timeout in seconds.
  • -th num : specifies the number of worker threads. By default, it is 16.
  • -log file : specifies the path of the log file. By default, logs are written into the standard output.
  • -li : sets the logging level "INFO".
  • -ls : sets the logging level "SYSTEM".
  • -le : sets the logging level "ERROR".
  • -lz : sets the logging level "NONE".
  • -ulog dir : specifies the path of the update log directory. By default, it is disabled.
  • -ulim num : specifies the limit size of each update log file.
  • -uasi num : specifies the interval of synchronization of update log files. By default, it is disabled.
  • -sid num : specifies the server ID number.
  • -ord : opens the database as a reader.
  • -oat : opens the database with the auto transaction option.
  • -oas : opens the database with the auto synchronization option.
  • -onl : opens the database with the no locking option.
  • -otl : opens the database with the try locking option.
  • -onr : opens the database with the no auto repair option.
  • -asi num : specifies the interval of auto synchronization. By default, it is disabled.
  • -ash : does physical synchronization while auto synchronization.
  • -bgs dir : specifies the path of the background snapshot directory. By default, it is disabled.
  • -bgsi num : specifies the interval of background snapshotting. By default, it is 180.
  • -bgsc str : specifies the compression algorithm of the snapshot. "zlib", "lzo", are "lzma" are supported.
  • -dmn : switches to a daemon process.
  • -pid file : specifies the file to contain the process ID to send signals by.
  • -cmd dir : specifies the command search path for outer commands. By default, it is the current directroy.
  • -scr file : specifies the script file for the scripting extention.
  • -mhost str : specifies the host name of the master server of replication.
  • -mport num : specifies the port number of the master server of replication.
  • -rts file : specifies the file to contain the replication time stamp.
  • -riv num : specifies the interval of each replication operation in milliseconds. By default, it is 0.04.
  • -plsv file : specifies the shared library file of a pluggable server.
  • -plex str : specifies the configuration expression of a pluggable server.
  • -pldb file : specifies the shared library file of a pluggable database.

This command returns 0 on success, another on failure.

To finish the server process running on foreground, input `Ctrl-C' on the terminal. To finish the server process running as a daemon, send a termination signal such as SIGTERM by the `kill' command. If a daemon process catches SIGHUP, the server restarts and the log file is re-opened. Because thr current directory of a daemon process is changed to the root directory, paths of related files should be described as their absolute paths.

The naming convention of database name is the same as polymorphic database of Kyoto Cabinet. If it is "-", the database will be a prototype hash database. If it is "+", the database will be a prototype tree database. If it is ":", the database will be a stash database. If it is "*", the database will be a cache hash database. If it is "%", the database will be a cache tree database. If its suffix is ".kch", the database will be a file hash database. If its suffix is ".kct", the database will be a file tree database. If its suffix is ".kcd", the database will be a directory hash database. If its suffix is ".kcf", the database will be a directory tree database. Tuning parameters can trail the name, separated by "#". Each parameter is composed of the name and the value, separated by "=". If the "type" parameter is specified, the database type is determined by the value in "-", "+", ":", "*", "%", "kch", "kct", "kcd", and "kcf". All database types support the logging parameters of "log", "logkinds", and "logpx". The prototype hash database and the prototype tree database do not support any other tuning parameter. The stash database supports "bnum". The cache hash database supports "opts", "bnum", "zcomp", "capcnt", "capsiz", and "zkey". The cache tree database supports all parameters of the cache hash database except for capacity limitation, and supports "psiz", "rcomp", "pccap" in addition. The file hash database supports "apow", "fpow", "opts", "bnum", "msiz", "dfunit", "zcomp", and "zkey". The file tree database supports all parameters of the file hash database and "psiz", "rcomp", "pccap" in addition. The directory hash database supports "opts", "zcomp", and "zkey". The directory tree database supports all parameters of the directory hash database and "psiz", "rcomp", "pccap" in addition.

Furthermore, several parameters are added by Kyoto Tycoon. "ktopts" sets options and the value can contain "p" for the persistent option. "ktcapcnt" sets the capacity by record number. "ktcapsiz" sets the capacity by database size.


ktutiltest

The command `ktutiltest' is a utility for facility test and performance test of the utility functions. This command is used in the following format. `url' specifies the target URL. `rnum' specifies the number of iterations. `proc' specifies the name of the procedure to call. `name' and `value' specify a pair of the key and the value of an input parameter. `path' specifies the path of a repository.

ktutiltest http [-th num] [-get|-head|-post|-put|-delete] [-body file] [-ah name value] [-qs name value] [-tout num] [-ka] url rnum
Performs test of HTTP sessions.
ktutiltest rpc [-th num] [-host str] [-port num] [-tout num] proc rnum [name value ...]
Performs test of RPC sessions.
ktutiltest ulog [-th num] [-ulim num] path rnum [name value ...]
Performs test of update logging.

Options feature the following.

  • -th num : specifies the number of worker threads.
  • -get : uses the GET method.
  • -head : uses the HEAD method.
  • -post : uses the POST method.
  • -put : uses the PUT method.
  • -delete : uses the DELETE method.
  • -body file : sends the entity body of the content the file.
  • -ah name value : adds an HTTP header.
  • -qs name value : adds a key/value pair to the query string.
  • -tout num : specifies the timeout in seconds.
  • -ka : use keep-alive connection.
  • -host str : specifies the host name of the server.
  • -port num : specifies the port number of the server.
  • -ulim num : specifies the limit size of each update log file.

This command returns 0 on success, another on failure.


ktutilmgr

The command `ktutilmgr' is a tool of miscellaneous utilities, and to show the configuration. This command is used in the following format. `url' specifies the target URL. `proc' specifies the name of the procedure to call. `name' and `value' specify a pair of the key and the value of an input parameter. `path' specifies the path of a repository.

ktutilmgr date [-ds str] [-jl num] [-wf] [-rf]
Prints date information. By default, prints the current UNIX time.
ktutilmgr http [-get|-head|-post|-put|-delete] [-body file] [-ah name value] [-qs name value] [-tout num] [-ph] [-ec num] url
Performs an HTTP session.
ktutilmgr rpc [-host str] [-port num] [-tout num] [-ienc str] [-oenc str] proc [name value ...]
Performs an RPC session.
ktutilmgr ulog [-ts num] [-uw] [-uf] path
Prints update logs.
ktutilmgr conf [-v|-i|-l|-p]
Shows the configuration of Kyoto Tycoon.
ktutilmgr version
Shows the version information of Kyoto Tycoon.

Options feature the following.

  • -ds str : specifies the datetime string.
  • -jl num : specifies the jet lag.
  • -wf : formats the output in W3CDTF.
  • -rf : formats the output in RFC 1123 format.
  • -get : uses the GET method.
  • -head : uses the HEAD method.
  • -post : uses the POST method.
  • -put : uses the PUT method.
  • -delete : uses the DELETE method.
  • -body file : sends the entity body of the content the file.
  • -ah name value : adds an HTTP header.
  • -qs name value : adds a key/value pair to the query string.
  • -tout num : specifies the timeout in seconds.
  • -ph : prints response headers.
  • -ec num : reports error if the response code is not the same as the expected.
  • -host str : specifies the host name of the server.
  • -port num : specifies the port number of the server.
  • -ienc str : specifies the encoding of the input data.
  • -oenc str : specifies the encoding of the output data.
  • -ts num : specifies the maximum time stamp of already read logs. "now" means the current time stamp.
  • -uw : waits for update forever.
  • -uf : prints status of each update log file.
  • -v : show the version number of Kyoto Tycoon.
  • -i : show options to include the headers of Tokyo Tycoon.
  • -l : show options to link the library of Tokyo Tycoon.
  • -p : show the directory path of the commands.

This command returns 0 on success, another on failure.


ktutilserv

The command `ktutilserv' is a utility for facility test and performance test of the server tool kit. This command is used in the following format. `basedir' specifies the document root directory.

ktutilserv echo [-host str] [-port num] [-tout num]
Runs the single-threaded echo server.
ktutilserv mtecho [-host str] [-port num] [-tout num] [-th num] [-li|-ls|-le|-lz]
Runs the multi-threaded echo server.
ktutilserv http [-host str] [-port num] [-tout num] [-th num] [-li|-ls|-le|-lz] [basedir]
Runs the HTTP server.
ktutilserv rpc [-host str] [-port num] [-tout num] [-th num] [-li|-ls|-le|-lz]
Runs the RPC server.

Options feature the following.

  • -host str : specifies the host name of the server.
  • -port num : specifies the port number of the server.
  • -tout num : specifies the timeout in seconds.
  • -th num : specifies the number of worker threads. By default, it is 16.
  • -li : sets the logging level "INFO".
  • -ls : sets the logging level "SYSTEM".
  • -le : sets the logging level "ERROR".
  • -lz : sets the logging level "NONE".

This command returns 0 on success, another on failure.


kttimedtest

The command `kttimedtest' is a utility for facility test and performance test of the timed database. This command is used in the following format. `path' specifies the path of a database file. `rnum' specifies the number of iterations.

kttimedtest order [-th num] [-rnd] [-set|-get|-getw|-rem|-etc] [-tran] [-oat|-onl|-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-lv] path rnum
Performs in-order tests.
kttimedtest queue [-th num] [-it num] [-rnd] [-oat|-onl|-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-lv] path rnum
Performs queuing operations.
kttimedtest wicked [-th num] [-it num] [-oat|-onl|-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-lv] path rnum
Performs mixed operations selected at random.
kttimedtest tran [-th num] [-it num] [-hard] [-oat|-onl|-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-lv] path rnum
Performs test of transaction.
kctimedtest mapred [-rnd] [-ru] [-oat|-onl|-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-lv] [-tmp str] [-dbnum num] [-clim num] [-cbnum num] [-xnl] [-xpm] [-xpr] [-xpf] [-xnc] path rnum
Performs MapReduce operations.
kttimedtest misc path
Performs miscellaneous tests.

Options feature the following.

  • -th num : specifies the number of worker threads.
  • -rnd : performs random test.
  • -set : performs setting operation only.
  • -get : performs getting operation only.
  • -getw : performs getting with a buffer operation only.
  • -rem : performs removing operation only.
  • -etc : performs miscellaneous operations.
  • -tran : performs transaction.
  • -oat : opens the database with the auto transaction option.
  • -oas : opens the database with the auto synchronization option.
  • -onl : opens the database with the no locking option.
  • -otl : opens the database with the try locking option.
  • -onr : opens the database with the no auto repair option.
  • -ulog str : specifies the update log directory.
  • -ulim num : specifies the limit size of each update log file.
  • -sid num : specifies the server ID number.
  • -dbid num : specifies the database ID number.
  • -lv : reports all errors.
  • -it num : specifies the number of repetition.
  • -hard : performs physical synchronization.
  • -ru : reuses the existing database.
  • -tmp str : specifies the path of a directory for temporary storage.
  • -dbnum num : specifies the number of temporary databases.
  • -clim num : specifies the limit size of cache memory.
  • -cbnum num : specifies the bucket number of cache memory.
  • -xnl : executes with the no locking option.
  • -xpm : executes with the parallel mapper option.
  • -xpr : executes with the parallel reducer option.
  • -xpf : executes with the parallel flusher option.
  • -xnc : executes with the no compression option.

This command returns 0 on success, another on failure.


kttimedmgr

The command `kttimedmgr' is a utility for test and debugging of the timed database and its applications. `path' specifies the path of a database file. `key' specifies the key of a record. `value' specifies the value of a record. `file' specifies the input/output file. `dir' specifies the input/output directory. `src' specifies other database files.

kttimedmgr create [-otr] [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] path
Creates a database file.
kttimedmgr inform [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-st] path
Prints status information.
kttimedmgr set [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-add|-app|-rep|-inci|-incd] [-sx] [-xt num] path key value
Stores a record.
kttimedmgr remove [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-sx] path key
Removes a record.
kttimedmgr get [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-rm] [-sx] [-px] [-pt] [-pz] path key
Prints the value of a record.
kttimedmgr list [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-des] [-max num] [-rm] [-sx] [-pv] [-px] [-pt] path [key]
Prints keys of all records, separated by line feeds.
kttimedmgr clear [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] path
Removes all records of a database.
kttimedmgr import [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-sx] [-xt num] path [file]
Imports records from a TSV file.
kttimedmgr copy [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] path file
Copies the whole database.
kttimedmgr dump [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] path [file]
Dumps records into a snapshot file.
kttimedmgr load [-otr] [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] path [file]
Loads records from a snapshot file.
kttimedmgr vacuum [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] path
Eliminates regions of expired records.
kttimedmgr recover [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-ts num] path dir
Recover the database with update log data.
kttimedmgr merge [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] [-add|-app|-rep] path src...
Merge records from other databases.
kttimedmgr check [-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num] path
Checks consistency.
kttimedmgr bgsinform file
Prints status information of background snapshot files.

Options feature the following.

  • -otr : opens the database with the truncation option.
  • -onl : opens the database with the no locking option.
  • -otl : opens the database with the try locking option.
  • -onr : opens the database with the no auto repair option.
  • -ulog str : specifies the update log directory.
  • -ulim num : specifies the limit size of each update log file.
  • -sid num : specifies the server ID number.
  • -dbid num : specifies the database ID number.
  • -st : prints miscellaneous information.
  • -add : performs adding operation.
  • -app : performs appending operation.
  • -rep : performs replacing operation.
  • -inci : performs integer increment operation.
  • -incd : performs real number increment operation.
  • -sx : the input data is evaluated as a hexadecimal data string.
  • -xt num : specifies the expiration time.
  • -rm : removes the record.
  • -px : the output data is converted into a hexadecimal data string.
  • -pt : prints the expiration time also.
  • -pz : does not append line feed at the end of the output.
  • -des : visits records in descending order.
  • -max num : specifies the maximum number of shown records.
  • -pv : prints values of records also.
  • -ts num : specifies the maximum time stamp of already read logs. "now" means the current time stamp.

This command returns 0 on success, another on failure.


ktremotetest

The command `ktremotetest' is a utility for facility test and performance test of the remote database. This command is used in the following format. `rnum' specifies the number of iterations.

ktremotetest order [-th num] [-rnd] [-set|-get|-rem|-etc] [-host str] [-port num] [-tout num] rnum
Performs in-order tests.
ktremotetest bulk [-th num] [-bin] [-rnd] [-set|-get|-rem|-etc] [-bulk num] [-host str] [-port num] [-tout num] [-bnr] rnum
Performs bulk operation tests.
ktremotetest wicked [-th num] [-it num] [-host str] [-port num] [-tout num] rnum
Performs mixed operations selected at random.
ktremotetest usual [-th num] [-it num] [-host str] [-port num] [-tout num] [-kp num] [-vs num] [-xt num] [-iv num] rnum
Performs mixed operations to simulate usual use cases.

Options feature the following.

  • -th num : specifies the number of worker threads.
  • -rnd : performs random test.
  • -set : performs setting operation only.
  • -get : performs getting operation only.
  • -rem : performs removing operation only.
  • -etc : performs miscellaneous operations.
  • -host str : specifies the host name of the server.
  • -port num : specifies the port number of the server.
  • -tout num : specifies the timeout in seconds.
  • -bin : uses the binary protocol.
  • -bulk num : specifies the number of records in a bulk operation.
  • -bnr : enables the no-reply option in the binary protocol.
  • -it num : specifies the number of repetition.
  • -kp num : specifies the number of patterns of keys.
  • -vs num : specifies the size of each value.
  • -xt num : specifies the expiration date.
  • -iv num : specifies the interval of each operation in milliseconds.

This command returns 0 on success, another on failure.


ktremotemgr

The command `ktremotedmgr' is a utility for test and debugging of the remote database and its applications. `proc' specifies the name of a procedure. `params' specifies arbitrary parameters. `mhost' specifies the host name of the master server. `key' specifies the key of a record. `value' specifies the value of a record.

ktremotemgr report [-host str] [-port num] [-tout num]
Prints statistics of the server.
ktremotemgr script [-host str] [-port num] [-tout num] [-bin] [-swname str] [-swtime num] [-ssname str] [-ssbrd] proc [params...]
Calls a procedure of the scripting extension.
ktremotemgr tunerepl [-host str] [-port num] [-tout num] [-mport str] [-ts num] [-iv num] [mhost]
Sets the replication configuration.
ktremotemgr inform [-host str] [-port num] [-tout num] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-st]
Prints status information of a database.
ktremotemgr clear [-host str] [-port num] [-tout num] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str]
Removes all records of a database.
ktremotemgr sync [-host str] [-port num] [-tout num] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-hard] [-cmd str]
Synchronizes updated contents with the file and the device.
ktremotemgr set [-host str] [-port num] [-tout num] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-add|-rep|-app|-inci|-incd] [-sx] [-xt num] key value
Stores a record.
ktremotemgr remove [-host str] [-port num] [-tout num] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-sx] key
Removes a record.
ktremotemgr get [-host str] [-port num] [-tout num] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-rm] [-sx] [-px] [-pt] [-pz] key
Prints the value of a record.
ktremotemgr list [-host str] [-port num] [-tout num] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-des] [-max num] [-rm] [-sx] [-pv] [-px] [-pt] [key]
Prints keys of all records, separated by line feeds.
ktremotemgr import [-host str] [-port num] [-tout num] [-db str] [-sx] [-xt num] [file]
Imports records from a TSV file.
ktremotemgr vacuum [-host str] [-port num] [-tout num] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-step num] path
Eliminates regions of expired records.
ktremotemgr slave [-host str] [-port num] [-tout num] [-ts num] [-sid num] [-ux] [-uw] [-uf] [-ur]
Simulates a client of replication and prints update logs.
ktremotemgr setbulk [-host str] [-port num] [-tout num] [-bin] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-sx] [-xt num] key value ...
Store records at once.
ktremotemgr removebulk [-host str] [-port num] [-tout num] [-bin] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-sx] key ...
Remove records at once.
ktremotemgr getbulk [-host str] [-port num] [-tout num] [-bin] [-swname str] [-swtime num] [-ssname str] [-ssbrd] [-db str] [-sx] [-px] key ...
Retrieve records at once.

Options feature the following.

  • -host str : specifies the host name of the server.
  • -port num : specifies the port number of the server.
  • -tout num : specifies the timeout in seconds.
  • -swname str : waits for a signal by a named condition variable.
  • -swtime num : specifies the timeout of signal waiting in seconds.
  • -ssname str : sends a signal to a named condition variable.
  • -ssbrd : switches signal sending to broadcasting.
  • -bin : uses the binary protocol.
  • -mport num : specifies the port number of the master server.
  • -ts num : specifies the maximum time stamp of already read logs. "now" means the current time stamp.
  • -iv num : specifies the interval of each replication operation in milliseconds.
  • -db str : specifies the target database.
  • -st : prints miscellaneous information.
  • -hard : performs physical synchronization with the device.
  • -cmd str : specifies an outer command for postprocessing.
  • -add : performs adding operation.
  • -app : performs appending operation.
  • -rep : performs replacing operation.
  • -inci : performs integer increment operation.
  • -incd : performs real number increment operation.
  • -sx : the input data is evaluated as a hexadecimal data string.
  • -xt num : specifies the expiration time.
  • -rm : removes the record.
  • -px : the output data is converted into a hexadecimal data string.
  • -pt : prints the expiration time also.
  • -pz : does not append line feed at the end of the output.
  • -des : visits records in descending order.
  • -max num : specifies the maximum number of shown records.
  • -pv : prints values of records also.
  • -step num : specifies the number of steps.
  • -sid num : specifies the server ID number.
  • -ux : fetches update logs of the specified server ID number only.
  • -uw : waits for update forever.
  • -uf : prints status of each update log file.
  • -ur : remove old update log files.

This command returns 0 on success, another on failure.


kyototycoon-0.9.56/doc/api/0000755000175000017500000000000011757471600014544 5ustar mikiomikiokyototycoon-0.9.56/doc/api/structkyototycoon_1_1RemoteDB_1_1BulkRecord-members.html0000644000175000017500000000715511757471600027377 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RemoteDB::BulkRecord Member List
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1PluggableDB.html0000644000175000017500000000773411757471600023565 0ustar mikiomikio Kyoto Tycoon: kyototycoon::PluggableDB Class Reference
kyototycoon::PluggableDB Class Reference

Interface of pluggable database abstraction. More...

#include <ktplugdb.h>

List of all members.

Public Member Functions

virtual ~PluggableDB ()
 Destructor.

Detailed Description

Interface of pluggable database abstraction.


Constructor & Destructor Documentation

Destructor.

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer.html0000644000175000017500000006276511757471600024371 0ustar mikiomikio Kyoto Tycoon: kyototycoon::ThreadedServer Class Reference
kyototycoon::ThreadedServer Class Reference

Threaded TCP Server. More...

#include <ktthserv.h>

List of all members.

Classes

class  Logger
 Interface to log internal information and errors. More...
class  Session
 Interface to access each session data. More...
class  SessionTask
 Task with a session.
class  TaskQueueImpl
 Task queue implementation.
class  Worker
 Interface to process each request. More...

Public Member Functions

 ThreadedServer ()
 Default constructor.
 ~ThreadedServer ()
 Destructor.
void set_network (const std::string &expr, double timeout=-1)
 Set the network configurations.
void set_logger (Logger *logger, uint32_t kinds=Logger::SYSTEM|Logger::ERROR)
 Set the logger to process each log message.
void set_worker (Worker *worker, size_t thnum=1)
 Set the worker to process each request.
bool start ()
 Start the service.
bool stop ()
 Stop the service.
bool finish ()
 Finish the service.
void log (Logger::Kind kind, const char *format,...)
 Log a message.
void log_v (Logger::Kind kind, const char *format, va_list ap)
 Log a message.
int64_t connection_count ()
 Get the number of connections.
int64_t task_count ()
 Get the number of tasks in the queue.
bool aborted ()
 Check whether the thread is to be aborted.

Detailed Description

Threaded TCP Server.


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

void kyototycoon::ThreadedServer::set_network ( const std::string &  expr,
double  timeout = -1 
)

Set the network configurations.

Parameters:
expran expression of the address and the port of the server.
timeoutthe timeout of each network operation in seconds. If it is not more than 0, no timeout is specified.
void kyototycoon::ThreadedServer::set_logger ( Logger logger,
uint32_t  kinds = Logger::SYSTEM | Logger::ERROR 
)

Set the logger to process each log message.

Parameters:
loggerthe logger object.
kindskinds of logged messages by bitwise-or: Logger::DEBUG for debugging, Logger::INFO for normal information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error.
void kyototycoon::ThreadedServer::set_worker ( Worker worker,
size_t  thnum = 1 
)

Set the worker to process each request.

Parameters:
workerthe worker object.
thnumthe number of worker threads.

Start the service.

Returns:
true on success, or false on failure.
Note:
This function blocks until the server stops by the ThreadedServer::stop method.

Stop the service.

Returns:
true on success, or false on failure.

Finish the service.

Returns:
true on success, or false on failure.
void kyototycoon::ThreadedServer::log ( Logger::Kind  kind,
const char *  format,
  ... 
)

Log a message.

Parameters:
kindthe kind of the event. Logger::DEBUG for debugging, Logger::INFO for normal information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error.
formatthe printf-like format string. The conversion character `' can be used with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `'.
...used according to the format string.
void kyototycoon::ThreadedServer::log_v ( Logger::Kind  kind,
const char *  format,
va_list  ap 
)

Log a message.

Note:
Equal to the original Cursor::set_value method except that the last parameters is va_list.

Get the number of connections.

Returns:
the number of connections.

Get the number of tasks in the queue.

Returns:
the number of tasks in the queue.

Check whether the thread is to be aborted.

Returns:
true if the thread is to be aborted, or false if not.
kyototycoon-0.9.56/doc/api/tab_s.png0000644000175000017500000000027511757471600016346 0ustar mikiomikio‰PNG  IHDR$ÇÇ[„IDATxíÝë ‚P@áKg"%(IE|¡%¦I¡7iÚlmÐ" ÓäÛC¼ÞòÛ“\.dåOZ̤ÅBr‰/¿‰(ŸˆÎ#a6⟂ôŽ› 8q÷ØÇëÐaF-û°Et¿Aó4¯fçÖlŠ]±¶äJjJC¢%Š!¿<Å#üÀÄ«IEND®B`‚kyototycoon-0.9.56/doc/api/ktcommon_8h.html0000644000175000017500000000542411757471600017665 0ustar mikiomikio Kyoto Tycoon: ktcommon.h File Reference
ktcommon.h File Reference

common symbols for the library More...

#include <kccommon.h>
#include <kcutil.h>
#include <kcthread.h>
#include <kcdb.h>
#include <kcpolydb.h>
#include <kcdbext.h>

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.



Detailed Description

common symbols for the library

kyototycoon-0.9.56/doc/api/namespacemembers.html0000644000175000017500000002116111757471600020742 0ustar mikiomikio Kyoto Tycoon: Namespace Members
Here is a list of all documented namespace members with links to the namespaces they belong to:

- c -

- d -

- e -

- f -

- g -

- j -

- k -

- l -

- m -

- p -

- s -

- t -

- u -

- v -

- w -

- x -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer_1_1Worker-members.html0000644000175000017500000001076211757471600027641 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::ThreadedServer::Worker Member List
This is the complete list of members for kyototycoon::ThreadedServer::Worker, including all inherited members.
process(ThreadedServer *serv, Session *sess)=0kyototycoon::ThreadedServer::Worker [pure virtual]
process_finish(ThreadedServer *serv)kyototycoon::ThreadedServer::Worker [virtual]
process_idle(ThreadedServer *serv)kyototycoon::ThreadedServer::Worker [virtual]
process_start(ThreadedServer *serv)kyototycoon::ThreadedServer::Worker [virtual]
process_timer(ThreadedServer *serv)kyototycoon::ThreadedServer::Worker [virtual]
~Worker()kyototycoon::ThreadedServer::Worker [virtual]
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer_1_1Session.html0000644000175000017500000002306611757471600026364 0ustar mikiomikio Kyoto Tycoon: kyototycoon::ThreadedServer::Session Class Reference
kyototycoon::ThreadedServer::Session Class Reference

Interface to access each session data. More...

#include <ktthserv.h>

List of all members.

Classes

class  Data
 Interface of session local data. More...

Public Member Functions

uint64_t id ()
 Get the ID number of the session.
uint32_t thread_id ()
 Get the ID number of the worker thread.
void set_data (Data *data)
 Set the session local data.
Datadata ()
 Get the session local data.

Friends

class ThreadedServer

Detailed Description

Interface to access each session data.


Member Function Documentation

Get the ID number of the session.

Returns:
the ID number of the session.

Get the ID number of the worker thread.

Returns:
the ID number of the worker thread. It is from 0 to less than the number of worker threads.

Set the session local data.

Parameters:
datathe session local data. If it is NULL, no data is registered.
Note:
The registered data is destroyed implicitly when the session object is destroyed or this method is called again.

Get the session local data.

Returns:
the session local data, or NULL if no data is registered.
kyototycoon-0.9.56/doc/api/nav_f.png0000644000175000017500000000023711757471600016345 0ustar mikiomikio‰PNG  IHDR8³»fIDATxíÝIB1 Q;uÛ¿@ÑÏh;áÚ ±aË !ŽÐ‹V½CÈíþ âŠÅÆ|c±˜¾™¶¶3èsÑFÐFP»S{PšSšsVãlN®F.F.“ã2’ˆüµ¤ï_U¿Œ¾˜Ïþ«‰ÈH Ým”°•IEND®B`‚kyototycoon-0.9.56/doc/api/classkyototycoon_1_1Pollable-members.html0000644000175000017500000001202711757471600024626 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::Pollable Member List
This is the complete list of members for kyototycoon::Pollable, including all inherited members.
descriptor()=0kyototycoon::Pollable [pure virtual]
event_flags()=0kyototycoon::Pollable [pure virtual]
EventFlag enum namekyototycoon::Pollable
EVEXCEPT enum valuekyototycoon::Pollable
EVINPUT enum valuekyototycoon::Pollable
EVOUTPUT enum valuekyototycoon::Pollable
Pollable()kyototycoon::Pollable [explicit]
Poller (defined in kyototycoon::Pollable)kyototycoon::Pollable [friend]
set_event_flags(uint32_t flags)=0kyototycoon::Pollable [pure virtual]
~Pollable()kyototycoon::Pollable [virtual]
kyototycoon-0.9.56/doc/api/functions_0x69.html0000644000175000017500000001366411757471600020242 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- i -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer_1_1Session_1_1Data-members.html0000644000175000017500000000575411757471600030311 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::HTTPServer::Session::Data Member List
This is the complete list of members for kyototycoon::HTTPServer::Session::Data, including all inherited members.
~Data()kyototycoon::HTTPServer::Session::Data [virtual]
kyototycoon-0.9.56/doc/api/functions_0x75.html0000644000175000017500000001216411757471600020231 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- u -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RemoteDB_1_1Cursor.html0000644000175000017500000013360111757471600024745 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RemoteDB::Cursor Class Reference
kyototycoon::RemoteDB::Cursor Class Reference

Cursor to indicate a record. More...

#include <ktremotedb.h>

List of all members.

Public Member Functions

 Cursor (RemoteDB *db)
 Constructor.
virtual ~Cursor ()
 Destructor.
bool jump ()
 Jump the cursor to the first record for forward scan.
bool jump (const char *kbuf, size_t ksiz)
 Jump the cursor to a record for forward scan.
bool jump (const std::string &key)
 Jump the cursor to a record for forward scan.
bool jump_back ()
 Jump the cursor to the last record for backward scan.
bool jump_back (const char *kbuf, size_t ksiz)
 Jump the cursor to a record for backward scan.
bool jump_back (const std::string &key)
 Jump the cursor to a record for backward scan.
bool step ()
 Step the cursor to the next record.
bool step_back ()
 Step the cursor to the previous record.
bool set_value (const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX, bool step=false)
 Set the value of the current record.
bool set_value_str (const std::string &value, int64_t xt=kc::INT64MAX, bool step=false)
 Set the value of the current record.
bool remove ()
 Remove the current record.
char * get_key (size_t *sp, bool step=false)
 Get the key of the current record.
bool get_key (std::string *key, bool step=false)
 Get the key of the current record.
char * get_value (size_t *sp, bool step=false)
 Get the value of the current record.
bool get_value (std::string *value, bool step=false)
 Get the value of the current record.
char * get (size_t *ksp, const char **vbp, size_t *vsp, int64_t *xtp=NULL, bool step=false)
 Get a pair of the key and the value of the current record.
bool get (std::string *key, std::string *value, int64_t *xtp=NULL, bool step=false)
 Get a pair of the key and the value of the current record.
char * seize (size_t *ksp, const char **vbp, size_t *vsp, int64_t *xtp=NULL)
 Get a pair of the key and the value of the current record and remove it atomically.
bool seize (std::string *key, std::string *value, int64_t *xtp=NULL)
 Get a pair of the key and the value of the current record and remove it atomically.
RemoteDBdb ()
 Get the database object.
Error error ()
 Get the last happened error.

Friends

class RemoteDB

Detailed Description

Cursor to indicate a record.


Constructor & Destructor Documentation

Constructor.

Parameters:
dbthe container database object.

Destructor.


Member Function Documentation

Jump the cursor to the first record for forward scan.

Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::Cursor::jump ( const char *  kbuf,
size_t  ksiz 
)

Jump the cursor to a record for forward scan.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::Cursor::jump ( const std::string &  key)

Jump the cursor to a record for forward scan.

Note:
Equal to the original Cursor::jump method except that the parameter is std::string.

Jump the cursor to the last record for backward scan.

Returns:
true on success, or false on failure.
Note:
This method is dedicated to tree databases. Some database types, especially hash databases, may provide a dummy implementation.
bool kyototycoon::RemoteDB::Cursor::jump_back ( const char *  kbuf,
size_t  ksiz 
)

Jump the cursor to a record for backward scan.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
Returns:
true on success, or false on failure.
Note:
This method is dedicated to tree databases. Some database types, especially hash databases, will provide a dummy implementation.
bool kyototycoon::RemoteDB::Cursor::jump_back ( const std::string &  key)

Jump the cursor to a record for backward scan.

Note:
Equal to the original Cursor::jump_back method except that the parameter is std::string.

Step the cursor to the next record.

Returns:
true on success, or false on failure.

Step the cursor to the previous record.

Returns:
true on success, or false on failure.
Note:
This method is dedicated to tree databases. Some database types, especially hash databases, may provide a dummy implementation.
bool kyototycoon::RemoteDB::Cursor::set_value ( const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX,
bool  step = false 
)

Set the value of the current record.

Parameters:
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
steptrue to move the cursor to the next record, or false for no move.
Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::Cursor::set_value_str ( const std::string &  value,
int64_t  xt = kc::INT64MAX,
bool  step = false 
)

Set the value of the current record.

Note:
Equal to the original Cursor::set_value method except that the parameter is std::string.

Remove the current record.

Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, false is returned. The cursor is moved to the next record implicitly.
char* kyototycoon::RemoteDB::Cursor::get_key ( size_t *  sp,
bool  step = false 
)

Get the key of the current record.

Parameters:
spthe pointer to the variable into which the size of the region of the return value is assigned.
steptrue to move the cursor to the next record, or false for no move.
Returns:
the pointer to the key region of the current record, or NULL on failure.
Note:
If the cursor is invalidated, NULL is returned. Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a C-style string. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
bool kyototycoon::RemoteDB::Cursor::get_key ( std::string *  key,
bool  step = false 
)

Get the key of the current record.

Note:
Equal to the original Cursor::get_key method except that a parameter is a string to contain the result and the return value is bool for success.
char* kyototycoon::RemoteDB::Cursor::get_value ( size_t *  sp,
bool  step = false 
)

Get the value of the current record.

Parameters:
spthe pointer to the variable into which the size of the region of the return value is assigned.
steptrue to move the cursor to the next record, or false for no move.
Returns:
the pointer to the value region of the current record, or NULL on failure.
Note:
If the cursor is invalidated, NULL is returned. Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a C-style string. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
bool kyototycoon::RemoteDB::Cursor::get_value ( std::string *  value,
bool  step = false 
)

Get the value of the current record.

Note:
Equal to the original Cursor::get_value method except that a parameter is a string to contain the result and the return value is bool for success.
char* kyototycoon::RemoteDB::Cursor::get ( size_t *  ksp,
const char **  vbp,
size_t *  vsp,
int64_t *  xtp = NULL,
bool  step = false 
)

Get a pair of the key and the value of the current record.

Parameters:
kspthe pointer to the variable into which the size of the region of the return value is assigned.
vbpthe pointer to the variable into which the pointer to the value region is assigned.
vspthe pointer to the variable into which the size of the value region is assigned.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
steptrue to move the cursor to the next record, or false for no move.
Returns:
the pointer to the pair of the key region, or NULL on failure.
Note:
If the cursor is invalidated, NULL is returned. Because an additional zero code is appended at the end of each region of the key and the value, each region can be treated as a C-style string. The return value should be deleted explicitly by the caller with the detele[] operator.
bool kyototycoon::RemoteDB::Cursor::get ( std::string *  key,
std::string *  value,
int64_t *  xtp = NULL,
bool  step = false 
)

Get a pair of the key and the value of the current record.

Note:
Equal to the original Cursor::get method except that parameters are strings to contain the result and the return value is bool for success.
char* kyototycoon::RemoteDB::Cursor::seize ( size_t *  ksp,
const char **  vbp,
size_t *  vsp,
int64_t *  xtp = NULL 
)

Get a pair of the key and the value of the current record and remove it atomically.

Parameters:
kspthe pointer to the variable into which the size of the region of the return value is assigned.
vbpthe pointer to the variable into which the pointer to the value region is assigned.
vspthe pointer to the variable into which the size of the value region is assigned.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
Returns:
the pointer to the pair of the key region, or NULL on failure.
Note:
If the cursor is invalidated, NULL is returned. Because an additional zero code is appended at the end of each region of the key and the value, each region can be treated as a C-style string. The return value should be deleted explicitly by the caller with the detele[] operator. The cursor is moved to the next record implicitly.
bool kyototycoon::RemoteDB::Cursor::seize ( std::string *  key,
std::string *  value,
int64_t *  xtp = NULL 
)

Get a pair of the key and the value of the current record and remove it atomically.

Note:
Equal to the original Cursor::seize method except that parameters are strings to contain the result and the return value is bool for success.

Get the database object.

Returns:
the database object.

Get the last happened error.

Returns:
the last happened error.
kyototycoon-0.9.56/doc/api/functions_0x64.html0000644000175000017500000001444111757471600020227 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- d -

kyototycoon-0.9.56/doc/api/doxygen.png0000644000175000017500000000754611757471600016743 0ustar mikiomikio‰PNG  IHDRh ;ˆØ-IDATxí]{XŒyÿ¾sZ%Ê”NF:¨´FåЪքbÝè@;~ÓŽÃ"DH‘ÚZ•ð–m_Œéè4ÄÙÚ!ë-‡2«U«Ce[Š"§š_ñÌ3óLSìõ¾ï¾öº|®««y>§ïý¹ïïá_ ™L†öþZ·¼ß¦ajëñ®¹L•oñúþ}«.Íë2Þãû$Zöå);*.d¥~Ûìß³wˆ—·'ˆâ0³Ëâþ@áû!ZZeÊÿÁÞͺwÓøÏÔÚ‰ù?ØO =\Lâ[òg²dxr0Ð —€¤Rrj·Jž€‘*í.WJN5¨äÉqÈMªÔ[mºÞ•’Sb58™Ä¼RB5½¥•’SRus[2<ÙÄ %·˜˜•²V'˜ê+%§$fv˜ØÄºR»«Kó$ ¡¥C 4ã+xº˜£½sQÙ}f¶ðÀ[²vôZ €ç6c}”½!,Lt×ï<ÂÅ«µ°dx†H)/ÎÙfí襧¥C«1¶v£ôº[~– ÏÑåÅ9%DÏDKgžrN}M9úY««3*/Îi謷%ÓU^œ#¶vôr'p²=]ÌÑ_§7®ßy„ìS¸ª½ëkÊaÉð´-/Î!E²vôâà902œíÁÉ–FæŸ*¸Å,ý­– O!1k>QÓÓ³¦°dx¦X:ûð¼=GÃÂD×ï<ÂþÃ'¸fvRªKó‚UZjbóièþ¤`èõýˆtº9cùœ‘xÕÚªV W­­°sžabóièw1ó1x%îæhŒ¹Þ¶¸9׉>oÕ®hkG¯~¥—Nl°sž"^™ÀdŽ2%sw…ø¨•¼W­­‹ìœ§D¸z¯àí W †Æç˜8c>‚í1”ô‡m·Bvêî«ÖÖ8܉ÞAˆZò þT…u—r­½ª´th9kÂÖRêåŸSfÛþ/d§–°‰¾äœ1kçb„A.ܸ@ø“+;:j ÛÚÑË«ôÒ‰|#­Ýp4i®â¨]¼â߯óV~éØÇŒ…xfv$Õ¥y| S[ö;BOK‡V“ÅßÖàÎÌa 4x0¶Ï:ÂßDN54>Çgœõxp÷ªo;Z:´¬œÃÉ”º€ÕÇðë™ïbÛ‡ªöü|Ñ^TŠ7=$4)L!Ü/åuü’#)9/rqÃ%îØÅï¬~a”çŽÅ-à¸poE ‚”®,|gŽ¥m /9/ŠsÃâ˜Ø|šœ±c Ó/åu¨ü Êë€P\…aÁÂ’ó¢‡1,¦¥Ó¢Ã;ueòyªKó\ä…°üÃ"7-K!3>õ2ÊËËamm åÚÈr7M.(~[2ÓÝÉ„Œ]©¨C<¿í»b9Ç[)v[~Ñ,_º@\|î8ËqÜ´{· Ð}QÞ”ugr7àÛÈJ]|Úe¤ïÚ`ƒ–­æçÿ¤à™4s5Ü+µÕÒ¡•©Æ\§áéãû¶Ù•ýxàJ,ûÌudùùs&@yŽõI…eD…Ÿ;ç8nZÁž={ʘfóQU|X ÞØÚ)ض˜"ÞtîVÜ-ÏwÐo¨ãç¢ý‰œöJy>¶6è°¹ ÌFrÊf¥ÑÍú’ KbÏà¼(!@~»ó³) F¹{€í€Ave'3£Hÿ£¦˜î»Íu @³¯Aò±¬$èj÷"s&û…½&ób~¶t”»w¢ÿ¼¼¥þŠ·öQÓ J~Iå âJÚö½˜Ÿ]=ÊÝ;=|S{ºû™Éç‘“nçÊÜ9ôË¿ÈõË„.{ù®‰Ü´`Œb³ßÅÊå ÅâÚž)†j\Þ€ÔΕ›ÞY_ÂE_¸â.gÚ0uõ‹‘Ÿ‰2ݪiDàWËÐÜX'ÖìkÀÌÿº©ü–ñqýòV¶gDO³¯Ý„¦âÁÔôçE 6È ä1cZŒ¦ÄÄ—n£¹±NXxú(¿] ±ãgL_ºM!ÓÐb4Ü+e´´Ê¤âŽdüƒç62[é£]Am­ž,b÷@Jáé£Õ„ÿð‘Ü_Ù,Wºˆr€‘®Îèr_g8ÕÕ&(ÁQAäÛ4·­Ÿò.«ö—¯­ajëAïghS–öÝFJËÛhheg©‹³;Lýcs é/¼RƒÈõËÄ¢ì,‘—¾84†íõ‰9™óõ:n–œ`‰²³Ä,o_ï~†6YIqaÐÑî¥vÊèã¸v>=V”E¹æXÞ¾5™é=uu›^À/ °A”eD䆸ÍX¹j®S¬‘#§Ï^Ëžç3œŒÇì-ÂÙ£[Ã@µövmæÏ ’X ÊÎÊW¤×vú9šÚúѽµõQ_{ͽ3žäW\ø¦æØ:p¤ajëeIÉ)tšâîŽåáܱ8Iû£>xødÆöEóöëd:ÛŒ4µõk¾OŽƒNI¼‰¨½q>m•á1!)[©›Vàb47ýa @æšṉ̃ p…%5Pþ~üä¾Z‚æ¦?| 3³•0DN  á}® Unû¬@ú® » 3¹ÌÁÃ'‹Tç(,©ÁÏ—ïÂÁÊ^.ŠM¤ÄA8a?šUÙ¾äJ<§à2S÷ þ~…@=hjë3-GÍÄ|ŸÈ8Y.¯—¨®]XRƒèËIT9X²A€›¿ž$ÚéÇÛÈõ™hIPvã!ÀvHÿ°}Úo)Ͷ‡8rŠßš ¶=…Ч*^÷˜éiEïŸÂ«8‘"<˜Ìö Ht™¶œ·"Б²æ–͘á¿Êx.üZ‹˜M!b~ƒé Ã!c ’bwÀ·zëqT\È L*a.ˆŒÙÁP7:Û*(FÁñøpáÁô8¶O@â¿5<å9•17>yö“1z¸a‡zs{/Q†9æ‘ ´j}S¹vYD*n]Í!rÐhyakÔj ™Ê„«úgúÍ‘ d¦©­_¾*llé]^&}ˆ˜¨ÍhnúÃÛpȨèí[¨ä.Y»µ7..ÐÔÖOŽÚ²ÆµÉX|Úeœ%¤ÈL%äL¿9e ‰Étå¼ÇO^ (ˆÛp 3U±%ßär ‡ŒJŽ ›§vÎ2éCÊ Äzá2SãfúÍ1êÃ]Ïõ™@ÝÈ™¼€ÄÜn’èÛp%®Ö"nËJR µß2GÛ+Z™Š[¥?’@„½[PèâÙcÐWKþÂÕZìÛó=’â×Q÷ŸšiøÏäôîÓ?yê¬E`3‡ª+Wá‡ý;ñìÉÃŽöîÓ¿fóæHŠÛÒ%¸x2!%#Mì?;p)î°™*à²u;p_zÉ%#M !pˆ‚WÇR†Š«phϦÝi‚Eª8ügFôîÓ?ÔÁíKÈïü²ëp)_+Ç©XÀPÅž‘&ˆ#jðÌí&q=˜n˜0ÚLí¬×n>Dá•\Ê¢á÷J[ts»I¢è5³)¼&~J ¤:Úè´µAB„î@‹PKÆ´×doCú)ñÑaSteLgÓ.㦶襩›Àÿ?MàÙ¿|Ö¸bÙšs+s’¤Ÿ¸†ÑtïÙ›À@€<öòyÓ¶_=ï ‡žok®Ô‡Û¶½ÚžŸ¿x¾Œª¢Ã=ä_C?ÝlÐßB™«WŠp·òœ‰ÙcK3=hh(b%ùÐ7u@}mEû»ÃtØxØØØâRÁ)ÔUÿ¢%“2™ ݺ)©Ø™¢;¸œŸnÝ{†®ÃÆÎ†‰¡î_2Ÿ´úªŠ ý‘ýLKϲַÆöEe÷¡A(ô¤ù%ž?iÀÓÆßÓ¸›`N·zýàëÑ,ñðÞo´w¯ÊNõ{elЧ‡òÉ«}ð·êq¥ì&ªKsñüÉÃän=>º`á°±³Ýÿ*q:½âht§¿Õw_Z”ÞòòÙ^š:cå¾nÝ{âùÓ†‹Ýº÷Ì`N£;‘×›Üj*ÿµ½¥å¥K¯Þ}^4?&ý=zi¡—¦zkõCcýPBht'×ÿÑ|UE‡ä1 ý;ž&5v›øßõëÛµ]@kS}ðÿpŽªª¢ÃâÕ¥y &þ>Ø{fÝ>Pð~ÛÿÞžk˜^œIEND®B`‚kyototycoon-0.9.56/doc/api/tab_h.png0000644000175000017500000000030011757471600016320 0ustar mikiomikio‰PNG  IHDR$ÇÇ[‡IDATxíÝÛ ‚`€áÿ¥ºˆFŠ¢‚hšYÒ ÿÌ26@c´HwÍñì!ïÏ—K1ê^‰©HtO’÷ÄyG˜µD׎ k9¦ç?iðâ7zá„vPaŸž˜þãÏðJŒ}ÉÆ)غwV»‚õ®`ai–Ö¥¥™›Z‰ˆšŒP³éøC"àèP=€IEND®B`‚kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ReplicationClient.html0000644000175000017500000003317311757471600025061 0ustar mikiomikio Kyoto Tycoon: kyototycoon::ReplicationClient Class Reference
kyototycoon::ReplicationClient Class Reference

Replication client. More...

#include <ktremotedb.h>

List of all members.

Public Types

enum  Option { WHITESID = 1 << 0 }
 Opening options. More...

Public Member Functions

 ReplicationClient ()
 Default constructor.
bool open (const std::string &host="", int32_t port=DEFPORT, double timeout=-1, uint64_t ts=0, uint16_t sid=0, uint32_t opts=0)
 Open the connection.
bool close ()
 Close the connection.
char * read (size_t *sp, uint64_t *tsp)
 Read the next message.
bool alive ()
 Check whether the connection is alive.

Detailed Description

Replication client.


Member Enumeration Documentation

Opening options.

Enumerator:
WHITESID 

fetch messages of the specified SID only


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

bool kyototycoon::ReplicationClient::open ( const std::string &  host = "",
int32_t  port = DEFPORT,
double  timeout = -1,
uint64_t  ts = 0,
uint16_t  sid = 0,
uint32_t  opts = 0 
)

Open the connection.

Parameters:
hostthe name or the address of the server. If it is an empty string, the local host is specified.
portthe port numger of the server.
timeoutthe timeout of each operation in seconds. If it is not more than 0, no timeout is specified.
tsthe maximum time stamp of already read logs.
sidthe server ID number.
optsthe optional features by bitwise-or: ReplicationClient::WHITESID to fetch messages whose server ID number is the specified one only.
Returns:
true on success, or false on failure.

Close the connection.

Returns:
true on success, or false on failure.
char* kyototycoon::ReplicationClient::read ( size_t *  sp,
uint64_t *  tsp 
)

Read the next message.

Parameters:
spthe pointer to the variable into which the size of the region of the return value is assigned.
tspthe pointer to the variable into which the time stamp is assigned.
Returns:
the pointer to the region of the message, or NULL on failure. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.

Check whether the connection is alive.

Returns:
true if alive, false if not.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1Poller-members.html0000644000175000017500000001256611757471600024341 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::Poller Member List
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RemoteDB-members.html0000644000175000017500000005155311757471600024544 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RemoteDB Member List
This is the complete list of members for kyototycoon::RemoteDB, including all inherited members.
add(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
add(const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
append(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
append(const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
BinaryMagic enum namekyototycoon::RemoteDB
BinaryOption enum namekyototycoon::RemoteDB
BMERROR enum valuekyototycoon::RemoteDB
BMGETBULK enum valuekyototycoon::RemoteDB
BMNOP enum valuekyototycoon::RemoteDB
BMPLAYSCRIPT enum valuekyototycoon::RemoteDB
BMREMOVEBULK enum valuekyototycoon::RemoteDB
BMREPLICATION enum valuekyototycoon::RemoteDB
BMSETBULK enum valuekyototycoon::RemoteDB
BONOREPLY enum valuekyototycoon::RemoteDB
cas(const char *kbuf, size_t ksiz, const char *ovbuf, size_t ovsiz, const char *nvbuf, size_t nvsiz, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
cas(const std::string &key, const std::string &ovalue, const std::string &nvalue, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
check(const char *kbuf, size_t ksiz, int64_t *xtp=NULL)kyototycoon::RemoteDB
check(const std::string &key, int64_t *xtp=NULL)kyototycoon::RemoteDB
clear()kyototycoon::RemoteDB
close(bool grace=true)kyototycoon::RemoteDB
count()kyototycoon::RemoteDB
cursor()kyototycoon::RemoteDB
DATAMAXSIZkyototycoon::RemoteDB [static]
error() const kyototycoon::RemoteDB
expression()kyototycoon::RemoteDB
get(const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp=NULL)kyototycoon::RemoteDB
get(const std::string &key, std::string *value, int64_t *xtp=NULL)kyototycoon::RemoteDB
get_bulk(const std::vector< std::string > &keys, std::map< std::string, std::string > *recs, bool atomic=true)kyototycoon::RemoteDB
get_bulk_binary(std::vector< BulkRecord > *recs)kyototycoon::RemoteDB
increment(const char *kbuf, size_t ksiz, int64_t num, int64_t orig=0, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
increment(const std::string &key, int64_t num, int64_t orig=0, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
increment_double(const char *kbuf, size_t ksiz, double num, double orig=0, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
increment_double(const std::string &key, double num, double orig=0, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
match_prefix(const std::string &prefix, std::vector< std::string > *strvec, int64_t max=-1)kyototycoon::RemoteDB
match_regex(const std::string &regex, std::vector< std::string > *strvec, int64_t max=-1)kyototycoon::RemoteDB
match_similar(const std::string &origin, size_t range, bool utf, std::vector< std::string > *strvec, int64_t max=-1)kyototycoon::RemoteDB
open(const std::string &host="", int32_t port=DEFPORT, double timeout=-1)kyototycoon::RemoteDB
play_script(const std::string &name, const std::map< std::string, std::string > &params, std::map< std::string, std::string > *result)kyototycoon::RemoteDB
play_script_binary(const std::string &name, const std::map< std::string, std::string > &params, std::map< std::string, std::string > *result=NULL, uint32_t opts=0)kyototycoon::RemoteDB
RemoteDB()kyototycoon::RemoteDB [explicit]
remove(const char *kbuf, size_t ksiz)kyototycoon::RemoteDB
remove(const std::string &key)kyototycoon::RemoteDB
remove_bulk(const std::vector< std::string > &keys, bool atomic=true)kyototycoon::RemoteDB
remove_bulk_binary(const std::vector< BulkRecord > &recs, uint32_t opts=0)kyototycoon::RemoteDB
replace(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
replace(const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
report(std::map< std::string, std::string > *strmap)kyototycoon::RemoteDB
seize(const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp=NULL)kyototycoon::RemoteDB
seize(const std::string &key, std::string *value, int64_t *xtp=NULL)kyototycoon::RemoteDB
set(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
set(const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)kyototycoon::RemoteDB
set_bulk(const std::map< std::string, std::string > &recs, int64_t xt=kc::INT64MAX, bool atomic=true)kyototycoon::RemoteDB
set_bulk_binary(const std::vector< BulkRecord > &recs, uint32_t opts=0)kyototycoon::RemoteDB
set_signal_sending(const std::string &name, bool broadcast=false)kyototycoon::RemoteDB
set_signal_waiting(const std::string &name, double timeout=0)kyototycoon::RemoteDB
set_target(const std::string &expr)kyototycoon::RemoteDB
size()kyototycoon::RemoteDB
status(std::map< std::string, std::string > *strmap)kyototycoon::RemoteDB
synchronize(bool hard, const std::string &command="")kyototycoon::RemoteDB
tune_replication(const std::string &host="", int32_t port=DEFPORT, uint64_t ts=kc::UINT64MAX, double iv=-1)kyototycoon::RemoteDB
ulog_list(std::vector< UpdateLogger::FileStatus > *fstvec)kyototycoon::RemoteDB
ulog_remove(uint64_t ts=kc::UINT64MAX)kyototycoon::RemoteDB
vacuum(int64_t step=0)kyototycoon::RemoteDB
~RemoteDB()kyototycoon::RemoteDB [virtual]
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer_1_1Session-members.html0000644000175000017500000001024711757471600026715 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RPCServer::Session Member List
kyototycoon-0.9.56/doc/api/structkyototycoon_1_1RemoteDB_1_1BulkRecord.html0000644000175000017500000001532011757471600025740 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RemoteDB::BulkRecord Struct Reference
kyototycoon::RemoteDB::BulkRecord Struct Reference

Record for bulk operation. More...

#include <ktremotedb.h>

List of all members.

Public Attributes

uint16_t dbidx
 index of the target database
std::string key
 key
std::string value
 value
int64_t xt
 expiration time

Detailed Description

Record for bulk operation.


Member Data Documentation

index of the target database

expiration time

kyototycoon-0.9.56/doc/api/namespacemembers_func.html0000644000175000017500000001313311757471600021755 0ustar mikiomikio Kyoto Tycoon: Namespace Members
 
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RemoteDB.html0000644000175000017500000035740111757471600023115 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RemoteDB Class Reference
kyototycoon::RemoteDB Class Reference

Remote database. More...

#include <ktremotedb.h>

List of all members.

Classes

struct  BulkRecord
 Record for bulk operation. More...
class  Cursor
 Cursor to indicate a record. More...
class  Error
 Error data. More...
struct  OrderedKey
 Key with the order.

Public Types

enum  BinaryMagic {
  BMNOP = 0xb0, BMREPLICATION = 0xb1, BMPLAYSCRIPT = 0xb4, BMSETBULK = 0xb8,
  BMREMOVEBULK = 0xb9, BMGETBULK = 0xba, BMERROR = 0xbf
}
 Magic data in binary protocol. More...
enum  BinaryOption { BONOREPLY = 1 << 0 }
 Options in binary protocol. More...

Public Member Functions

 RemoteDB ()
 Default constructor.
virtual ~RemoteDB ()
 Destructor.
Error error () const
 Get the last happened error code.
bool open (const std::string &host="", int32_t port=DEFPORT, double timeout=-1)
 Open the connection.
bool close (bool grace=true)
 Close the connection.
bool report (std::map< std::string, std::string > *strmap)
 Get the report of the server information.
bool play_script (const std::string &name, const std::map< std::string, std::string > &params, std::map< std::string, std::string > *result)
 Call a procedure of the scripting extension.
bool tune_replication (const std::string &host="", int32_t port=DEFPORT, uint64_t ts=kc::UINT64MAX, double iv=-1)
 Set the replication configuration.
bool ulog_list (std::vector< UpdateLogger::FileStatus > *fstvec)
 Get status of each update log files.
bool ulog_remove (uint64_t ts=kc::UINT64MAX)
 Remove old update log files.
bool status (std::map< std::string, std::string > *strmap)
 Get the miscellaneous status information.
bool clear ()
 Remove all records.
bool synchronize (bool hard, const std::string &command="")
 Synchronize updated contents with the file and the device.
int64_t count ()
 Get the number of records.
int64_t size ()
 Get the size of the database file.
bool set (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)
 Set the value of a record.
bool set (const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)
 Set the value of a record.
bool add (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)
 Add a record.
bool add (const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)
 Set the value of a record.
bool replace (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)
 Replace the value of a record.
bool replace (const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)
 Replace the value of a record.
bool append (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)
 Append the value of a record.
bool append (const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)
 Set the value of a record.
int64_t increment (const char *kbuf, size_t ksiz, int64_t num, int64_t orig=0, int64_t xt=kc::INT64MAX)
 Add a number to the numeric integer value of a record.
int64_t increment (const std::string &key, int64_t num, int64_t orig=0, int64_t xt=kc::INT64MAX)
 Add a number to the numeric integer value of a record.
double increment_double (const char *kbuf, size_t ksiz, double num, double orig=0, int64_t xt=kc::INT64MAX)
 Add a number to the numeric double value of a record.
double increment_double (const std::string &key, double num, double orig=0, int64_t xt=kc::INT64MAX)
 Add a number to the numeric double value of a record.
bool cas (const char *kbuf, size_t ksiz, const char *ovbuf, size_t ovsiz, const char *nvbuf, size_t nvsiz, int64_t xt=kc::INT64MAX)
 Perform compare-and-swap.
bool cas (const std::string &key, const std::string &ovalue, const std::string &nvalue, int64_t xt=kc::INT64MAX)
 Perform compare-and-swap.
bool remove (const char *kbuf, size_t ksiz)
 Remove a record.
bool remove (const std::string &key)
 Remove a record.
char * get (const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp=NULL)
 Retrieve the value of a record.
bool get (const std::string &key, std::string *value, int64_t *xtp=NULL)
 Retrieve the value of a record.
int32_t check (const char *kbuf, size_t ksiz, int64_t *xtp=NULL)
 Check the existence of a record.
int32_t check (const std::string &key, int64_t *xtp=NULL)
 Check the existence of a record.
char * seize (const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp=NULL)
 Retrieve the value of a record and remove it atomically.
bool seize (const std::string &key, std::string *value, int64_t *xtp=NULL)
 Retrieve the value of a record and remove it atomically.
int64_t set_bulk (const std::map< std::string, std::string > &recs, int64_t xt=kc::INT64MAX, bool atomic=true)
 Store records at once.
int64_t remove_bulk (const std::vector< std::string > &keys, bool atomic=true)
 Store records at once.
int64_t get_bulk (const std::vector< std::string > &keys, std::map< std::string, std::string > *recs, bool atomic=true)
 Retrieve records at once.
bool vacuum (int64_t step=0)
 Scan the database and eliminate regions of expired records.
int64_t match_prefix (const std::string &prefix, std::vector< std::string > *strvec, int64_t max=-1)
 Get keys matching a prefix string.
int64_t match_regex (const std::string &regex, std::vector< std::string > *strvec, int64_t max=-1)
 Get keys matching a regular expression string.
int64_t match_similar (const std::string &origin, size_t range, bool utf, std::vector< std::string > *strvec, int64_t max=-1)
 Get keys similar to a string in terms of the levenshtein distance.
void set_target (const std::string &expr)
 Set the target database.
void set_signal_waiting (const std::string &name, double timeout=0)
 Set the signal waiting condition of the next procedure.
void set_signal_sending (const std::string &name, bool broadcast=false)
 Set the signal sending condition of the next procedure.
bool play_script_binary (const std::string &name, const std::map< std::string, std::string > &params, std::map< std::string, std::string > *result=NULL, uint32_t opts=0)
 Call a procedure of the scripting extension in the binary protocol.
int64_t set_bulk_binary (const std::vector< BulkRecord > &recs, uint32_t opts=0)
 Store records at once in the binary protocol.
int64_t remove_bulk_binary (const std::vector< BulkRecord > &recs, uint32_t opts=0)
 Store records at once in the binary protocol.
int64_t get_bulk_binary (std::vector< BulkRecord > *recs)
 Retrieve records at once in the binary protocol.
const std::string expression ()
 Get the expression of the socket.
Cursorcursor ()
 Create a cursor object.

Static Public Attributes

static const size_t DATAMAXSIZ = 1ULL << 28
 The maximum size of each record data.

Detailed Description

Remote database.

Note:
This class is a concrete class to access remote database servers. This class can be inherited but overwriting methods is forbidden. Before every database operation, it is necessary to call the RemoteDB::open method in order to connect to a database server. To avoid resource starvation it is important to close every database file by the RemoteDB::close method when the connection is no longer in use. Although all methods of this class are thread-safe, its instance does not have mutual exclusion mechanism. So, multiple threads must not share the same instance and they must use their own respective instances.

Member Enumeration Documentation

Magic data in binary protocol.

Enumerator:
BMNOP 

no operation

BMREPLICATION 

replication

BMPLAYSCRIPT 

call a scripting procedure

BMSETBULK 

set in bulk

BMREMOVEBULK 

remove in bulk

BMGETBULK 

get in bulk

BMERROR 

error

Options in binary protocol.

Enumerator:
BONOREPLY 

no reply


Constructor & Destructor Documentation

Default constructor.

virtual kyototycoon::RemoteDB::~RemoteDB ( ) [virtual]

Destructor.


Member Function Documentation

Get the last happened error code.

Returns:
the last happened error code.
bool kyototycoon::RemoteDB::open ( const std::string &  host = "",
int32_t  port = DEFPORT,
double  timeout = -1 
)

Open the connection.

Parameters:
hostthe name or the address of the server. If it is an empty string, the local host is specified.
portthe port numger of the server.
timeoutthe timeout of each operation in seconds. If it is not more than 0, no timeout is specified.
Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::close ( bool  grace = true)

Close the connection.

Parameters:
gracetrue for graceful shutdown, or false for immediate disconnection.
Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::report ( std::map< std::string, std::string > *  strmap)

Get the report of the server information.

Parameters:
strmapa string map to contain the result.
Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::play_script ( const std::string &  name,
const std::map< std::string, std::string > &  params,
std::map< std::string, std::string > *  result 
)

Call a procedure of the scripting extension.

Parameters:
namethe name of the procedure to call.
paramsa string map containing the input parameters.
resulta string map to contain the output data.
Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::tune_replication ( const std::string &  host = "",
int32_t  port = DEFPORT,
uint64_t  ts = kc::UINT64MAX,
double  iv = -1 
)

Set the replication configuration.

Parameters:
hostthe name or the address of the master server. If it is an empty string, replication is disabled.
portthe port numger of the server.
tsthe maximum time stamp of already read logs. If it is kyotocabinet::UINT64MAX, the current setting is not modified. If it is kyotocabinet::UINT64MAX - 1, the current time is specified.
ivthe interval of each replication operation in milliseconds. If it is negative, the current interval is not modified.
Returns:
true on success, or false on failure.

Get status of each update log files.

Parameters:
fstveca vector to store status structures of each update log files.
Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::ulog_remove ( uint64_t  ts = kc::UINT64MAX)

Remove old update log files.

Parameters:
tsthe maximum time stamp of disposable logs.
Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::status ( std::map< std::string, std::string > *  strmap)

Get the miscellaneous status information.

Parameters:
strmapa string map to contain the result.
Returns:
true on success, or false on failure.

Remove all records.

Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::synchronize ( bool  hard,
const std::string &  command = "" 
)

Synchronize updated contents with the file and the device.

Parameters:
hardtrue for physical synchronization with the device, or false for logical synchronization with the file system.
commandthe command name to process the database file. If it is an empty string, no postprocessing is performed.
Returns:
true on success, or false on failure.

Get the number of records.

Returns:
the number of records, or -1 on failure.

Get the size of the database file.

Returns:
the size of the database file in bytes, or -1 on failure.
bool kyototycoon::RemoteDB::set ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX 
)

Set the value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, a new record is created. If the corresponding record exists, the value is overwritten.
bool kyototycoon::RemoteDB::set ( const std::string &  key,
const std::string &  value,
int64_t  xt = kc::INT64MAX 
)

Set the value of a record.

Note:
Equal to the original DB::set method except that the parameters are std::string.
bool kyototycoon::RemoteDB::add ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX 
)

Add a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, a new record is created. If the corresponding record exists, the record is not modified and false is returned.
bool kyototycoon::RemoteDB::add ( const std::string &  key,
const std::string &  value,
int64_t  xt = kc::INT64MAX 
)

Set the value of a record.

Note:
Equal to the original DB::add method except that the parameters are std::string.
bool kyototycoon::RemoteDB::replace ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX 
)

Replace the value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, no new record is created and false is returned. If the corresponding record exists, the value is modified.
bool kyototycoon::RemoteDB::replace ( const std::string &  key,
const std::string &  value,
int64_t  xt = kc::INT64MAX 
)

Replace the value of a record.

Note:
Equal to the original DB::replace method except that the parameters are std::string.
bool kyototycoon::RemoteDB::append ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX 
)

Append the value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, a new record is created. If the corresponding record exists, the given value is appended at the end of the existing value.
bool kyototycoon::RemoteDB::append ( const std::string &  key,
const std::string &  value,
int64_t  xt = kc::INT64MAX 
)

Set the value of a record.

Note:
Equal to the original DB::append method except that the parameters are std::string.
int64_t kyototycoon::RemoteDB::increment ( const char *  kbuf,
size_t  ksiz,
int64_t  num,
int64_t  orig = 0,
int64_t  xt = kc::INT64MAX 
)

Add a number to the numeric integer value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
numthe additional number.
origthe origin number if no record corresponds to the key. If it is INT64MIN and no record corresponds, this function fails. If it is INT64MAX, the value is set as the additional number regardless of the current value.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
the result value, or kyotocabinet::INT64MIN on failure.
Note:
The value is serialized as an 8-byte binary integer in big-endian order, not a decimal string. If existing value is not 8-byte, this function fails.
int64_t kyototycoon::RemoteDB::increment ( const std::string &  key,
int64_t  num,
int64_t  orig = 0,
int64_t  xt = kc::INT64MAX 
)

Add a number to the numeric integer value of a record.

Note:
Equal to the original DB::increment method except that the parameter is std::string.
double kyototycoon::RemoteDB::increment_double ( const char *  kbuf,
size_t  ksiz,
double  num,
double  orig = 0,
int64_t  xt = kc::INT64MAX 
)

Add a number to the numeric double value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
numthe additional number.
origthe origin number if no record corresponds to the key. If it is negative infinity and no record corresponds, this function fails. If it is positive infinity, the value is set as the additional number regardless of the current value.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
the result value, or Not-a-number on failure.
Note:
The value is serialized as an 16-byte binary fixed-point number in big-endian order, not a decimal string. If existing value is not 16-byte, this function fails.
double kyototycoon::RemoteDB::increment_double ( const std::string &  key,
double  num,
double  orig = 0,
int64_t  xt = kc::INT64MAX 
)

Add a number to the numeric double value of a record.

Note:
Equal to the original DB::increment_double method except that the parameter is std::string.
bool kyototycoon::RemoteDB::cas ( const char *  kbuf,
size_t  ksiz,
const char *  ovbuf,
size_t  ovsiz,
const char *  nvbuf,
size_t  nvsiz,
int64_t  xt = kc::INT64MAX 
)

Perform compare-and-swap.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
ovbufthe pointer to the old value region. NULL means that no record corresponds.
ovsizthe size of the old value region.
nvbufthe pointer to the new value region. NULL means that the record is removed.
nvsizthe size of new old value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
bool kyototycoon::RemoteDB::cas ( const std::string &  key,
const std::string &  ovalue,
const std::string &  nvalue,
int64_t  xt = kc::INT64MAX 
)

Perform compare-and-swap.

Note:
Equal to the original DB::cas method except that the parameters are std::string.
bool kyototycoon::RemoteDB::remove ( const char *  kbuf,
size_t  ksiz 
)

Remove a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, false is returned.
bool kyototycoon::RemoteDB::remove ( const std::string &  key)

Remove a record.

Note:
Equal to the original DB::remove method except that the parameter is std::string.
char* kyototycoon::RemoteDB::get ( const char *  kbuf,
size_t  ksiz,
size_t *  sp,
int64_t *  xtp = NULL 
)

Retrieve the value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
spthe pointer to the variable into which the size of the region of the return value is assigned.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
Returns:
the pointer to the value region of the corresponding record, or NULL on failure.
Note:
If no record corresponds to the key, NULL is returned. Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a C-style string. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
bool kyototycoon::RemoteDB::get ( const std::string &  key,
std::string *  value,
int64_t *  xtp = NULL 
)

Retrieve the value of a record.

Note:
Equal to the original DB::get method except that the first parameters is the key string and the second parameter is a string to contain the result and the return value is bool for success.
int32_t kyototycoon::RemoteDB::check ( const char *  kbuf,
size_t  ksiz,
int64_t *  xtp = NULL 
)

Check the existence of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
Returns:
the size of the value, or -1 on failure.
int32_t kyototycoon::RemoteDB::check ( const std::string &  key,
int64_t *  xtp = NULL 
)

Check the existence of a record.

Note:
Equal to the original DB::check method except that the first parameters is the key string.
char* kyototycoon::RemoteDB::seize ( const char *  kbuf,
size_t  ksiz,
size_t *  sp,
int64_t *  xtp = NULL 
)

Retrieve the value of a record and remove it atomically.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
spthe pointer to the variable into which the size of the region of the return value is assigned.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
Returns:
the pointer to the value region of the corresponding record, or NULL on failure.
Note:
If no record corresponds to the key, NULL is returned. Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a C-style string. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
bool kyototycoon::RemoteDB::seize ( const std::string &  key,
std::string *  value,
int64_t *  xtp = NULL 
)

Retrieve the value of a record and remove it atomically.

Note:
Equal to the original DB::seize method except that the first parameters is the key string and the second parameter is a string to contain the result and the return value is bool for success.
int64_t kyototycoon::RemoteDB::set_bulk ( const std::map< std::string, std::string > &  recs,
int64_t  xt = kc::INT64MAX,
bool  atomic = true 
)

Store records at once.

Parameters:
recsthe records to store.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
atomictrue to perform all operations atomically, or false for non-atomic operations.
Returns:
the number of stored records, or -1 on failure.
int64_t kyototycoon::RemoteDB::remove_bulk ( const std::vector< std::string > &  keys,
bool  atomic = true 
)

Store records at once.

Parameters:
keysthe keys of the records to remove.
atomictrue to perform all operations atomically, or false for non-atomic operations.
Returns:
the number of removed records, or -1 on failure.
int64_t kyototycoon::RemoteDB::get_bulk ( const std::vector< std::string > &  keys,
std::map< std::string, std::string > *  recs,
bool  atomic = true 
)

Retrieve records at once.

Parameters:
keysthe keys of the records to retrieve.
recsa string map to contain the retrieved records.
atomictrue to perform all operations atomically, or false for non-atomic operations.
Returns:
the number of retrieved records, or -1 on failure.
bool kyototycoon::RemoteDB::vacuum ( int64_t  step = 0)

Scan the database and eliminate regions of expired records.

Parameters:
stepthe number of steps. If it is not more than 0, the whole region is scanned.
Returns:
true on success, or false on failure.
int64_t kyototycoon::RemoteDB::match_prefix ( const std::string &  prefix,
std::vector< std::string > *  strvec,
int64_t  max = -1 
)

Get keys matching a prefix string.

Parameters:
prefixthe prefix string.
strveca string vector to contain the result.
maxthe maximum number to retrieve. If it is negative, no limit is specified.
Returns:
the number of retrieved keys or -1 on failure.
int64_t kyototycoon::RemoteDB::match_regex ( const std::string &  regex,
std::vector< std::string > *  strvec,
int64_t  max = -1 
)

Get keys matching a regular expression string.

Parameters:
regexthe regular expression string.
strveca string vector to contain the result.
maxthe maximum number to retrieve. If it is negative, no limit is specified.
Returns:
the number of retrieved keys or -1 on failure.
int64_t kyototycoon::RemoteDB::match_similar ( const std::string &  origin,
size_t  range,
bool  utf,
std::vector< std::string > *  strvec,
int64_t  max = -1 
)

Get keys similar to a string in terms of the levenshtein distance.

Parameters:
originthe origin string.
rangethe maximum distance of keys to adopt.
utfflag to treat keys as UTF-8 strings.
strveca string vector to contain the result.
maxthe maximum number to retrieve. If it is negative, no limit is specified.
Returns:
the number of retrieved keys or -1 on failure.
void kyototycoon::RemoteDB::set_target ( const std::string &  expr)

Set the target database.

Parameters:
exprthe expression of the target database.
void kyototycoon::RemoteDB::set_signal_waiting ( const std::string &  name,
double  timeout = 0 
)

Set the signal waiting condition of the next procedure.

Parameters:
namethe name of the condition variable.
timeoutthe timeout in seconds.
Note:
This setting is used only in the next procedure call and then cleared.
void kyototycoon::RemoteDB::set_signal_sending ( const std::string &  name,
bool  broadcast = false 
)

Set the signal sending condition of the next procedure.

Parameters:
namethe name of the condition variable.
broadcasttrue to send the signal to every corresponding thread, or false to send it to just one thread.
Note:
This setting is used only in the next procedure call and then cleared.
bool kyototycoon::RemoteDB::play_script_binary ( const std::string &  name,
const std::map< std::string, std::string > &  params,
std::map< std::string, std::string > *  result = NULL,
uint32_t  opts = 0 
)

Call a procedure of the scripting extension in the binary protocol.

Parameters:
namethe name of the procedure to call.
paramsa string map containing the input parameters.
resulta string map to contain the output data. If it is NULL, it is ignored.
optsthe optional features by bitwise-or: RemoteDB::BONOREPLY to ignore reply from the server.
Returns:
true on success, or false on failure.
int64_t kyototycoon::RemoteDB::set_bulk_binary ( const std::vector< BulkRecord > &  recs,
uint32_t  opts = 0 
)

Store records at once in the binary protocol.

Parameters:
recsthe records to store.
optsthe optional features by bitwise-or: RemoteDB::BONOREPLY to ignore reply from the server.
Returns:
the number of stored records, or -1 on failure.
int64_t kyototycoon::RemoteDB::remove_bulk_binary ( const std::vector< BulkRecord > &  recs,
uint32_t  opts = 0 
)

Store records at once in the binary protocol.

Parameters:
recsthe records to remove.
optsthe optional features by bitwise-or: RemoteDB::BONOREPLY to ignore reply from the server.
Returns:
the number of removed records, or -1 on failure.
int64_t kyototycoon::RemoteDB::get_bulk_binary ( std::vector< BulkRecord > *  recs)

Retrieve records at once in the binary protocol.

Parameters:
recsthe records to retrieve. The value member and the xt member of each retrieved record will be set appropriately. The xt member of each missing record will be -1.
Returns:
the number of retrieved records, or -1 on failure.
const std::string kyototycoon::RemoteDB::expression ( )

Get the expression of the socket.

Returns:
the expression of the socket or an empty string on failure.

Create a cursor object.

Returns:
the return value is the created cursor object.
Note:
Because the object of the return value is allocated by the constructor, it should be released with the delete operator when it is no longer in use.

Member Data Documentation

const size_t kyototycoon::RemoteDB::DATAMAXSIZ = 1ULL << 28 [static]

The maximum size of each record data.

kyototycoon-0.9.56/doc/api/functions_func_0x72.html0000644000175000017500000002046611757471600021245 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer_1_1Worker.html0000644000175000017500000005177611757471600025127 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RPCServer::Worker Class Reference
kyototycoon::RPCServer::Worker Class Reference

Interface to process each request. More...

#include <ktrpc.h>

List of all members.

Public Member Functions

virtual ~Worker ()
 Destructor.
virtual RPCClient::ReturnValue process (RPCServer *serv, Session *sess, const std::string &name, const std::map< std::string, std::string > &inmap, std::map< std::string, std::string > &outmap)=0
 Process each request of RPC.
virtual int32_t process (HTTPServer *serv, HTTPServer::Session *sess, const std::string &path, HTTPClient::Method method, const std::map< std::string, std::string > &reqheads, const std::string &reqbody, std::map< std::string, std::string > &resheads, std::string &resbody, const std::map< std::string, std::string > &misc)
 Process each request of the others.
virtual bool process_binary (ThreadedServer *serv, ThreadedServer::Session *sess)
 Process each binary request.
virtual void process_idle (RPCServer *serv)
 Process each idle event.
virtual void process_timer (RPCServer *serv)
 Process each timer event.
virtual void process_start (RPCServer *serv)
 Process the starting event.
virtual void process_finish (RPCServer *serv)
 Process the finishing event.

Detailed Description

Interface to process each request.


Constructor & Destructor Documentation

Destructor.


Member Function Documentation

virtual RPCClient::ReturnValue kyototycoon::RPCServer::Worker::process ( RPCServer serv,
Session sess,
const std::string &  name,
const std::map< std::string, std::string > &  inmap,
std::map< std::string, std::string > &  outmap 
) [pure virtual]

Process each request of RPC.

Parameters:
servthe server.
sessthe session with the client.
namethe name of the procecude.
inmapa string map which contains the input of the procedure.
outmapa string map to contain the input parameters.
Returns:
the return value of the procedure.
virtual int32_t kyototycoon::RPCServer::Worker::process ( HTTPServer serv,
HTTPServer::Session sess,
const std::string &  path,
HTTPClient::Method  method,
const std::map< std::string, std::string > &  reqheads,
const std::string &  reqbody,
std::map< std::string, std::string > &  resheads,
std::string &  resbody,
const std::map< std::string, std::string > &  misc 
) [virtual]

Process each request of the others.

Parameters:
servthe server.
sessthe session with the client.
paththe path of the requested resource.
methodthe kind of the request methods.
reqheadsa string map which contains the headers of the request. Header names are converted into lower cases. The empty key means the request-line.
reqbodya string which contains the entity body of the request.
resheadsa string map to contain the headers of the response.
resbodya string to contain the entity body of the response.
misca string map which contains miscellaneous information. "url" means the absolute URL. "query" means the query string of the URL.
Returns:
the status code of the response. If it is less than 1, internal server error is sent to the client and the connection is closed.

Process each binary request.

Parameters:
servthe server.
sessthe session with the client.
Returns:
true to reuse the session, or false to close the session.
virtual void kyototycoon::RPCServer::Worker::process_idle ( RPCServer serv) [virtual]

Process each idle event.

Parameters:
servthe server.
virtual void kyototycoon::RPCServer::Worker::process_timer ( RPCServer serv) [virtual]

Process each timer event.

Parameters:
servthe server.
virtual void kyototycoon::RPCServer::Worker::process_start ( RPCServer serv) [virtual]

Process the starting event.

Parameters:
servthe server.
virtual void kyototycoon::RPCServer::Worker::process_finish ( RPCServer serv) [virtual]

Process the finishing event.

Parameters:
servthe server.
kyototycoon-0.9.56/doc/api/tab_a.png0000644000175000017500000000021411757471600016315 0ustar mikiomikio‰PNG  IHDR$ÇÇ[SIDATxí» €@wçÉ¡œˆ˜*æ‚M˜ØIïÎF†ýL :®‡±nÌëN™ ¶±Á’„ØN&â¼_ ɭɾ}Õ¶8~î¾îOwv-ÿêA4Y)Ñ}IEND®B`‚kyototycoon-0.9.56/doc/api/classkyototycoon_1_1MapReduce-members.html0000644000175000017500000001665011757471600024747 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::MapReduce Member List
This is the complete list of members for kyototycoon::MapReduce, including all inherited members.
emit(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz)kyototycoon::MapReduce [protected]
execute(TimedDB *db, const std::string &tmppath="", uint32_t opts=0)kyototycoon::MapReduce
log(const char *name, const char *message)kyototycoon::MapReduce [virtual]
map(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz)=0kyototycoon::MapReduce [pure virtual]
MapReduce()kyototycoon::MapReduce [explicit]
midprocess()kyototycoon::MapReduce [virtual]
Option enum namekyototycoon::MapReduce
postprocess()kyototycoon::MapReduce [virtual]
preprocess()kyototycoon::MapReduce [virtual]
reduce(const char *kbuf, size_t ksiz, ValueIterator *iter)=0kyototycoon::MapReduce [pure virtual]
tune_storage(int32_t dbnum, int64_t clim, int64_t cbnum)kyototycoon::MapReduce
tune_thread(int32_t mapthnum, int32_t redthnum, int32_t flsthnum)kyototycoon::MapReduce
XNOCOMP enum valuekyototycoon::MapReduce
XNOLOCK enum valuekyototycoon::MapReduce
XPARAFLS enum valuekyototycoon::MapReduce
XPARAMAP enum valuekyototycoon::MapReduce
XPARARED enum valuekyototycoon::MapReduce
~MapReduce()kyototycoon::MapReduce [virtual]
kyototycoon-0.9.56/doc/api/globals.html0000644000175000017500000000504411757471600017060 0ustar mikiomikio Kyoto Tycoon: File Members
Here is a list of all documented file members with links to the documentation:
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer_1_1Logger-members.html0000644000175000017500000001134511757471600027605 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::ThreadedServer::Logger Member List
kyototycoon-0.9.56/doc/api/ktdbext_8h.html0000644000175000017500000001324411757471600017502 0ustar mikiomikio Kyoto Tycoon: ktdbext.h File Reference
ktdbext.h File Reference

database extension More...

#include <ktcommon.h>
#include <ktutil.h>
#include <ktulog.h>
#include <ktshlib.h>
#include <kttimeddb.h>

Classes

class  kyototycoon::MapReduce
 MapReduce framework. More...
class  kyototycoon::MapReduce::ValueIterator
 Value iterator for the reducer. More...
class  kyototycoon::MapReduce::FlushThread
 Cache flusher.
class  kyototycoon::MapReduce::ReduceTaskQueue
 Task queue for parallel reducer.
class  kyototycoon::MapReduce::ReduceTaskQueue::ReduceTask
 Task for parallel reducer. More...
class  kyototycoon::MapReduce::MapChecker
 Checker for the map process.
class  kyototycoon::MapReduce::MapVisitor
 Visitor for the map process.
struct  kyototycoon::MapReduce::MergeLine
 Front line of a merging list.

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.



Detailed Description

database extension

kyototycoon-0.9.56/doc/api/functions_0x73.html0000644000175000017500000003540411757471600020231 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- s -

kyototycoon-0.9.56/doc/api/functions_func_0x74.html0000644000175000017500000001406411757471600021244 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer_1_1Logger-members.html0000644000175000017500000001127011757471600026506 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RPCServer::Logger Member List
kyototycoon-0.9.56/doc/api/ktrpc_8h.html0000644000175000017500000002271111757471600017157 0ustar mikiomikio Kyoto Tycoon: ktrpc.h File Reference
ktrpc.h File Reference

RPC utilities. More...

#include <ktcommon.h>
#include <ktutil.h>
#include <ktsocket.h>
#include <ktthserv.h>
#include <kthttp.h>

Classes

class  kyototycoon::RPCClient
 RPC client. More...
class  kyototycoon::RPCServer
 RPC server. More...
class  kyototycoon::RPCServer::Logger
 Interface to log internal information and errors. More...
class  kyototycoon::RPCServer::Worker
 Interface to process each request. More...
class  kyototycoon::RPCServer::Session
 Interface to log internal information and errors. More...
class  kyototycoon::RPCServer::Session::Data
 Interface of session local data. More...
class  kyototycoon::RPCServer::WorkerAdapter
 Adapter for the worker.

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.


Defines

#define KTRPCPATHPREFIX   "/rpc/"
 prefix of the RPC entry
#define KTRPCFORMMTYPE   "application/x-www-form-urlencoded"
 MIME type of form data.
#define KTRPCTSVMTYPE   "text/tab-separated-values"
 MIME type of TSV.
#define KTRPCTSVMATTR   "colenc"
 encoding attribute of TSV

Detailed Description

RPC utilities.


Define Documentation

#define KTRPCPATHPREFIX   "/rpc/"

prefix of the RPC entry

#define KTRPCFORMMTYPE   "application/x-www-form-urlencoded"

MIME type of form data.

#define KTRPCTSVMTYPE   "text/tab-separated-values"

MIME type of TSV.

#define KTRPCTSVMATTR   "colenc"

encoding attribute of TSV

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1UpdateLogger.html0000644000175000017500000005001311757471600024023 0ustar mikiomikio Kyoto Tycoon: kyototycoon::UpdateLogger Class Reference
kyototycoon::UpdateLogger Class Reference

Update logger. More...

#include <ktulog.h>

List of all members.

Classes

class  AutoFlusher
 Automatic flusher of cacheed logs.
struct  FileStatus
 Status of each log file. More...
struct  Log
 Log message.
class  Reader
 Reader of update logs. More...

Public Member Functions

 UpdateLogger ()
 Default constructor.
 ~UpdateLogger ()
 Destructor.
bool open (const std::string &path, int64_t limsiz=-1, double asi=-1)
 Open the logger.
bool close ()
 Close the logger.
bool write (const char *mbuf, size_t msiz, uint64_t ts=0)
 Write a log message.
bool write_volatile (char *mbuf, size_t msiz, uint64_t ts=0)
 Write a log message with a volatile buffer.
bool write_bulk (const std::vector< std::string > &mvec, uint64_t ts=0)
 Write multiple log messages at once.
uint64_t clock ()
 Get the current clock data for time stamp.
void list_files (std::vector< FileStatus > *fstvec)
 Get status of each log files.

Static Public Member Functions

static uint64_t clock_pure ()
 Get the current pure clock data for time stamp.

Detailed Description

Update logger.


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

bool kyototycoon::UpdateLogger::open ( const std::string &  path,
int64_t  limsiz = -1,
double  asi = -1 
)

Open the logger.

Parameters:
paththe path of the base directory.
limsizthe limit size of each log file. If it is not more than 0, no limit is specified. If it is kyotocabinet::INT64MIN, the logger is opened as reader.
asithe interval of auto synchronization. If it is not more than 0, auto synchronization is not performed.
Returns:
true on success, or false on failure.

Close the logger.

Returns:
true on success, or false on failure.
bool kyototycoon::UpdateLogger::write ( const char *  mbuf,
size_t  msiz,
uint64_t  ts = 0 
)

Write a log message.

Parameters:
mbufthe pointer to the message region.
msizthe size of the message region.
tsthe time stamp of the message. If it is not more than 0, the current time stamp is specified.
Returns:
true on success, or false on failure.
bool kyototycoon::UpdateLogger::write_volatile ( char *  mbuf,
size_t  msiz,
uint64_t  ts = 0 
)

Write a log message with a volatile buffer.

Parameters:
mbufthe pointer to the message region which is allocated by the new[] operator.
msizthe size of the message region.
tsthe time stamp of the message. If it is not more than 0, the current time stamp is specified.
Returns:
true on success, or false on failure.
Note:
the message region is to be deleted inside this object implicitly.
bool kyototycoon::UpdateLogger::write_bulk ( const std::vector< std::string > &  mvec,
uint64_t  ts = 0 
)

Write multiple log messages at once.

Parameters:
mveca string vector of log messages.
tsthe time stamp of the message. If it is not more than 0, the current time stamp is specified.
Returns:
true on success, or false on failure.

Get the current clock data for time stamp.

Returns:
the current clock data for time stamp.
void kyototycoon::UpdateLogger::list_files ( std::vector< FileStatus > *  fstvec)

Get status of each log files.

Parameters:
fstveca vector to store status structures of each log files.
static uint64_t kyototycoon::UpdateLogger::clock_pure ( ) [static]

Get the current pure clock data for time stamp.

Returns:
the current pure clock data for time stamp.
kyototycoon-0.9.56/doc/api/doxygen.css0000644000175000017500000003516511757471600016745 0ustar mikiomikio/* The standard CSS for doxygen */ body, table, div, p, dl { font-family: Lucida Grande, Verdana, Geneva, Arial, sans-serif; font-size: 13px; line-height: 1.3; } /* @group Heading Levels */ h1 { font-size: 150%; } .title { font-size: 150%; font-weight: bold; margin: 10px 2px; } h2 { font-size: 120%; } h3 { font-size: 100%; } dt { font-weight: bold; } div.multicol { -moz-column-gap: 1em; -webkit-column-gap: 1em; -moz-column-count: 3; -webkit-column-count: 3; } p.startli, p.startdd, p.starttd { margin-top: 2px; } p.endli { margin-bottom: 0px; } p.enddd { margin-bottom: 4px; } p.endtd { margin-bottom: 2px; } /* @end */ caption { font-weight: bold; } span.legend { font-size: 70%; text-align: center; } h3.version { font-size: 90%; text-align: center; } div.qindex, div.navtab{ background-color: #EBEFF6; border: 1px solid #A3B4D7; text-align: center; } div.qindex, div.navpath { width: 100%; line-height: 140%; } div.navtab { margin-right: 15px; } /* @group Link Styling */ a { color: #3D578C; font-weight: normal; text-decoration: none; } .contents a:visited { color: #4665A2; } a:hover { text-decoration: underline; } a.qindex { font-weight: bold; } a.qindexHL { font-weight: bold; background-color: #9CAFD4; color: #ffffff; border: 1px double #869DCA; } .contents a.qindexHL:visited { color: #ffffff; } a.el { font-weight: bold; } a.elRef { } a.code, a.code:visited { color: #4665A2; } a.codeRef, a.codeRef:visited { color: #4665A2; } /* @end */ dl.el { margin-left: -1cm; } .fragment { font-family: monospace, fixed; font-size: 105%; } pre.fragment { border: 1px solid #C4CFE5; background-color: #FBFCFD; padding: 4px 6px; margin: 4px 8px 4px 2px; overflow: auto; word-wrap: break-word; font-size: 9pt; line-height: 125%; } div.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px; padding: 0.2em; border: solid thin #333; border-radius: 0.5em; -webkit-border-radius: .5em; -moz-border-radius: .5em; box-shadow: 2px 2px 3px #999; -webkit-box-shadow: 2px 2px 3px #999; -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000); } div.groupHeader { margin-left: 16px; margin-top: 12px; font-weight: bold; } div.groupText { margin-left: 16px; font-style: italic; } body { background-color: white; color: black; margin: 0; } div.contents { margin-top: 10px; margin-left: 8px; margin-right: 8px; } td.indexkey { background-color: #EBEFF6; font-weight: bold; border: 1px solid #C4CFE5; margin: 2px 0px 2px 0; padding: 2px 10px; white-space: nowrap; vertical-align: top; } td.indexvalue { background-color: #EBEFF6; border: 1px solid #C4CFE5; padding: 2px 10px; margin: 2px 0px; } tr.memlist { background-color: #EEF1F7; } p.formulaDsp { text-align: center; } img.formulaDsp { } img.formulaInl { vertical-align: middle; } div.center { text-align: center; margin-top: 0px; margin-bottom: 0px; padding: 0px; } div.center img { border: 0px; } address.footer { text-align: right; padding-right: 12px; } img.footer { border: 0px; vertical-align: middle; } /* @group Code Colorization */ span.keyword { color: #008000 } span.keywordtype { color: #604020 } span.keywordflow { color: #e08000 } span.comment { color: #800000 } span.preprocessor { color: #806020 } span.stringliteral { color: #002080 } span.charliteral { color: #008080 } span.vhdldigit { color: #ff00ff } span.vhdlchar { color: #000000 } span.vhdlkeyword { color: #700070 } span.vhdllogic { color: #ff0000 } /* @end */ /* .search { color: #003399; font-weight: bold; } form.search { margin-bottom: 0px; margin-top: 0px; } input.search { font-size: 75%; color: #000080; font-weight: normal; background-color: #e8eef2; } */ td.tiny { font-size: 75%; } .dirtab { padding: 4px; border-collapse: collapse; border: 1px solid #A3B4D7; } th.dirtab { background: #EBEFF6; font-weight: bold; } hr { height: 0px; border: none; border-top: 1px solid #4A6AAA; } hr.footer { height: 1px; } /* @group Member Descriptions */ table.memberdecls { border-spacing: 0px; padding: 0px; } .mdescLeft, .mdescRight, .memItemLeft, .memItemRight, .memTemplItemLeft, .memTemplItemRight, .memTemplParams { background-color: #F9FAFC; border: none; margin: 4px; padding: 1px 0 0 8px; } .mdescLeft, .mdescRight { padding: 0px 8px 4px 8px; color: #555; } .memItemLeft, .memItemRight, .memTemplParams { border-top: 1px solid #C4CFE5; } .memItemLeft, .memTemplItemLeft { white-space: nowrap; } .memItemRight { width: 100%; } .memTemplParams { color: #4665A2; white-space: nowrap; } /* @end */ /* @group Member Details */ /* Styles for detailed member documentation */ .memtemplate { font-size: 80%; color: #4665A2; font-weight: normal; margin-left: 9px; } .memnav { background-color: #EBEFF6; border: 1px solid #A3B4D7; text-align: center; margin: 2px; margin-right: 15px; padding: 2px; } .mempage { width: 100%; } .memitem { padding: 0; margin-bottom: 10px; margin-right: 5px; } .memname { white-space: nowrap; font-weight: bold; margin-left: 6px; } .memproto, dl.reflist dt { border-top: 1px solid #A8B8D9; border-left: 1px solid #A8B8D9; border-right: 1px solid #A8B8D9; padding: 6px 0px 6px 0px; color: #253555; font-weight: bold; text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); /* opera specific markup */ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); border-top-right-radius: 8px; border-top-left-radius: 8px; /* firefox specific markup */ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; -moz-border-radius-topright: 8px; -moz-border-radius-topleft: 8px; /* webkit specific markup */ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); -webkit-border-top-right-radius: 8px; -webkit-border-top-left-radius: 8px; background-image:url('nav_f.png'); background-repeat:repeat-x; background-color: #E2E8F2; } .memdoc, dl.reflist dd { border-bottom: 1px solid #A8B8D9; border-left: 1px solid #A8B8D9; border-right: 1px solid #A8B8D9; padding: 2px 5px; background-color: #FBFCFD; border-top-width: 0; /* opera specific markup */ border-bottom-left-radius: 8px; border-bottom-right-radius: 8px; box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); /* firefox specific markup */ -moz-border-radius-bottomleft: 8px; -moz-border-radius-bottomright: 8px; -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; background-image: -moz-linear-gradient(center top, #FFFFFF 0%, #FFFFFF 60%, #F7F8FB 95%, #EEF1F7); /* webkit specific markup */ -webkit-border-bottom-left-radius: 8px; -webkit-border-bottom-right-radius: 8px; -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); background-image: -webkit-gradient(linear,center top,center bottom,from(#FFFFFF), color-stop(0.6,#FFFFFF), color-stop(0.60,#FFFFFF), color-stop(0.95,#F7F8FB), to(#EEF1F7)); } dl.reflist dt { padding: 5px; } dl.reflist dd { margin: 0px 0px 10px 0px; padding: 5px; } .paramkey { text-align: right; } .paramtype { white-space: nowrap; } .paramname { color: #602020; white-space: nowrap; } .paramname em { font-style: normal; } .params, .retval, .exception, .tparams { border-spacing: 6px 2px; } .params .paramname, .retval .paramname { font-weight: bold; vertical-align: top; } .params .paramtype { font-style: italic; vertical-align: top; } .params .paramdir { font-family: "courier new",courier,monospace; vertical-align: top; } /* @end */ /* @group Directory (tree) */ /* for the tree view */ .ftvtree { font-family: sans-serif; margin: 0px; } /* these are for tree view when used as main index */ .directory { font-size: 9pt; font-weight: bold; margin: 5px; } .directory h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } /* The following two styles can be used to replace the root node title with an image of your choice. Simply uncomment the next two styles, specify the name of your image and be sure to set 'height' to the proper pixel height of your image. */ /* .directory h3.swap { height: 61px; background-repeat: no-repeat; background-image: url("yourimage.gif"); } .directory h3.swap span { display: none; } */ .directory > h3 { margin-top: 0; } .directory p { margin: 0px; white-space: nowrap; } .directory div { display: none; margin: 0px; } .directory img { vertical-align: -30%; } /* these are for tree view when not used as main index */ .directory-alt { font-size: 100%; font-weight: bold; } .directory-alt h3 { margin: 0px; margin-top: 1em; font-size: 11pt; } .directory-alt > h3 { margin-top: 0; } .directory-alt p { margin: 0px; white-space: nowrap; } .directory-alt div { display: none; margin: 0px; } .directory-alt img { vertical-align: -30%; } /* @end */ div.dynheader { margin-top: 8px; } address { font-style: normal; color: #2A3D61; } table.doxtable { border-collapse:collapse; } table.doxtable td, table.doxtable th { border: 1px solid #2D4068; padding: 3px 7px 2px; } table.doxtable th { background-color: #374F7F; color: #FFFFFF; font-size: 110%; padding-bottom: 4px; padding-top: 5px; text-align:left; } table.fieldtable { width: 100%; margin-bottom: 10px; border: 1px solid #A8B8D9; border-spacing: 0px; -moz-border-radius: 4px; -webkit-border-radius: 4px; border-radius: 4px; -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); } .fieldtable td, .fieldtable th { padding: 3px 7px 2px; } .fieldtable td.fieldtype, .fieldtable td.fieldname { white-space: nowrap; border-right: 1px solid #A8B8D9; border-bottom: 1px solid #A8B8D9; vertical-align: top; } .fieldtable td.fielddoc { border-bottom: 1px solid #A8B8D9; width: 100%; } .fieldtable tr:last-child td { border-bottom: none; } .fieldtable th { background-image:url('nav_f.png'); background-repeat:repeat-x; background-color: #E2E8F2; font-size: 90%; color: #253555; padding-bottom: 4px; padding-top: 5px; text-align:left; -moz-border-radius-topleft: 4px; -moz-border-radius-topright: 4px; -webkit-border-top-left-radius: 4px; -webkit-border-top-right-radius: 4px; border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom: 1px solid #A8B8D9; } .tabsearch { top: 0px; left: 10px; height: 36px; background-image: url('tab_b.png'); z-index: 101; overflow: hidden; font-size: 13px; } .navpath ul { font-size: 11px; background-image:url('tab_b.png'); background-repeat:repeat-x; height:30px; line-height:30px; color:#8AA0CC; border:solid 1px #C2CDE4; overflow:hidden; margin:0px; padding:0px; } .navpath li { list-style-type:none; float:left; padding-left:10px; padding-right:15px; background-image:url('bc_s.png'); background-repeat:no-repeat; background-position:right; color:#364D7C; } .navpath li.navelem a { height:32px; display:block; text-decoration: none; outline: none; } .navpath li.navelem a:hover { color:#6884BD; } .navpath li.footer { list-style-type:none; float:right; padding-left:10px; padding-right:15px; background-image:none; background-repeat:no-repeat; background-position:right; color:#364D7C; font-size: 8pt; } div.summary { float: right; font-size: 8pt; padding-right: 5px; width: 50%; text-align: right; } div.summary a { white-space: nowrap; } div.ingroups { margin-left: 5px; font-size: 8pt; padding-left: 5px; width: 50%; text-align: left; } div.ingroups a { white-space: nowrap; } div.header { background-image:url('nav_h.png'); background-repeat:repeat-x; background-color: #F9FAFC; margin: 0px; border-bottom: 1px solid #C4CFE5; } div.headertitle { padding: 5px 5px 5px 7px; } dl { padding: 0 0 0 10px; } dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug { border-left:4px solid; padding: 0 0 0 6px; } dl.note { border-color: #D0C000; } dl.warning, dl.attention { border-color: #FF0000; } dl.pre, dl.post, dl.invariant { border-color: #00D000; } dl.deprecated { border-color: #505050; } dl.todo { border-color: #00C0E0; } dl.test { border-color: #3030E0; } dl.bug { border-color: #C08050; } #projectlogo { text-align: center; vertical-align: bottom; border-collapse: separate; } #projectlogo img { border: 0px none; } #projectname { font: 300% Tahoma, Arial,sans-serif; margin: 0px; padding: 2px 0px; } #projectbrief { font: 120% Tahoma, Arial,sans-serif; margin: 0px; padding: 0px; } #projectnumber { font: 50% Tahoma, Arial,sans-serif; margin: 0px; padding: 0px; } #titlearea { padding: 0px; margin: 0px; width: 100%; border-bottom: 1px solid #5373B4; } .image { text-align: center; } .dotgraph { text-align: center; } .mscgraph { text-align: center; } .caption { font-weight: bold; } div.zoom { border: 1px solid #90A5CE; } dl.citelist { margin-bottom:50px; } dl.citelist dt { color:#334975; float:left; font-weight:bold; margin-right:10px; padding:5px; } dl.citelist dd { margin:2px 0; padding:5px 0; } @media print { #top { display: none; } #side-nav { display: none; } #nav-path { display: none; } body { overflow:visible; } h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } .summary { display: none; } .memitem { page-break-inside: avoid; } #doc-content { margin-left:0 !important; height:auto !important; width:auto !important; overflow:inherit; display:inline; } pre.fragment { overflow: visible; text-wrap: unrestricted; white-space: -moz-pre-wrap; /* Moz */ white-space: -pre-wrap; /* Opera 4-6 */ white-space: -o-pre-wrap; /* Opera 7 */ white-space: pre-wrap; /* CSS3 */ word-wrap: break-word; /* IE 5.5+ */ } } kyototycoon-0.9.56/doc/api/functions_func_0x6e.html0000644000175000017500000001113411757471600021317 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/functions_0x6f.html0000644000175000017500000001472111757471600020312 0ustar mikiomikio Kyoto Tycoon: Class Members kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ServerSocket.html0000644000175000017500000004414111757471600024065 0ustar mikiomikio Kyoto Tycoon: kyototycoon::ServerSocket Class Reference
kyototycoon::ServerSocket Class Reference

Network server abstraction based on TCP/IP. More...

#include <ktsocket.h>

List of all members.

Public Member Functions

 ServerSocket ()
 Default constructor.
 ~ServerSocket ()
 Destructor.
const char * error ()
 Get the last happened error information.
bool open (const std::string &expr)
 Open a server socket.
bool close ()
 Close the socket.
bool accept (Socket *sock)
 Accept a connection from a client.
bool abort ()
 Abort the current operation.
bool set_timeout (double timeout)
 Set the timeout of each operation.
const std::string expression ()
 Get the expression of the socket.
int32_t descriptor ()
 Get the descriptor integer.
void set_event_flags (uint32_t flags)
 Set event flags.
uint32_t event_flags ()
 Get the current event flags.

Detailed Description

Network server abstraction based on TCP/IP.


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

Get the last happened error information.

Returns:
the last happened error information.
bool kyototycoon::ServerSocket::open ( const std::string &  expr)

Open a server socket.

Parameters:
expran expression of the address and the port of the server.
Returns:
true on success, or false on failure.

Close the socket.

Returns:
true on success, or false on failure.

Accept a connection from a client.

Parameters:
sockthe socket object to manage the connection.
Returns:
true on success, or false on failure.

Abort the current operation.

Returns:
true on success, or false on failure.
bool kyototycoon::ServerSocket::set_timeout ( double  timeout)

Set the timeout of each operation.

Parameters:
timeoutthe timeout of each operation in seconds.
Returns:
true on success, or false on failure.

Get the expression of the socket.

Returns:
the expression of the socket or an empty string on failure.

Get the descriptor integer.

Returns:
the descriptor integer, or -1 on failure.

Implements kyototycoon::Pollable.

void kyototycoon::ServerSocket::set_event_flags ( uint32_t  flags) [virtual]

Set event flags.

Parameters:
flagsspecifies the event mode. The following may be added by bitwise-or: ServerSocket::EVINPUT for input events, ServerSocket::EVOUTPUT for output events, ServerSocket::EVERROR for error events.

Implements kyototycoon::Pollable.

Get the current event flags.

Returns:
the current event flags.

Implements kyototycoon::Pollable.

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer_1_1Logger.html0000644000175000017500000001054111757471600025056 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RPCServer::Logger Class Reference
kyototycoon::RPCServer::Logger Class Reference

Interface to log internal information and errors. More...

#include <ktrpc.h>

List of all members.

Public Member Functions

virtual ~Logger ()
 Destructor.

Detailed Description

Interface to log internal information and errors.


Constructor & Destructor Documentation

Destructor.

Reimplemented from kyototycoon::HTTPServer::Logger.

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1TimedDB_1_1UpdateTrigger-members.html0000644000175000017500000000751311757471600027477 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::TimedDB::UpdateTrigger Member List
This is the complete list of members for kyototycoon::TimedDB::UpdateTrigger, including all inherited members.
begin_transaction()=0kyototycoon::TimedDB::UpdateTrigger [pure virtual]
end_transaction(bool commit)=0kyototycoon::TimedDB::UpdateTrigger [pure virtual]
trigger(const char *mbuf, size_t msiz)=0kyototycoon::TimedDB::UpdateTrigger [pure virtual]
~UpdateTrigger()kyototycoon::TimedDB::UpdateTrigger [virtual]
kyototycoon-0.9.56/doc/api/tabs.css0000644000175000017500000000210711757471600016207 0ustar mikiomikio.tabs, .tabs2, .tabs3 { background-image: url('tab_b.png'); width: 100%; z-index: 101; font-size: 13px; } .tabs2 { font-size: 10px; } .tabs3 { font-size: 9px; } .tablist { margin: 0; padding: 0; display: table; } .tablist li { float: left; display: table-cell; background-image: url('tab_b.png'); line-height: 36px; list-style: none; } .tablist a { display: block; padding: 0 20px; font-weight: bold; background-image:url('tab_s.png'); background-repeat:no-repeat; background-position:right; color: #283A5D; text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); text-decoration: none; outline: none; } .tabs3 .tablist a { padding: 0 10px; } .tablist a:hover { background-image: url('tab_h.png'); background-repeat:repeat-x; color: #fff; text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); text-decoration: none; } .tablist li.current a { background-image: url('tab_a.png'); background-repeat:repeat-x; color: #fff; text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); } kyototycoon-0.9.56/doc/api/functions_func_0x70.html0000644000175000017500000002013011757471600021227 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/functions_func_0x6f.html0000644000175000017500000001406511757471600021326 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/functions_func_0x65.html0000644000175000017500000001643711757471600021252 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/classkyototycoon_1_1MapReduce_1_1ValueIterator.html0000644000175000017500000001201711757471600026457 0ustar mikiomikio Kyoto Tycoon: kyototycoon::MapReduce::ValueIterator Class Reference
kyototycoon::MapReduce::ValueIterator Class Reference

Value iterator for the reducer. More...

#include <ktdbext.h>

List of all members.

Public Member Functions

const char * next (size_t *sp)
 Get the next value.

Friends

class MapReduce

Detailed Description

Value iterator for the reducer.


Member Function Documentation

const char* kyototycoon::MapReduce::ValueIterator::next ( size_t *  sp)

Get the next value.

Parameters:
spthe pointer to the variable into which the size of the region of the return value is assigned.
Returns:
the pointer to the next value region, or NULL if no value remains.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1TimedDB_1_1Cursor-members.html0000644000175000017500000002324511757471600026206 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::TimedDB::Cursor Member List
This is the complete list of members for kyototycoon::TimedDB::Cursor, including all inherited members.
accept(Visitor *visitor, bool writable=true, bool step=false)kyototycoon::TimedDB::Cursor
Cursor(TimedDB *db)kyototycoon::TimedDB::Cursor [explicit]
db()kyototycoon::TimedDB::Cursor
error()kyototycoon::TimedDB::Cursor
get(size_t *ksp, const char **vbp, size_t *vsp, int64_t *xtp=NULL, bool step=false)kyototycoon::TimedDB::Cursor
get(std::string *key, std::string *value, int64_t *xtp=NULL, bool step=false)kyototycoon::TimedDB::Cursor
get_key(size_t *sp, bool step=false)kyototycoon::TimedDB::Cursor
get_key(std::string *key, bool step=false)kyototycoon::TimedDB::Cursor
get_value(size_t *sp, bool step=false)kyototycoon::TimedDB::Cursor
get_value(std::string *value, bool step=false)kyototycoon::TimedDB::Cursor
jump()kyototycoon::TimedDB::Cursor
jump(const char *kbuf, size_t ksiz)kyototycoon::TimedDB::Cursor
jump(const std::string &key)kyototycoon::TimedDB::Cursor
jump_back()kyototycoon::TimedDB::Cursor
jump_back(const char *kbuf, size_t ksiz)kyototycoon::TimedDB::Cursor
jump_back(const std::string &key)kyototycoon::TimedDB::Cursor
remove()kyototycoon::TimedDB::Cursor
seize(size_t *ksp, const char **vbp, size_t *vsp, int64_t *xtp=NULL)kyototycoon::TimedDB::Cursor
seize(std::string *key, std::string *value, int64_t *xtp=NULL)kyototycoon::TimedDB::Cursor
set_value(const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX, bool step=false)kyototycoon::TimedDB::Cursor
set_value_str(const std::string &value, int64_t xt=kc::INT64MAX, bool step=false)kyototycoon::TimedDB::Cursor
step()kyototycoon::TimedDB::Cursor
step_back()kyototycoon::TimedDB::Cursor
TimedDB (defined in kyototycoon::TimedDB::Cursor)kyototycoon::TimedDB::Cursor [friend]
~Cursor()kyototycoon::TimedDB::Cursor [virtual]
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1TimedDB_1_1Visitor-members.html0000644000175000017500000001120211757471600026356 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::TimedDB::Visitor Member List
This is the complete list of members for kyototycoon::TimedDB::Visitor, including all inherited members.
NOPkyototycoon::TimedDB::Visitor [static]
REMOVEkyototycoon::TimedDB::Visitor [static]
visit_after()kyototycoon::TimedDB::Visitor [virtual]
visit_before()kyototycoon::TimedDB::Visitor [virtual]
visit_empty(const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp)kyototycoon::TimedDB::Visitor [virtual]
visit_full(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, size_t *sp, int64_t *xtp)kyototycoon::TimedDB::Visitor [virtual]
~Visitor()kyototycoon::TimedDB::Visitor [virtual]
kyototycoon-0.9.56/doc/api/functions_func_0x66.html0000644000175000017500000001232211757471600021240 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/functions_0x67.html0000644000175000017500000001545511757471600020240 0ustar mikiomikio Kyoto Tycoon: Class Members kyototycoon-0.9.56/doc/api/functions_func_0x73.html0000644000175000017500000003414411757471600021244 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions
 

- s -

kyototycoon-0.9.56/doc/api/hierarchy.html0000644000175000017500000001451311757471600017414 0ustar mikiomikio Kyoto Tycoon: Class Hierarchy
Class Hierarchy
kyototycoon-0.9.56/doc/api/ktplugserv_8h.html0000644000175000017500000001203611757471600020241 0ustar mikiomikio Kyoto Tycoon: ktplugserv.h File Reference
ktplugserv.h File Reference

pluggable server interface More...

#include <ktcommon.h>
#include <ktutil.h>
#include <ktsocket.h>
#include <ktthserv.h>
#include <kthttp.h>
#include <ktrpc.h>
#include <ktulog.h>
#include <ktshlib.h>
#include <kttimeddb.h>
#include <ktdbext.h>
#include <ktremotedb.h>

Classes

class  kyototycoon::PluggableServer
 Interface of pluggable server abstraction. More...

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.


Typedefs

typedef PluggableServer *(* kyototycoon::KTSERVINIT )()
 Initializer of a server implementation.

Variables

const char *const kyototycoon::KTSERVINITNAME = "ktservinit"
 The name of the initializer function.

Detailed Description

pluggable server interface

kyototycoon-0.9.56/doc/api/functions_0x68.html0000644000175000017500000001132611757471600020232 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- h -

kyototycoon-0.9.56/doc/api/functions_enum.html0000644000175000017500000000727011757471600020474 0ustar mikiomikio Kyoto Tycoon: Class Members - Enumerations kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ServerSocket-members.html0000644000175000017500000001610611757471600025515 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::ServerSocket Member List
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer-members.html0000644000175000017500000001422511757471600025044 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::HTTPServer Member List
This is the complete list of members for kyototycoon::HTTPServer, including all inherited members.
finish()kyototycoon::HTTPServer
HTTPServer()kyototycoon::HTTPServer [explicit]
localize_path(const std::string &path)kyototycoon::HTTPServer [static]
log(Logger::Kind kind, const char *format,...)kyototycoon::HTTPServer
log_v(Logger::Kind kind, const char *format, va_list ap)kyototycoon::HTTPServer
media_type(const std::string &url)kyototycoon::HTTPServer [static]
reveal_core()kyototycoon::HTTPServer
set_logger(Logger *logger, uint32_t kinds=Logger::SYSTEM|Logger::ERROR)kyototycoon::HTTPServer
set_network(const std::string &expr, double timeout=-1, const std::string &name="")kyototycoon::HTTPServer
set_worker(Worker *worker, size_t thnum=1)kyototycoon::HTTPServer
start()kyototycoon::HTTPServer
status_name(int32_t code)kyototycoon::HTTPServer [static]
stop()kyototycoon::HTTPServer
~HTTPServer()kyototycoon::HTTPServer
kyototycoon-0.9.56/doc/api/functions_0x66.html0000644000175000017500000001253711757471600020235 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- f -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCClient.html0000644000175000017500000004510011757471600023225 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RPCClient Class Reference
kyototycoon::RPCClient Class Reference

RPC client. More...

#include <ktrpc.h>

List of all members.

Public Types

enum  ReturnValue {
  RVSUCCESS, RVENOIMPL, RVEINVALID, RVELOGIC,
  RVETIMEOUT, RVEINTERNAL, RVENETWORK, RVEMISC = 15
}
 Return value. More...

Public Member Functions

 RPCClient ()
 Default constructor.
 ~RPCClient ()
 Destructor.
bool open (const std::string &host="", int32_t port=DEFPORT, double timeout=-1)
 Open the connection.
bool close (bool grace=true)
 Close the connection.
ReturnValue call (const std::string &name, const std::map< std::string, std::string > *inmap=NULL, std::map< std::string, std::string > *outmap=NULL)
 Call a remote procedure.
const std::string expression ()
 Get the expression of the socket.
HTTPClientreveal_core ()
 Reveal the internal HTTP client.

Detailed Description

RPC client.

Note:
Although all methods of this class are thread-safe, its instance does not have mutual exclusion mechanism. So, multiple threads must not share the same instance and they must use their own respective instances.

Member Enumeration Documentation

Return value.

Enumerator:
RVSUCCESS 

success

RVENOIMPL 

not implemented

RVEINVALID 

invalid operation

RVELOGIC 

logical inconsistency

RVETIMEOUT 

timeout

RVEINTERNAL 

internal error

RVENETWORK 

network error

RVEMISC 

miscellaneous error


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

bool kyototycoon::RPCClient::open ( const std::string &  host = "",
int32_t  port = DEFPORT,
double  timeout = -1 
)

Open the connection.

Parameters:
hostthe name or the address of the server. If it is an empty string, the local host is specified.
portthe port numger of the server.
timeoutthe timeout of each operation in seconds. If it is not more than 0, no timeout is specified.
Returns:
true on success, or false on failure.
bool kyototycoon::RPCClient::close ( bool  grace = true)

Close the connection.

Parameters:
gracetrue for graceful shutdown, or false for immediate disconnection.
Returns:
true on success, or false on failure.
ReturnValue kyototycoon::RPCClient::call ( const std::string &  name,
const std::map< std::string, std::string > *  inmap = NULL,
std::map< std::string, std::string > *  outmap = NULL 
)

Call a remote procedure.

Parameters:
namethe name of the procecude.
inmapa string map which contains the input of the procedure. If it is NULL, it is ignored.
outmapa string map to contain the output parameters. If it is NULL, it is ignored.
Returns:
the return value of the procedure.
const std::string kyototycoon::RPCClient::expression ( )

Get the expression of the socket.

Returns:
the expression of the socket or an empty string on failure.

Reveal the internal HTTP client.

Returns:
the internal HTTP client.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1SharedLibrary-members.html0000644000175000017500000000726111757471600025633 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::SharedLibrary Member List
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer_1_1Worker.html0000644000175000017500000004302211757471600025243 0ustar mikiomikio Kyoto Tycoon: kyototycoon::HTTPServer::Worker Class Reference
kyototycoon::HTTPServer::Worker Class Reference

Interface to process each request. More...

#include <kthttp.h>

List of all members.

Public Member Functions

virtual ~Worker ()
 Destructor.
virtual int32_t process (HTTPServer *serv, Session *sess, const std::string &path, HTTPClient::Method method, const std::map< std::string, std::string > &reqheads, const std::string &reqbody, std::map< std::string, std::string > &resheads, std::string &resbody, const std::map< std::string, std::string > &misc)=0
 Process each request.
virtual bool process_binary (ThreadedServer *serv, ThreadedServer::Session *sess)
 Process each binary request.
virtual void process_idle (HTTPServer *serv)
 Process each idle event.
virtual void process_timer (HTTPServer *serv)
 Process each timer event.
virtual void process_start (HTTPServer *serv)
 Process the starting event.
virtual void process_finish (HTTPServer *serv)
 Process the finishing event.

Detailed Description

Interface to process each request.


Constructor & Destructor Documentation

Destructor.


Member Function Documentation

virtual int32_t kyototycoon::HTTPServer::Worker::process ( HTTPServer serv,
Session sess,
const std::string &  path,
HTTPClient::Method  method,
const std::map< std::string, std::string > &  reqheads,
const std::string &  reqbody,
std::map< std::string, std::string > &  resheads,
std::string &  resbody,
const std::map< std::string, std::string > &  misc 
) [pure virtual]

Process each request.

Parameters:
servthe server.
sessthe session with the client.
paththe path of the requested resource.
methodthe kind of the request methods.
reqheadsa string map which contains the headers of the request. Header names are converted into lower cases. The empty key means the request-line.
reqbodya string which contains the entity body of the request.
resheadsa string map to contain the headers of the response.
resbodya string to contain the entity body of the response.
misca string map which contains miscellaneous information. "url" means the absolute URL. "query" means the query string of the URL.
Returns:
the status code of the response. If it is less than 1, internal server error is sent to the client and the connection is closed.

Process each binary request.

Parameters:
servthe server.
sessthe session with the client.
Returns:
true to reuse the session, or false to close the session.
virtual void kyototycoon::HTTPServer::Worker::process_idle ( HTTPServer serv) [virtual]

Process each idle event.

Parameters:
servthe server.
virtual void kyototycoon::HTTPServer::Worker::process_timer ( HTTPServer serv) [virtual]

Process each timer event.

Parameters:
servthe server.
virtual void kyototycoon::HTTPServer::Worker::process_start ( HTTPServer serv) [virtual]

Process the starting event.

Parameters:
servthe server.
virtual void kyototycoon::HTTPServer::Worker::process_finish ( HTTPServer serv) [virtual]

Process the finishing event.

Parameters:
servthe server.
kyototycoon-0.9.56/doc/api/functions_0x77.html0000644000175000017500000001227011757471600020231 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- w -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer_1_1Worker-members.html0000644000175000017500000001270611757471600026545 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RPCServer::Worker Member List
This is the complete list of members for kyototycoon::RPCServer::Worker, including all inherited members.
process(RPCServer *serv, Session *sess, const std::string &name, const std::map< std::string, std::string > &inmap, std::map< std::string, std::string > &outmap)=0kyototycoon::RPCServer::Worker [pure virtual]
process(HTTPServer *serv, HTTPServer::Session *sess, const std::string &path, HTTPClient::Method method, const std::map< std::string, std::string > &reqheads, const std::string &reqbody, std::map< std::string, std::string > &resheads, std::string &resbody, const std::map< std::string, std::string > &misc)kyototycoon::RPCServer::Worker [virtual]
process_binary(ThreadedServer *serv, ThreadedServer::Session *sess)kyototycoon::RPCServer::Worker [virtual]
process_finish(RPCServer *serv)kyototycoon::RPCServer::Worker [virtual]
process_idle(RPCServer *serv)kyototycoon::RPCServer::Worker [virtual]
process_start(RPCServer *serv)kyototycoon::RPCServer::Worker [virtual]
process_timer(RPCServer *serv)kyototycoon::RPCServer::Worker [virtual]
~Worker()kyototycoon::RPCServer::Worker [virtual]
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1UpdateLogger_1_1Reader-members.html0000644000175000017500000000773211757471600027250 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::UpdateLogger::Reader Member List
This is the complete list of members for kyototycoon::UpdateLogger::Reader, including all inherited members.
close()kyototycoon::UpdateLogger::Reader
open(UpdateLogger *ulog, uint64_t ts=0)kyototycoon::UpdateLogger::Reader
read(size_t *sp, uint64_t *tsp)kyototycoon::UpdateLogger::Reader
Reader()kyototycoon::UpdateLogger::Reader [explicit]
~Reader()kyototycoon::UpdateLogger::Reader
kyototycoon-0.9.56/doc/api/functions_vars.html0000644000175000017500000001057311757471600020503 0ustar mikiomikio Kyoto Tycoon: Class Members - Variables ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootkyototycoon-0.9.56/doc/api/classkyototycoon_1_1MapReduce_1_1ReduceTaskQueue_1_1ReduceTask-members.htmlkyototycoon-0.9.56/doc/api/classkyototycoon_1_1MapReduce_1_1ReduceTaskQueue_1_1ReduceTask-members.ht0000644000175000017500000000676111757471600032453 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::MapReduce::ReduceTaskQueue::ReduceTask Member List
This is the complete list of members for kyototycoon::MapReduce::ReduceTaskQueue::ReduceTask, including all inherited members.
ReduceTask(MapReduce *mr, const char *kbuf, size_t ksiz, const Values &values)kyototycoon::MapReduce::ReduceTaskQueue::ReduceTask [explicit]
ReduceTaskQueue (defined in kyototycoon::MapReduce::ReduceTaskQueue::ReduceTask)kyototycoon::MapReduce::ReduceTaskQueue::ReduceTask [friend]
kyototycoon-0.9.56/doc/api/bc_s.png0000644000175000017500000000124511757471600016162 0ustar mikiomikio‰PNG  IHDR /ð9ÐlIDATxíÝKHTmðÿóžwfÎgæÌ¯å8ŽÓ˜—Š6ñ-BÚ´‘]d–VZMa…D}ßg¸háB¤¶*Ñýbå¥U9Š—3ƒŽFy<£‹ šaæè²í³yøÿÎóžÅóî©ýÁÇåþtðªÚ %”8Vj•LÜlø·ÅCF@mÃÿˆÞ[”ïü À7ªj¿RÀ•ûC0TâU‹Y¸øYÕú’ÿsv~Æî,Ûi)€.w €™ˆæwø\cT i Ðúÿ`¼owgÛö»âH0¤5%À¥ÿ>Äû\.°ÉÒ×*O0¬-c}BàÞûä+msË…VÑÔ5Ö:€Îß}— *l’©Çç–cÁV¸€OÅ^ÅaâìÔXxñ)µÜ0‚ãé²xrKfÚÜxx±Ššo½5Ièk±WaŒÑjºùÆà¶;ÛVá´[¨ñÆ«Í@¥ÃfnöäØ¿°ÍRÕ.‡¨¬®B¥×_C™ˆæK|.¬ý²Ÿ®½0‚3ŠTŸ¥H¡‰½†Ž¶=7‚ ßã´™8k˜œÑ_Ó‘«Ï’Ã2«Èz·:V&fôBv—Ní9iVÎY— Õµ>‰‡.Qx{¾E“³ú»Ê‡˜'‰|dj6ÚØ‡ÚÀãx?åÏsJ‚@uÓ‘hbI„Ò½‡Ö2ì“,¼F¶[bÓ‘h e'«Ïõ@;Û^d•x·‰þ›¶ôg2Fa¿G^ÿ @,é) êlß… §Të’-ãêÜRý†—UÙÜ*È•EΩ64·4lÜÄÙ #èjDßþú Ųo{”N IEND®B`‚kyototycoon-0.9.56/doc/api/functions_func_0x77.html0000644000175000017500000001156011757471600021245 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions
 

- w -

kyototycoon-0.9.56/doc/api/functions_func_0x75.html0000644000175000017500000001174711757471600021252 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions
 

- u -

kyototycoon-0.9.56/doc/api/open.png0000644000175000017500000000016611757471600016216 0ustar mikiomikio‰PNG  IHDR à‘=IDATxí1 “ت¦@@   ]01ÀQXY~Jr?D>„¥¶þ’n¼ áFÍ  }ÈúÂéãÏ\ ÄáÿòIEND®B`‚kyototycoon-0.9.56/doc/api/classkyototycoon_1_1MapReduce_1_1ValueIterator-members.html0000644000175000017500000000626211757471600030114 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::MapReduce::ValueIterator Member List
This is the complete list of members for kyototycoon::MapReduce::ValueIterator, including all inherited members.
MapReduce (defined in kyototycoon::MapReduce::ValueIterator)kyototycoon::MapReduce::ValueIterator [friend]
next(size_t *sp)kyototycoon::MapReduce::ValueIterator
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPClient-members.html0000644000175000017500000001613411757471600025015 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::HTTPClient Member List
This is the complete list of members for kyototycoon::HTTPClient, including all inherited members.
close(bool grace=true)kyototycoon::HTTPClient
fetch(const std::string &pathquery, Method method=MGET, std::string *resbody=NULL, std::map< std::string, std::string > *resheads=NULL, const std::string *reqbody=NULL, const std::map< std::string, std::string > *reqheads=NULL)kyototycoon::HTTPClient
fetch_once(const std::string &url, Method method=MGET, std::string *resbody=NULL, std::map< std::string, std::string > *resheads=NULL, const std::string *reqbody=NULL, const std::map< std::string, std::string > *reqheads=NULL, double timeout=-1)kyototycoon::HTTPClient [static]
HTTPClient()kyototycoon::HTTPClient [explicit]
LINEBUFSIZkyototycoon::HTTPClient [static]
MDELETE enum valuekyototycoon::HTTPClient
Method enum namekyototycoon::HTTPClient
MGET enum valuekyototycoon::HTTPClient
MHEAD enum valuekyototycoon::HTTPClient
MPOST enum valuekyototycoon::HTTPClient
MPUT enum valuekyototycoon::HTTPClient
MUNKNOWN enum valuekyototycoon::HTTPClient
open(const std::string &host="", int32_t port=80, double timeout=-1)kyototycoon::HTTPClient
RECVMAXSIZkyototycoon::HTTPClient [static]
reveal_core()kyototycoon::HTTPClient
~HTTPClient()kyototycoon::HTTPClient
kyototycoon-0.9.56/doc/api/namespacemembers_vars.html0000644000175000017500000000566111757471600022004 0ustar mikiomikio Kyoto Tycoon: Namespace Members
 
kyototycoon-0.9.56/doc/api/functions_func_0x62.html0000644000175000017500000001114611757471600021237 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions
 

- b -

kyototycoon-0.9.56/doc/api/globals_defs.html0000644000175000017500000000467711757471600020074 0ustar mikiomikio Kyoto Tycoon: File Members
 
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1Socket-members.html0000644000175000017500000002313711757471600024330 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::Socket Member List
kyototycoon-0.9.56/doc/api/functions_0x71.html0000644000175000017500000001066711757471600020233 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- q -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1TimedDB_1_1Cursor.html0000644000175000017500000014024511757471600024556 0ustar mikiomikio Kyoto Tycoon: kyototycoon::TimedDB::Cursor Class Reference
kyototycoon::TimedDB::Cursor Class Reference

Cursor to indicate a record. More...

#include <kttimeddb.h>

List of all members.

Public Member Functions

 Cursor (TimedDB *db)
 Constructor.
virtual ~Cursor ()
 Destructor.
bool jump ()
 Jump the cursor to the first record for forward scan.
bool jump (const char *kbuf, size_t ksiz)
 Jump the cursor to a record for forward scan.
bool jump (const std::string &key)
 Jump the cursor to a record for forward scan.
bool jump_back ()
 Jump the cursor to the last record for backward scan.
bool jump_back (const char *kbuf, size_t ksiz)
 Jump the cursor to a record for backward scan.
bool jump_back (const std::string &key)
 Jump the cursor to a record for backward scan.
bool step ()
 Step the cursor to the next record.
bool step_back ()
 Step the cursor to the previous record.
bool accept (Visitor *visitor, bool writable=true, bool step=false)
 Accept a visitor to the current record.
bool set_value (const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX, bool step=false)
 Set the value of the current record.
bool set_value_str (const std::string &value, int64_t xt=kc::INT64MAX, bool step=false)
 Set the value of the current record.
bool remove ()
 Remove the current record.
char * get_key (size_t *sp, bool step=false)
 Get the key of the current record.
bool get_key (std::string *key, bool step=false)
 Get the key of the current record.
char * get_value (size_t *sp, bool step=false)
 Get the value of the current record.
bool get_value (std::string *value, bool step=false)
 Get the value of the current record.
char * get (size_t *ksp, const char **vbp, size_t *vsp, int64_t *xtp=NULL, bool step=false)
 Get a pair of the key and the value of the current record.
bool get (std::string *key, std::string *value, int64_t *xtp=NULL, bool step=false)
 Get a pair of the key and the value of the current record.
char * seize (size_t *ksp, const char **vbp, size_t *vsp, int64_t *xtp=NULL)
 Get a pair of the key and the value of the current record and remove it atomically.
bool seize (std::string *key, std::string *value, int64_t *xtp=NULL)
 Get a pair of the key and the value of the current record and remove it atomically.
TimedDBdb ()
 Get the database object.
kc::BasicDB::Error error ()
 Get the last happened error.

Friends

class TimedDB

Detailed Description

Cursor to indicate a record.


Constructor & Destructor Documentation

Constructor.

Parameters:
dbthe container database object.

Destructor.


Member Function Documentation

Jump the cursor to the first record for forward scan.

Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::Cursor::jump ( const char *  kbuf,
size_t  ksiz 
)

Jump the cursor to a record for forward scan.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::Cursor::jump ( const std::string &  key)

Jump the cursor to a record for forward scan.

Note:
Equal to the original Cursor::jump method except that the parameter is std::string.

Jump the cursor to the last record for backward scan.

Returns:
true on success, or false on failure.
Note:
This method is dedicated to tree databases. Some database types, especially hash databases, may provide a dummy implementation.
bool kyototycoon::TimedDB::Cursor::jump_back ( const char *  kbuf,
size_t  ksiz 
)

Jump the cursor to a record for backward scan.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
Returns:
true on success, or false on failure.
Note:
This method is dedicated to tree databases. Some database types, especially hash databases, will provide a dummy implementation.
bool kyototycoon::TimedDB::Cursor::jump_back ( const std::string &  key)

Jump the cursor to a record for backward scan.

Note:
Equal to the original Cursor::jump_back method except that the parameter is std::string.

Step the cursor to the next record.

Returns:
true on success, or false on failure.

Step the cursor to the previous record.

Returns:
true on success, or false on failure.
Note:
This method is dedicated to tree databases. Some database types, especially hash databases, may provide a dummy implementation.
bool kyototycoon::TimedDB::Cursor::accept ( Visitor visitor,
bool  writable = true,
bool  step = false 
)

Accept a visitor to the current record.

Parameters:
visitora visitor object.
writabletrue for writable operation, or false for read-only operation.
steptrue to move the cursor to the next record, or false for no move.
Returns:
true on success, or false on failure.
Note:
the operation for each record is performed atomically and other threads accessing the same record are blocked.
bool kyototycoon::TimedDB::Cursor::set_value ( const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX,
bool  step = false 
)

Set the value of the current record.

Parameters:
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
steptrue to move the cursor to the next record, or false for no move.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::Cursor::set_value_str ( const std::string &  value,
int64_t  xt = kc::INT64MAX,
bool  step = false 
)

Set the value of the current record.

Note:
Equal to the original Cursor::set_value method except that the parameter is std::string.

Remove the current record.

Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, false is returned. The cursor is moved to the next record implicitly.
char* kyototycoon::TimedDB::Cursor::get_key ( size_t *  sp,
bool  step = false 
)

Get the key of the current record.

Parameters:
spthe pointer to the variable into which the size of the region of the return value is assigned.
steptrue to move the cursor to the next record, or false for no move.
Returns:
the pointer to the key region of the current record, or NULL on failure.
Note:
If the cursor is invalidated, NULL is returned. Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a C-style string. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
bool kyototycoon::TimedDB::Cursor::get_key ( std::string *  key,
bool  step = false 
)

Get the key of the current record.

Note:
Equal to the original Cursor::get_key method except that a parameter is a string to contain the result and the return value is bool for success.
char* kyototycoon::TimedDB::Cursor::get_value ( size_t *  sp,
bool  step = false 
)

Get the value of the current record.

Parameters:
spthe pointer to the variable into which the size of the region of the return value is assigned.
steptrue to move the cursor to the next record, or false for no move.
Returns:
the pointer to the value region of the current record, or NULL on failure.
Note:
If the cursor is invalidated, NULL is returned. Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a C-style string. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
bool kyototycoon::TimedDB::Cursor::get_value ( std::string *  value,
bool  step = false 
)

Get the value of the current record.

Note:
Equal to the original Cursor::get_value method except that a parameter is a string to contain the result and the return value is bool for success.
char* kyototycoon::TimedDB::Cursor::get ( size_t *  ksp,
const char **  vbp,
size_t *  vsp,
int64_t *  xtp = NULL,
bool  step = false 
)

Get a pair of the key and the value of the current record.

Parameters:
kspthe pointer to the variable into which the size of the region of the return value is assigned.
vbpthe pointer to the variable into which the pointer to the value region is assigned.
vspthe pointer to the variable into which the size of the value region is assigned.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
steptrue to move the cursor to the next record, or false for no move.
Returns:
the pointer to the pair of the key region, or NULL on failure.
Note:
If the cursor is invalidated, NULL is returned. Because an additional zero code is appended at the end of each region of the key and the value, each region can be treated as a C-style string. The return value should be deleted explicitly by the caller with the detele[] operator.
bool kyototycoon::TimedDB::Cursor::get ( std::string *  key,
std::string *  value,
int64_t *  xtp = NULL,
bool  step = false 
)

Get a pair of the key and the value of the current record.

Note:
Equal to the original Cursor::get method except that parameters are strings to contain the result and the return value is bool for success.
char* kyototycoon::TimedDB::Cursor::seize ( size_t *  ksp,
const char **  vbp,
size_t *  vsp,
int64_t *  xtp = NULL 
)

Get a pair of the key and the value of the current record and remove it atomically.

Parameters:
kspthe pointer to the variable into which the size of the region of the return value is assigned.
vbpthe pointer to the variable into which the pointer to the value region is assigned.
vspthe pointer to the variable into which the size of the value region is assigned.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
Returns:
the pointer to the pair of the key region, or NULL on failure.
Note:
If the cursor is invalidated, NULL is returned. Because an additional zero code is appended at the end of each region of the key and the value, each region can be treated as a C-style string. The return value should be deleted explicitly by the caller with the detele[] operator.
bool kyototycoon::TimedDB::Cursor::seize ( std::string *  key,
std::string *  value,
int64_t *  xtp = NULL 
)

Get a pair of the key and the value of the current record and remove it atomically.

Note:
Equal to the original Cursor::seize method except that parameters are strings to contain the result and the return value is bool for success.

Get the database object.

Returns:
the database object.
kc::BasicDB::Error kyototycoon::TimedDB::Cursor::error ( )

Get the last happened error.

Returns:
the last happened error.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1URL-members.html0000644000175000017500000001675011757471600023545 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::URL Member List
This is the complete list of members for kyototycoon::URL, including all inherited members.
authority()kyototycoon::URL
expression()kyototycoon::URL
fragment()kyototycoon::URL
host()kyototycoon::URL
operator=(const URL &right)kyototycoon::URL
path()kyototycoon::URL
path_query()kyototycoon::URL
port()kyototycoon::URL
query()kyototycoon::URL
scheme()kyototycoon::URL
set_authority(const std::string &authority)kyototycoon::URL
set_expression(const std::string &expr)kyototycoon::URL
set_fragment(const std::string &fragment)kyototycoon::URL
set_host(const std::string &host)kyototycoon::URL
set_path(const std::string &path)kyototycoon::URL
set_port(int32_t port)kyototycoon::URL
set_query(const std::string &query)kyototycoon::URL
set_scheme(const std::string &scheme)kyototycoon::URL
URL()kyototycoon::URL [explicit]
URL(const std::string &expr)kyototycoon::URL [explicit]
URL(const URL &src)kyototycoon::URL [explicit]
~URL()kyototycoon::URL
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer_1_1Session_1_1Data-members.html0000644000175000017500000000602411757471600031241 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::ThreadedServer::Session::Data Member List
This is the complete list of members for kyototycoon::ThreadedServer::Session::Data, including all inherited members.
~Data()kyototycoon::ThreadedServer::Session::Data [virtual]
kyototycoon-0.9.56/doc/api/functions_func_0x6c.html0000644000175000017500000001361211757471600021320 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/functions_0x78.html0000644000175000017500000001306411757471600020234 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- x -

kyototycoon-0.9.56/doc/api/structkyototycoon_1_1UpdateLogger_1_1FileStatus-members.html0000644000175000017500000000662611757471600030351 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::UpdateLogger::FileStatus Member List
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer_1_1Session.html0000644000175000017500000002504711757471600025271 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RPCServer::Session Class Reference
kyototycoon::RPCServer::Session Class Reference

Interface to log internal information and errors. More...

#include <ktrpc.h>

List of all members.

Classes

class  Data
 Interface of session local data. More...

Public Member Functions

uint64_t id ()
 Get the ID number of the session.
uint32_t thread_id ()
 Get the ID number of the worker thread.
void set_data (Data *data)
 Set the session local data.
Datadata ()
 Get the session local data.
const std::string expression ()
 Get the expression of the socket.

Friends

class RPCServer

Detailed Description

Interface to log internal information and errors.


Member Function Documentation

Get the ID number of the session.

Returns:
the ID number of the session.

Get the ID number of the worker thread.

Returns:
the ID number of the worker thread. It is from 0 to less than the number of worker threads.

Set the session local data.

Parameters:
datathe session local data. If it is NULL, no data is registered.
Note:
The registered data is destroyed implicitly when the session object is destroyed or this method is called again.

Get the session local data.

Returns:
the session local data, or NULL if no data is registered.

Get the expression of the socket.

Returns:
the expression of the socket or an empty string on failure.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1MapReduce_1_1ReduceTaskQueue_1_1ReduceTask.html0000644000175000017500000001341111757471600031342 0ustar mikiomikio Kyoto Tycoon: kyototycoon::MapReduce::ReduceTaskQueue::ReduceTask Class Reference
kyototycoon::MapReduce::ReduceTaskQueue::ReduceTask Class Reference

Task for parallel reducer. More...

#include <ktdbext.h>

List of all members.

Public Member Functions

 ReduceTask (MapReduce *mr, const char *kbuf, size_t ksiz, const Values &values)
 constructor

Friends

class ReduceTaskQueue

Detailed Description

Task for parallel reducer.


Constructor & Destructor Documentation

kyototycoon::MapReduce::ReduceTaskQueue::ReduceTask::ReduceTask ( MapReduce mr,
const char *  kbuf,
size_t  ksiz,
const Values &  values 
) [explicit]

constructor

kyototycoon-0.9.56/doc/api/namespaces.html0000644000175000017500000000412311757471600017551 0ustar mikiomikio Kyoto Tycoon: Namespace List
Namespace List
Here is a list of all documented namespaces with brief descriptions:
kyototycoonAll symbols of Kyoto Tycoon
kyototycoon-0.9.56/doc/api/functions_func_0x6a.html0000644000175000017500000001240411757471600021314 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer_1_1Logger-members.html0000644000175000017500000001130111757471600026634 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::HTTPServer::Logger Member List
kyototycoon-0.9.56/doc/api/functions_0x62.html0000644000175000017500000001453611757471600020232 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- b -

kyototycoon-0.9.56/doc/api/ktutil_8h.html0000644000175000017500000004375611757471600017364 0ustar mikiomikio Kyoto Tycoon: ktutil.h File Reference
ktutil.h File Reference

utility functions More...

#include <ktcommon.h>

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.


Functions

bool kyototycoon::setkillsignalhandler (void(*handler)(int))
 Set the signal handler for termination signals.
bool kyototycoon::maskthreadsignal ()
 Set the signal mask of the current to ignore all.
bool kyototycoon::daemonize ()
 Switch the process into the background.
int32_t kyototycoon::executecommand (const std::vector< std::string > &args)
 Execute a shell command.
const char * kyototycoon::strmapget (const std::map< std::string, std::string > &map, const char *key, size_t *sp=NULL)
 Get the C-style string value of a record in a string map.
void kyototycoon::printstrvec (const std::vector< std::string > &vec, std::ostream &strm=std::cout)
 Print all records in a string vector.
void kyototycoon::printstrmap (const std::map< std::string, std::string > &map, std::ostream &strm=std::cout)
 Print all records in a string map.
void kyototycoon::urlbreak (const char *url, std::map< std::string, std::string > *elems)
 Break up a URL into elements.
char * kyototycoon::xmlescape (const char *str)
 Escape meta characters in a string with the entity references of XML.
char * kyototycoon::xmlunescape (const char *str)
 Unescape meta characters in a string with the entity references of XML.
void kyototycoon::wwwformtomap (const std::string &str, std::map< std::string, std::string > *map)
 Parse a www-form-urlencoded string and store each records into a map.
void kyototycoon::maptowwwform (const std::map< std::string, std::string > &map, std::string *str)
 Serialize a string map into a www-form-urlencoded string.
void kyototycoon::tsvtomap (const std::string &str, std::map< std::string, std::string > *map)
 Parse a TSV string and store each records into a map.
void kyototycoon::maptotsv (const std::map< std::string, std::string > &map, std::string *str)
 Serialize a string map into a TSV string.
void kyototycoon::tsvmapencode (std::map< std::string, std::string > *map, int32_t mode)
 Encode each record of a string map.
void kyototycoon::tsvmapdecode (std::map< std::string, std::string > *map, int32_t mode)
 Decode each record of a string map.
int32_t kyototycoon::checkmapenc (const std::map< std::string, std::string > &map)
 Check the best suited encoding of a string map.
char * kyototycoon::strcapitalize (char *str)
 Capitalize letters of a string.
bool kyototycoon::strisalnum (const char *str)
 Check a string is composed of alphabets or numbers only.
void kyototycoon::strtokenize (const char *str, std::vector< std::string > *tokens)
 Tokenize a string separating by space characters.
void kyototycoon::getcalendar (int64_t t, int32_t jl, int32_t *yearp=NULL, int32_t *monp=NULL, int32_t *dayp=NULL, int32_t *hourp=NULL, int32_t *minp=NULL, int32_t *secp=NULL)
 Get the Gregorian calendar of a time.
void kyototycoon::datestrwww (int64_t t, int32_t jl, char *buf)
 Format a date as a string in W3CDTF.
void kyototycoon::datestrwww (double t, int32_t jl, int32_t acr, char *buf)
 Format a date as a string in W3CDTF with the fraction part.
void kyototycoon::datestrhttp (int64_t t, int32_t jl, char *buf)
 Format a date as a string in RFC 1123 format.
int64_t kyototycoon::strmktime (const char *str)
 Get the time value of a date string.
int32_t kyototycoon::jetlag ()
 Get the jet lag of the local time.
int32_t kyototycoon::dayofweek (int32_t year, int32_t mon, int32_t day)
 Get the day of week of a date.
bool kyototycoon::getlocaltime (time_t time, struct std::tm *result)
 Get the local time of a time.
bool kyototycoon::getgmtime (time_t time, struct std::tm *result)
 Get the GMT local time of a time.
time_t kyototycoon::mkgmtime (struct std::tm *tm)
 Make the GMT from a time structure.

Variables

const char *const kyototycoon::VERSION
 The package version.
const int32_t kyototycoon::LIBVER
 The library version.
const int32_t kyototycoon::LIBREV
 The library revision.
const char *const kyototycoon::FEATURES
 The extra feature list.
const int32_t kyototycoon::DEFPORT = 1978
 The default port number.

Detailed Description

utility functions

kyototycoon-0.9.56/doc/api/index.html0000644000175000017500000003507211757471600016550 0ustar mikiomikio Kyoto Tycoon: Kyoto Tycoon: a handy cache/storage server
Kyoto Tycoon: a handy cache/storage server

Introduction

Kyoto Tycoon is a lightweight database server with auto expiration mechanism, which is useful to handle cache data and persistent data of various applications. Kyoto Tycoon is also a package of network interface to the DBM called Kyoto Cabinet. Though the DBM has high performance and high concurrency, you might bother in case that multiple processes share the same database, or remote processes access the database. Thus, Kyoto Tycoon is provided for concurrent and remote connections to Kyoto Cabinet. Kyoto Tycoon is composed of the server process managing multiple databases and its access library for client applications.

The network protocol between the server and clients is HTTP so that you can write client applications and client libraries in almost all popular languages. Both of RESTful-style interface by the GET, HEAD, PUT, DELETE methods and RPC-style inteface by the POST method are supported. The server can handle more than 10 thousand connections at the same time because it uses modern I/O event notification facilities such as "epoll" and "kqueue" of underlying systems. The server can embed Lua, a lightweight script language so that you can define arbitrary operations of the database.

The following classes are the most important. If you are interested in writing applications of Kyoto Tycoon, all you have to learn is how to use the remote database interface.

Example

The following code is an example to use a remote database.

#include <ktremotedb.h>

using namespace std;
using namespace kyototycoon;

// main routine
int main(int argc, char** argv) {

  // create the database object
  RemoteDB db;

  // open the database
  if (!db.open()) {
    cerr << "open error: " << db.error().name() << endl;
  }

  // store records
  if (!db.set("foo", "hop") ||
      !db.set("bar", "step") ||
      !db.set("baz", "jump")) {
    cerr << "set error: " << db.error().name() << endl;
  }

  // retrieve a record
  string value;
  if (db.get("foo", &value)) {
    cout << value << endl;
  } else {
    cerr << "get error: " << db.error().name() << endl;
  }

  // traverse records
  RemoteDB::Cursor* cur = db.cursor();
  cur->jump();
  string ckey, cvalue;
  while (cur->get(&ckey, &cvalue, NULL, true)) {
    cout << ckey << ":" << cvalue << endl;
  }
  delete cur;

  // close the database
  if (!db.close()) {
    cerr << "close error: " << db.error().name() << endl;
  }

  return 0;
}

The following code is an example to use the TCP server framework.

#include <ktthserv.h>

using namespace std;
using namespace kyototycoon;

// the flag whether the server is alive
ThreadedServer* g_serv = NULL;

// stop the running server
static void stopserver(int signum) {
  if (g_serv) g_serv->stop();
  g_serv = NULL;
}

// main routine
int main(int argc, char** argv) {

  // set the signal handler to stop the server
  setkillsignalhandler(stopserver);

  // prepare the worker
  class Worker : public ThreadedServer::Worker {
    bool process(ThreadedServer* serv, ThreadedServer::Session* sess) {
      bool keep = false;
      // read a line from the client socket
      char line[1024];
      if (sess->receive_line(line, sizeof(line))) {
        if (!kc::stricmp(line, "/quit")) {
          // process the quit command
          sess->printf("> Bye!\n");
        } else {
          // echo back the message
          sess->printf("> %s\n", line);
          keep = true;
        }
      }
      return keep;
    }
  };
  Worker worker;

  // prepare the server
  ThreadedServer serv;
  serv.set_network("127.0.0.1:1978", 1.0);
  serv.set_worker(&worker, 4);
  g_serv = &serv;

  // start the server and block until its stop
  serv.start();

  // clean up connections and other resources
  serv.finish();

  return 0;
}
kyototycoon-0.9.56/doc/api/structkyototycoon_1_1UpdateLogger_1_1FileStatus.html0000644000175000017500000001354211757471600026714 0ustar mikiomikio Kyoto Tycoon: kyototycoon::UpdateLogger::FileStatus Struct Reference
kyototycoon::UpdateLogger::FileStatus Struct Reference

Status of each log file. More...

#include <ktulog.h>

List of all members.

Public Attributes

std::string path
 path
uint64_t size
 file size
uint64_t ts
 maximum time stamp

Detailed Description

Status of each log file.


Member Data Documentation

maximum time stamp

kyototycoon-0.9.56/doc/api/ktulog_8h.html0000644000175000017500000001313311757471600017337 0ustar mikiomikio Kyoto Tycoon: ktulog.h File Reference
ktulog.h File Reference

update logger More...

#include <ktcommon.h>
#include <ktutil.h>

Classes

class  kyototycoon::UpdateLogger
 Update logger. More...
class  kyototycoon::UpdateLogger::Reader
 Reader of update logs. More...
struct  kyototycoon::UpdateLogger::FileStatus
 Status of each log file. More...
struct  kyototycoon::UpdateLogger::Log
 Log message.
class  kyototycoon::UpdateLogger::AutoFlusher
 Automatic flusher of cacheed logs.

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.


Defines

#define KTULPATHEXT   "ulog"
 extension of each file

Detailed Description

update logger


Define Documentation

#define KTULPATHEXT   "ulog"

extension of each file

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1URL.html0000644000175000017500000007010011757471600022102 0ustar mikiomikio Kyoto Tycoon: kyototycoon::URL Class Reference
kyototycoon::URL Class Reference

URL accessor. More...

#include <kthttp.h>

List of all members.

Public Member Functions

 URL ()
 Default constructor.
 URL (const std::string &expr)
 Constructor.
 URL (const URL &src)
 Copy constructor.
 ~URL ()
 Destructor.
void set_expression (const std::string &expr)
 Set the string expression of the URL.
void set_scheme (const std::string &scheme)
 Set the scheme.
void set_host (const std::string &host)
 Set the host name.
void set_port (int32_t port)
 Set the port number.
void set_authority (const std::string &authority)
 Set the authority information.
void set_path (const std::string &path)
 Set the path.
void set_query (const std::string &query)
 Set the query string.
void set_fragment (const std::string &fragment)
 Set the fragment string.
std::string expression ()
 Get the string expression of the URL.
std::string path_query ()
 Get the path and the query string for HTTP request.
std::string scheme ()
 Get the scheme.
std::string host ()
 Get the host name.
int32_t port ()
 Get the port number.
std::string authority ()
 Get the authority information.
std::string path ()
 Get the path.
std::string query ()
 Get the query string.
std::string fragment ()
 Get the fragment string.
URLoperator= (const URL &right)
 Assignment operator from the self type.

Detailed Description

URL accessor.


Constructor & Destructor Documentation

kyototycoon::URL::URL ( ) [explicit]

Default constructor.

kyototycoon::URL::URL ( const std::string &  expr) [explicit]

Constructor.

Parameters:
exprthe string expression of the URL.
kyototycoon::URL::URL ( const URL src) [explicit]

Copy constructor.

Parameters:
srcthe source object.

Destructor.


Member Function Documentation

void kyototycoon::URL::set_expression ( const std::string &  expr)

Set the string expression of the URL.

void kyototycoon::URL::set_scheme ( const std::string &  scheme)

Set the scheme.

void kyototycoon::URL::set_host ( const std::string &  host)

Set the host name.

void kyototycoon::URL::set_port ( int32_t  port)

Set the port number.

void kyototycoon::URL::set_authority ( const std::string &  authority)

Set the authority information.

void kyototycoon::URL::set_path ( const std::string &  path)

Set the path.

void kyototycoon::URL::set_query ( const std::string &  query)

Set the query string.

void kyototycoon::URL::set_fragment ( const std::string &  fragment)

Set the fragment string.

Get the string expression of the URL.

Returns:
the string expression of the URL.

Get the path and the query string for HTTP request.

Returns:
the path and the query string for HTTP request.
std::string kyototycoon::URL::scheme ( )

Get the scheme.

Returns:
the scheme.
std::string kyototycoon::URL::host ( )

Get the host name.

Returns:
the host name.

Get the port number.

Returns:
the port number.
std::string kyototycoon::URL::authority ( )

Get the authority information.

Returns:
the authority information.
std::string kyototycoon::URL::path ( )

Get the path.

Returns:
the path.
std::string kyototycoon::URL::query ( )

Get the query string.

Returns:
the query string.
std::string kyototycoon::URL::fragment ( )

Get the fragment string.

Returns:
the fragment string.
URL& kyototycoon::URL::operator= ( const URL right)

Assignment operator from the self type.

Parameters:
rightthe right operand.
Returns:
the reference to itself.
kyototycoon-0.9.56/doc/api/ktthserv_8h.html0000644000175000017500000001272711757471600017714 0ustar mikiomikio Kyoto Tycoon: ktthserv.h File Reference
ktthserv.h File Reference

threaded server More...

#include <ktcommon.h>
#include <ktutil.h>
#include <ktsocket.h>

Classes

class  kyototycoon::ThreadedServer
 Threaded TCP Server. More...
class  kyototycoon::ThreadedServer::Logger
 Interface to log internal information and errors. More...
class  kyototycoon::ThreadedServer::Worker
 Interface to process each request. More...
class  kyototycoon::ThreadedServer::Session
 Interface to access each session data. More...
class  kyototycoon::ThreadedServer::Session::Data
 Interface of session local data. More...
class  kyototycoon::ThreadedServer::TaskQueueImpl
 Task queue implementation.
class  kyototycoon::ThreadedServer::SessionTask
 Task with a session.

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.



Detailed Description

threaded server

kyototycoon-0.9.56/doc/api/functions.html0000644000175000017500000001467311757471600017455 0ustar mikiomikio Kyoto Tycoon: Class Members kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer_1_1Session-members.html0000644000175000017500000002574411757471600030021 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::ThreadedServer::Session Member List
This is the complete list of members for kyototycoon::ThreadedServer::Session, including all inherited members.
abort()kyototycoon::Socket
close(bool grace=true)kyototycoon::Socket
data()kyototycoon::ThreadedServer::Session
descriptor()kyototycoon::Socket [virtual]
error()kyototycoon::Socket
event_flags()kyototycoon::Socket [virtual]
EventFlag enum namekyototycoon::Pollable
EVEXCEPT enum valuekyototycoon::Pollable
EVINPUT enum valuekyototycoon::Pollable
EVOUTPUT enum valuekyototycoon::Pollable
expression()kyototycoon::Socket
get_host_address(const std::string &name)kyototycoon::Socket [static]
get_local_host_name()kyototycoon::Socket [static]
id()kyototycoon::ThreadedServer::Session
left_size()kyototycoon::Socket
open(const std::string &expr)kyototycoon::Socket
Pollable()kyototycoon::Pollable [explicit]
printf(const char *format,...)kyototycoon::Socket
receive(void *buf, size_t size)kyototycoon::Socket
receive_byte()kyototycoon::Socket
receive_line(void *buf, size_t max)kyototycoon::Socket
send(const void *buf, size_t size)kyototycoon::Socket
send(const std::string &str)kyototycoon::Socket
set_data(Data *data)kyototycoon::ThreadedServer::Session
set_event_flags(uint32_t flags)kyototycoon::Socket [virtual]
set_timeout(double timeout)kyototycoon::Socket
Socket()kyototycoon::Socket [explicit]
thread_id()kyototycoon::ThreadedServer::Session
ThreadedServer (defined in kyototycoon::ThreadedServer::Session)kyototycoon::ThreadedServer::Session [friend]
undo_receive_byte(int32_t c)kyototycoon::Socket
vprintf(const char *format, va_list ap)kyototycoon::Socket
~Pollable()kyototycoon::Pollable [virtual]
~Socket()kyototycoon::Socket
kyototycoon-0.9.56/doc/api/functions_0x6b.html0000644000175000017500000001117211757471600020303 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- k -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer_1_1Session_1_1Data-members.html0000644000175000017500000000574211757471600030153 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RPCServer::Session::Data Member List
This is the complete list of members for kyototycoon::RPCServer::Session::Data, including all inherited members.
~Data()kyototycoon::RPCServer::Session::Data [virtual]
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPClient.html0000644000175000017500000006155611757471600023375 0ustar mikiomikio Kyoto Tycoon: kyototycoon::HTTPClient Class Reference

HTTP client. More...

#include <kthttp.h>

List of all members.

Public Types

enum  Method {
  MGET, MHEAD, MPOST, MPUT,
  MDELETE, MUNKNOWN
}
 Kinds of HTTP request methods. More...

Public Member Functions

 HTTPClient ()
 Default constructor.
 ~HTTPClient ()
 Destructor.
bool open (const std::string &host="", int32_t port=80, double timeout=-1)
 Open the connection.
bool close (bool grace=true)
 Close the connection.
int32_t fetch (const std::string &pathquery, Method method=MGET, std::string *resbody=NULL, std::map< std::string, std::string > *resheads=NULL, const std::string *reqbody=NULL, const std::map< std::string, std::string > *reqheads=NULL)
 Fetch a resource.
Socketreveal_core ()
 Reveal the internal TCP socket.

Static Public Member Functions

static int32_t fetch_once (const std::string &url, Method method=MGET, std::string *resbody=NULL, std::map< std::string, std::string > *resheads=NULL, const std::string *reqbody=NULL, const std::map< std::string, std::string > *reqheads=NULL, double timeout=-1)
 Fetch a resource at once.

Static Public Attributes

static const int32_t LINEBUFSIZ = 8192
 The size for a line buffer.
static const int32_t RECVMAXSIZ = 1 << 28
 The maximum size of received data.

Detailed Description

HTTP client.

Note:
Although all methods of this class are thread-safe, its instance does not have mutual exclusion mechanism. So, multiple threads must not share the same instance and they must use their own respective instances.

Member Enumeration Documentation

Kinds of HTTP request methods.

Enumerator:
MGET 

GET.

MHEAD 

HEAD.

MPOST 

POST.

MPUT 

PUT.

MDELETE 

DELETE.

MUNKNOWN 

unknown


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

bool kyototycoon::HTTPClient::open ( const std::string &  host = "",
int32_t  port = 80,
double  timeout = -1 
)

Open the connection.

Parameters:
hostthe name or the address of the server. If it is an empty string, the local host is specified.
portthe port numger of the server.
timeoutthe timeout of each operation in seconds. If it is not more than 0, no timeout is specified.
Returns:
true on success, or false on failure.
bool kyototycoon::HTTPClient::close ( bool  grace = true)

Close the connection.

Parameters:
gracetrue for graceful shutdown, or false for immediate disconnection.
Returns:
true on success, or false on failure.
int32_t kyototycoon::HTTPClient::fetch ( const std::string &  pathquery,
Method  method = MGET,
std::string *  resbody = NULL,
std::map< std::string, std::string > *  resheads = NULL,
const std::string *  reqbody = NULL,
const std::map< std::string, std::string > *  reqheads = NULL 
)

Fetch a resource.

Parameters:
pathquerythe path and the query string of the resource.
methodthe kind of the request methods.
resbodya string to contain the entity body of the response. If it is NULL, it is ignored.
resheadsa string map to contain the headers of the response. If it is NULL, it is ignored. Header names are converted into lower cases. The empty key means the request-line.
reqbodya string which contains the entity body of the request. If it is NULL, it is ignored.
reqheadsa string map which contains the headers of the request. If it is NULL, it is ignored.
Returns:
the status code of the response, or -1 on failure.

Reveal the internal TCP socket.

Returns:
the internal TCP socket.
static int32_t kyototycoon::HTTPClient::fetch_once ( const std::string &  url,
Method  method = MGET,
std::string *  resbody = NULL,
std::map< std::string, std::string > *  resheads = NULL,
const std::string *  reqbody = NULL,
const std::map< std::string, std::string > *  reqheads = NULL,
double  timeout = -1 
) [static]

Fetch a resource at once.

Parameters:
urlthe URL of the resource.
methodthe kind of the request methods.
resbodya string to contain the entity body of the response. If it is NULL, it is ignored.
resheadsa string map to contain the headers of the response. If it is NULL, it is ignored. Header names are converted into lower cases. The empty key means the request-line.
reqbodya string which contains the entity body of the request. If it is NULL, it is ignored.
reqheadsa string map which contains the headers of the request. If it is NULL, it is ignored.
timeoutthe timeout of each operation in seconds. If it is not more than 0, no timeout is specified.
Returns:
the status code of the response, or -1 on failure.

Member Data Documentation

const int32_t kyototycoon::HTTPClient::LINEBUFSIZ = 8192 [static]

The size for a line buffer.

const int32_t kyototycoon::HTTPClient::RECVMAXSIZ = 1 << 28 [static]

The maximum size of received data.

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer_1_1Worker.html0000644000175000017500000003040211757471600026202 0ustar mikiomikio Kyoto Tycoon: kyototycoon::ThreadedServer::Worker Class Reference
kyototycoon::ThreadedServer::Worker Class Reference

Interface to process each request. More...

#include <ktthserv.h>

List of all members.

Public Member Functions

virtual ~Worker ()
 Destructor.
virtual bool process (ThreadedServer *serv, Session *sess)=0
 Process each request.
virtual void process_idle (ThreadedServer *serv)
 Process each idle event.
virtual void process_timer (ThreadedServer *serv)
 Process each timer event.
virtual void process_start (ThreadedServer *serv)
 Process the starting event.
virtual void process_finish (ThreadedServer *serv)
 Process the finishing event.

Detailed Description

Interface to process each request.


Constructor & Destructor Documentation

Destructor.


Member Function Documentation

virtual bool kyototycoon::ThreadedServer::Worker::process ( ThreadedServer serv,
Session sess 
) [pure virtual]

Process each request.

Parameters:
servthe server.
sessthe session with the client.
Returns:
true to reuse the session, or false to close the session.

Process each idle event.

Parameters:
servthe server.

Process each timer event.

Parameters:
servthe server.

Process the starting event.

Parameters:
servthe server.

Process the finishing event.

Parameters:
servthe server.
kyototycoon-0.9.56/doc/api/namespacemembers_type.html0000644000175000017500000000454111757471600022006 0ustar mikiomikio Kyoto Tycoon: Namespace Members
 
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1Socket.html0000644000175000017500000010277311757471600022704 0ustar mikiomikio Kyoto Tycoon: kyototycoon::Socket Class Reference
kyototycoon::Socket Class Reference

Network stream abstraction based on TCP/IP. More...

#include <ktsocket.h>

List of all members.

Public Member Functions

 Socket ()
 Default constructor.
 ~Socket ()
 Destructor.
const char * error ()
 Get the last happened error information.
bool open (const std::string &expr)
 Open a client socket.
bool close (bool grace=true)
 Close the socket.
bool send (const void *buf, size_t size)
 Send data.
bool send (const std::string &str)
 Send data.
bool printf (const char *format,...)
 Send formatted data.
bool vprintf (const char *format, va_list ap)
 Send formatted data.
bool receive (void *buf, size_t size)
 Receive data.
int32_t receive_byte ()
 Receive one byte.
bool undo_receive_byte (int32_t c)
 Push one byte back.
bool receive_line (void *buf, size_t max)
 Receive one line of characters.
size_t left_size ()
 Get the size of left data in the receiving buffer.
bool abort ()
 Abort the current operation.
bool set_timeout (double timeout)
 Set the timeout of each operation.
const std::string expression ()
 Get the expression of the socket.
int32_t descriptor ()
 Get the descriptor integer.
void set_event_flags (uint32_t flags)
 Set event flags.
uint32_t event_flags ()
 Get the current event flags.

Static Public Member Functions

static std::string get_local_host_name ()
 Get the primary name of the local host.
static std::string get_host_address (const std::string &name)
 Get the address of a host.

Friends

class ServerSocket

Detailed Description

Network stream abstraction based on TCP/IP.


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

const char* kyototycoon::Socket::error ( )

Get the last happened error information.

Returns:
the last happened error information.
bool kyototycoon::Socket::open ( const std::string &  expr)

Open a client socket.

Parameters:
expran expression of the address and the port of the server.
Returns:
true on success, or false on failure.
bool kyototycoon::Socket::close ( bool  grace = true)

Close the socket.

Parameters:
gracetrue for graceful shutdown, or false for immediate disconnection.
Returns:
true on success, or false on failure.
bool kyototycoon::Socket::send ( const void *  buf,
size_t  size 
)

Send data.

Parameters:
bufthe pointer to a data region to send.
sizethe size of the data region.
Returns:
true on success, or false on failure.
bool kyototycoon::Socket::send ( const std::string &  str)

Send data.

Parameters:
stra string to send.
Returns:
true on success, or false on failure.
bool kyototycoon::Socket::printf ( const char *  format,
  ... 
)

Send formatted data.

Parameters:
formatthe printf-like format string. The conversion character `' can be used with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `'.
...used according to the format string.
Returns:
true on success, or false on failure.
bool kyototycoon::Socket::vprintf ( const char *  format,
va_list  ap 
)

Send formatted data.

Parameters:
formatthe printf-like format string. The conversion character `' can be used with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `'.
apused according to the format string.
Returns:
true on success, or false on failure.
bool kyototycoon::Socket::receive ( void *  buf,
size_t  size 
)

Receive data.

Parameters:
bufthe pointer to the buffer into which the received data is written.
sizethe size of the data to receive.
Returns:
true on success, or false on failure.

Receive one byte.

Returns:
the received byte or -1 on failure.

Push one byte back.

Parameters:
cspecifies the byte.
Returns:
true on success, or false on failure.
Note:
The character is available for subsequent receive operations. Only one pushback is guaranteed.
bool kyototycoon::Socket::receive_line ( void *  buf,
size_t  max 
)

Receive one line of characters.

Parameters:
bufthe pointer to the buffer into which the received data is written.
maxthe maximum size of the data to receive. It must be more than 0.
Returns:
true on success, or false on failure.

Get the size of left data in the receiving buffer.

Returns:
the size of left data in the receiving buffer.

Abort the current operation.

Returns:
true on success, or false on failure.
bool kyototycoon::Socket::set_timeout ( double  timeout)

Set the timeout of each operation.

Parameters:
timeoutthe timeout of each operation in seconds.
Returns:
true on success, or false on failure.
const std::string kyototycoon::Socket::expression ( )

Get the expression of the socket.

Returns:
the expression of the socket or an empty string on failure.
int32_t kyototycoon::Socket::descriptor ( ) [virtual]

Get the descriptor integer.

Returns:
the descriptor integer, or -1 on failure.

Implements kyototycoon::Pollable.

void kyototycoon::Socket::set_event_flags ( uint32_t  flags) [virtual]

Set event flags.

Parameters:
flagsspecifies the event mode. The following may be added by bitwise-or: Socket::EVINPUT for input events, Socket::EVOUTPUT for output events, Socket::EVEXCEPT for exception events.

Implements kyototycoon::Pollable.

uint32_t kyototycoon::Socket::event_flags ( ) [virtual]

Get the current event flags.

Returns:
the current event flags.

Implements kyototycoon::Pollable.

static std::string kyototycoon::Socket::get_local_host_name ( ) [static]

Get the primary name of the local host.

Returns:
the host name, or an empty string on failure.
static std::string kyototycoon::Socket::get_host_address ( const std::string &  name) [static]

Get the address of a host.

Returns:
the host address, or an empty string on failure.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1UpdateLogger_1_1Reader.html0000644000175000017500000002436011757471600025614 0ustar mikiomikio Kyoto Tycoon: kyototycoon::UpdateLogger::Reader Class Reference
kyototycoon::UpdateLogger::Reader Class Reference

Reader of update logs. More...

#include <ktulog.h>

List of all members.

Public Member Functions

 Reader ()
 Default constructor.
 ~Reader ()
 Destructor.
bool open (UpdateLogger *ulog, uint64_t ts=0)
 Open the reader.
bool close ()
 Close the reader.
char * read (size_t *sp, uint64_t *tsp)
 Read the next message.

Detailed Description

Reader of update logs.


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

bool kyototycoon::UpdateLogger::Reader::open ( UpdateLogger ulog,
uint64_t  ts = 0 
)

Open the reader.

Parameters:
ulogthe update logger.
tsthe maximum time stamp of already read logs.
Returns:
true on success, or false on failure.

Close the reader.

char* kyototycoon::UpdateLogger::Reader::read ( size_t *  sp,
uint64_t *  tsp 
)

Read the next message.

Parameters:
spthe pointer to the variable into which the size of the region of the return value is assigned.
tspthe pointer to the variable into which the time stamp is assigned.
Returns:
the pointer to the region of the message, or NULL on failure. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1Pollable.html0000644000175000017500000003127611757471600023205 0ustar mikiomikio Kyoto Tycoon: kyototycoon::Pollable Class Reference
kyototycoon::Pollable Class Reference

Interface of poolable I/O event. More...

#include <ktsocket.h>

List of all members.

Public Types

enum  EventFlag { EVINPUT = 1 << 0, EVOUTPUT = 1 << 1, EVEXCEPT = 1 << 2 }
 Event flags. More...

Public Member Functions

 Pollable ()
 Default constructor.
virtual ~Pollable ()
 Destructor.
virtual int32_t descriptor ()=0
 Get the descriptor integer.
virtual void set_event_flags (uint32_t flags)=0
 Set event flags.
virtual uint32_t event_flags ()=0
 Get the current event flags.

Friends

class Poller

Detailed Description

Interface of poolable I/O event.


Member Enumeration Documentation

Event flags.

Enumerator:
EVINPUT 

input

EVOUTPUT 

output

EVEXCEPT 

exception


Constructor & Destructor Documentation

Default constructor.

virtual kyototycoon::Pollable::~Pollable ( ) [virtual]

Destructor.


Member Function Documentation

virtual int32_t kyototycoon::Pollable::descriptor ( ) [pure virtual]

Get the descriptor integer.

Returns:
the descriptor integer, or -1 on failure.

Implemented in kyototycoon::ServerSocket, and kyototycoon::Socket.

virtual void kyototycoon::Pollable::set_event_flags ( uint32_t  flags) [pure virtual]

Set event flags.

Parameters:
flagsspecifies the event mode. The following may be added by bitwise-or: Pollable::EVINPUT for input events, Pollable::EVOUTPUT for output events, Pollable::EVEXCEPT for exception events.

Implemented in kyototycoon::ServerSocket, and kyototycoon::Socket.

virtual uint32_t kyototycoon::Pollable::event_flags ( ) [pure virtual]

Get the current event flags.

Returns:
the current event flags.

Implemented in kyototycoon::ServerSocket, and kyototycoon::Socket.

kyototycoon-0.9.56/doc/api/functions_0x6e.html0000644000175000017500000001235511757471600020312 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- n -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RemoteDB_1_1Error-members.html0000644000175000017500000002026611757471600026213 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RemoteDB::Error Member List
kyototycoon-0.9.56/doc/api/functions_func_0x67.html0000644000175000017500000001524011757471600021243 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/functions_func_0x6d.html0000644000175000017500000001340011757471600021314 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer_1_1Session.html0000644000175000017500000002507011757471600025420 0ustar mikiomikio Kyoto Tycoon: kyototycoon::HTTPServer::Session Class Reference
kyototycoon::HTTPServer::Session Class Reference

Interface to access each session data. More...

#include <kthttp.h>

List of all members.

Classes

class  Data
 Interface of session local data. More...

Public Member Functions

uint64_t id ()
 Get the ID number of the session.
uint32_t thread_id ()
 Get the ID number of the worker thread.
void set_data (Data *data)
 Set the session local data.
Datadata ()
 Get the session local data.
const std::string expression ()
 Get the expression of the socket.

Friends

class HTTPServer

Detailed Description

Interface to access each session data.


Member Function Documentation

Get the ID number of the session.

Returns:
the ID number of the session.

Get the ID number of the worker thread.

Returns:
the ID number of the worker thread. It is from 0 to less than the number of worker threads.

Set the session local data.

Parameters:
datathe session local data. If it is NULL, no data is registered.
Note:
The registered data is destroyed implicitly when the session object is destroyed or this method is called again.

Get the session local data.

Returns:
the session local data, or NULL if no data is registered.

Get the expression of the socket.

Returns:
the expression of the socket or an empty string on failure.
kyototycoon-0.9.56/doc/api/closed.png0000644000175000017500000000017611757471600016527 0ustar mikiomikio‰PNG  IHDR à‘EIDATxíÝA @! PŠ­iš/`Є.È?,!ƒu zlÞ–Jh1ߘ+výRLé§x@‘Ù (*79HÑ þl)¡ó²‰IEND®B`‚kyototycoon-0.9.56/doc/api/kthttp_8h.html0000644000175000017500000001374211757471600017356 0ustar mikiomikio Kyoto Tycoon: kthttp.h File Reference
kthttp.h File Reference

HTTP utilities. More...

#include <ktcommon.h>
#include <ktutil.h>
#include <ktsocket.h>
#include <ktthserv.h>

Classes

class  kyototycoon::URL
 URL accessor. More...
class  kyototycoon::HTTPClient
 HTTP client. More...
class  kyototycoon::HTTPServer
 HTTP server. More...
class  kyototycoon::HTTPServer::Logger
 Interface to log internal information and errors. More...
class  kyototycoon::HTTPServer::Worker
 Interface to process each request. More...
class  kyototycoon::HTTPServer::Session
 Interface to access each session data. More...
class  kyototycoon::HTTPServer::Session::Data
 Interface of session local data. More...
class  kyototycoon::HTTPServer::WorkerAdapter
 Adapter for the worker.

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.



Detailed Description

HTTP utilities.

kyototycoon-0.9.56/doc/api/ktshlib_8h.html0000644000175000017500000000620211757471600017471 0ustar mikiomikio Kyoto Tycoon: ktshlib.h File Reference
ktshlib.h File Reference

shared library More...

#include <ktcommon.h>
#include <ktutil.h>

Classes

class  kyototycoon::SharedLibrary
 Shared library. More...

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.



Detailed Description

shared library

kyototycoon-0.9.56/doc/api/functions_0x72.html0000644000175000017500000002362011757471600020225 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- r -

kyototycoon-0.9.56/doc/api/ktsocket_8h.html0000644000175000017500000001040411757471600017657 0ustar mikiomikio Kyoto Tycoon: ktsocket.h File Reference
ktsocket.h File Reference

network functions More...

#include <ktcommon.h>
#include <ktutil.h>

Classes

class  kyototycoon::Pollable
 Interface of poolable I/O event. More...
class  kyototycoon::Socket
 Network stream abstraction based on TCP/IP. More...
class  kyototycoon::ServerSocket
 Network server abstraction based on TCP/IP. More...
class  kyototycoon::Poller
 I/O event notification. More...

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.



Detailed Description

network functions

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer_1_1Logger.html0000644000175000017500000002435711757471600026164 0ustar mikiomikio Kyoto Tycoon: kyototycoon::ThreadedServer::Logger Class Reference
kyototycoon::ThreadedServer::Logger Class Reference

Interface to log internal information and errors. More...

#include <ktthserv.h>

List of all members.

Public Types

enum  Kind { DEBUG = 1 << 0, INFO = 1 << 1, SYSTEM = 1 << 2, ERROR = 1 << 3 }
 Event kinds. More...

Public Member Functions

virtual ~Logger ()
 Destructor.
virtual void log (Kind kind, const char *message)=0
 Process a log message.

Detailed Description

Interface to log internal information and errors.


Member Enumeration Documentation

Event kinds.

Enumerator:
DEBUG 

normal information

INFO 

normal information

SYSTEM 

system information

ERROR 

error


Constructor & Destructor Documentation


Member Function Documentation

virtual void kyototycoon::ThreadedServer::Logger::log ( Kind  kind,
const char *  message 
) [pure virtual]

Process a log message.

Parameters:
kindthe kind of the event. Logger::DEBUG for debugging, Logger::INFO for normal information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error.
messagethe log message.
kyototycoon-0.9.56/doc/api/functions_0x6d.html0000644000175000017500000001746011757471600020313 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- m -

kyototycoon-0.9.56/doc/api/files.html0000644000175000017500000000717111757471600016542 0ustar mikiomikio Kyoto Tycoon: File List
File List
Here is a list of all documented files with brief descriptions:
ktcommon.hCommon symbols for the library
ktdbext.hDatabase extension
kthttp.hHTTP utilities
ktplugdb.hPluggable database interface
ktplugserv.hPluggable server interface
ktremotedb.hRemote database
ktrpc.hRPC utilities
ktshlib.hShared library
ktsocket.hNetwork functions
ktthserv.hThreaded server
kttimeddb.hTimed database
ktulog.hUpdate logger
ktutil.hUtility functions
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer_1_1Worker-members.html0000644000175000017500000001200611757471600026671 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::HTTPServer::Worker Member List
This is the complete list of members for kyototycoon::HTTPServer::Worker, including all inherited members.
process(HTTPServer *serv, Session *sess, const std::string &path, HTTPClient::Method method, const std::map< std::string, std::string > &reqheads, const std::string &reqbody, std::map< std::string, std::string > &resheads, std::string &resbody, const std::map< std::string, std::string > &misc)=0kyototycoon::HTTPServer::Worker [pure virtual]
process_binary(ThreadedServer *serv, ThreadedServer::Session *sess)kyototycoon::HTTPServer::Worker [virtual]
process_finish(HTTPServer *serv)kyototycoon::HTTPServer::Worker [virtual]
process_idle(HTTPServer *serv)kyototycoon::HTTPServer::Worker [virtual]
process_start(HTTPServer *serv)kyototycoon::HTTPServer::Worker [virtual]
process_timer(HTTPServer *serv)kyototycoon::HTTPServer::Worker [virtual]
~Worker()kyototycoon::HTTPServer::Worker [virtual]
kyototycoon-0.9.56/doc/api/functions_0x74.html0000644000175000017500000001503611757471600020231 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- t -

kyototycoon-0.9.56/doc/api/functions_func_0x63.html0000644000175000017500000002060411757471600021237 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/classes.html0000644000175000017500000003410511757471600017072 0ustar mikiomikio Kyoto Tycoon: Class Index
Class Index
B | C | D | E | F | H | L | M | P | R | S | T | U | V | W
  B  
RPCServer::Logger (kyototycoon)   ThreadedServer::Session (kyototycoon)   
ThreadedServer::Logger (kyototycoon)   SharedLibrary (kyototycoon)   
RemoteDB::BulkRecord (kyototycoon)   
  M  
Socket (kyototycoon)   
  C  
  T  
MapReduce (kyototycoon)   
TimedDB::Cursor (kyototycoon)   
  P  
ThreadedServer (kyototycoon)   
RemoteDB::Cursor (kyototycoon)   TimedDB (kyototycoon)   
  D  
PluggableDB (kyototycoon)   
  U  
PluggableServer (kyototycoon)   
RPCServer::Session::Data (kyototycoon)   Pollable (kyototycoon)   UpdateLogger (kyototycoon)   
HTTPServer::Session::Data (kyototycoon)   Poller (kyototycoon)   TimedDB::UpdateTrigger (kyototycoon)   
ThreadedServer::Session::Data (kyototycoon)   
  R  
URL (kyototycoon)   
  E  
  V  
UpdateLogger::Reader (kyototycoon)   
RemoteDB::Error (kyototycoon)   MapReduce::ReduceTaskQueue::ReduceTask (kyototycoon)   MapReduce::ValueIterator (kyototycoon)   
  F  
RemoteDB (kyototycoon)   TimedDB::Visitor (kyototycoon)   
ReplicationClient (kyototycoon)   
  W  
UpdateLogger::FileStatus (kyototycoon)   RPCClient (kyototycoon)   
  H  
RPCServer (kyototycoon)   RPCServer::Worker (kyototycoon)   
  S  
ThreadedServer::Worker (kyototycoon)   
HTTPClient (kyototycoon)   HTTPServer::Worker (kyototycoon)   
HTTPServer (kyototycoon)   ServerSocket (kyototycoon)   
  L  
RPCServer::Session (kyototycoon)   
HTTPServer::Session (kyototycoon)   
HTTPServer::Logger (kyototycoon)   
B | C | D | E | F | H | L | M | P | R | S | T | U | V | W
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1MapReduce.html0000644000175000017500000007573111757471600023324 0ustar mikiomikio Kyoto Tycoon: kyototycoon::MapReduce Class Reference
kyototycoon::MapReduce Class Reference

MapReduce framework. More...

#include <ktdbext.h>

List of all members.

Classes

class  FlushThread
 Cache flusher.
class  MapChecker
 Checker for the map process.
class  MapVisitor
 Visitor for the map process.
struct  MergeLine
 Front line of a merging list.
class  ReduceTaskQueue
 Task queue for parallel reducer.
class  ValueIterator
 Value iterator for the reducer. More...

Public Types

enum  Option {
  XNOLOCK = 1 << 0, XPARAMAP = 1 << 1, XPARARED = 1 << 2, XPARAFLS = 1 << 3,
  XNOCOMP = 1 << 8
}
 Execution options. More...

Public Member Functions

 MapReduce ()
 Default constructor.
virtual ~MapReduce ()
 Destructor.
virtual bool map (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz)=0
 Map a record data.
virtual bool reduce (const char *kbuf, size_t ksiz, ValueIterator *iter)=0
 Reduce a record data.
virtual bool preprocess ()
 Preprocess the map operations.
virtual bool midprocess ()
 Mediate between the map and the reduce phases.
virtual bool postprocess ()
 Postprocess the reduce operations.
virtual bool log (const char *name, const char *message)
 Process a log message.
bool execute (TimedDB *db, const std::string &tmppath="", uint32_t opts=0)
 Execute the MapReduce process about a database.
void tune_storage (int32_t dbnum, int64_t clim, int64_t cbnum)
 Set the storage configurations.
void tune_thread (int32_t mapthnum, int32_t redthnum, int32_t flsthnum)
 Set the thread configurations.

Protected Member Functions

bool emit (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz)
 Emit a record from the mapper.

Detailed Description

MapReduce framework.

Note:
Although this framework is not distributed or concurrent, it is useful for aggregate calculation with less CPU loading and less memory usage.

Member Enumeration Documentation

Execution options.

Enumerator:
XNOLOCK 

avoid locking against update operations

XPARAMAP 

run mappers in parallel

XPARARED 

run reducers in parallel

XPARAFLS 

run cache flushers in parallel

XNOCOMP 

avoid compression of temporary databases


Constructor & Destructor Documentation

Default constructor.

virtual kyototycoon::MapReduce::~MapReduce ( ) [virtual]

Destructor.


Member Function Documentation

virtual bool kyototycoon::MapReduce::map ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz 
) [pure virtual]

Map a record data.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
Returns:
true on success, or false on failure.
Note:
This function can call the MapReduce::emit method to emit a record. To avoid deadlock, any explicit database operation must not be performed in this function.
virtual bool kyototycoon::MapReduce::reduce ( const char *  kbuf,
size_t  ksiz,
ValueIterator iter 
) [pure virtual]

Reduce a record data.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
iterthe iterator to get the values.
Returns:
true on success, or false on failure.
Note:
To avoid deadlock, any explicit database operation must not be performed in this function.
virtual bool kyototycoon::MapReduce::preprocess ( ) [virtual]

Preprocess the map operations.

Returns:
true on success, or false on failure.
Note:
This function can call the MapReduce::emit method to emit a record. To avoid deadlock, any explicit database operation must not be performed in this function.
virtual bool kyototycoon::MapReduce::midprocess ( ) [virtual]

Mediate between the map and the reduce phases.

Returns:
true on success, or false on failure.
Note:
This function can call the MapReduce::emit method to emit a record. To avoid deadlock, any explicit database operation must not be performed in this function.
virtual bool kyototycoon::MapReduce::postprocess ( ) [virtual]

Postprocess the reduce operations.

Returns:
true on success, or false on failure.
Note:
To avoid deadlock, any explicit database operation must not be performed in this function.
virtual bool kyototycoon::MapReduce::log ( const char *  name,
const char *  message 
) [virtual]

Process a log message.

Parameters:
namethe name of the event.
messagea supplement message.
Returns:
true on success, or false on failure.
bool kyototycoon::MapReduce::execute ( TimedDB db,
const std::string &  tmppath = "",
uint32_t  opts = 0 
)

Execute the MapReduce process about a database.

Parameters:
dbthe source database.
tmppaththe path of a directory for the temporary data storage. If it is an empty string, temporary data are handled on memory.
optsthe optional features by bitwise-or: MapReduce::XNOLOCK to avoid locking against update operations by other threads, MapReduce::XNOCOMP to avoid compression of temporary databases.
Returns:
true on success, or false on failure.
void kyototycoon::MapReduce::tune_storage ( int32_t  dbnum,
int64_t  clim,
int64_t  cbnum 
)

Set the storage configurations.

Parameters:
dbnumthe number of temporary databases.
climthe limit size of the internal cache.
cbnumthe bucket number of the internal cache.
void kyototycoon::MapReduce::tune_thread ( int32_t  mapthnum,
int32_t  redthnum,
int32_t  flsthnum 
)

Set the thread configurations.

Parameters:
mapthnumthe number of threads for the mapper.
redthnumthe number of threads for the reducer.
flsthnumthe number of threads for the internal flusher.
bool kyototycoon::MapReduce::emit ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz 
) [protected]

Emit a record from the mapper.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
Returns:
true on success, or false on failure.
kyototycoon-0.9.56/doc/api/functions_func_0x69.html0000644000175000017500000001273311757471600021251 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/functions_func_0x64.html0000644000175000017500000001324611757471600021244 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RemoteDB_1_1Cursor-members.html0000644000175000017500000002267411757471600026404 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RemoteDB::Cursor Member List
This is the complete list of members for kyototycoon::RemoteDB::Cursor, including all inherited members.
Cursor(RemoteDB *db)kyototycoon::RemoteDB::Cursor [explicit]
db()kyototycoon::RemoteDB::Cursor
error()kyototycoon::RemoteDB::Cursor
get(size_t *ksp, const char **vbp, size_t *vsp, int64_t *xtp=NULL, bool step=false)kyototycoon::RemoteDB::Cursor
get(std::string *key, std::string *value, int64_t *xtp=NULL, bool step=false)kyototycoon::RemoteDB::Cursor
get_key(size_t *sp, bool step=false)kyototycoon::RemoteDB::Cursor
get_key(std::string *key, bool step=false)kyototycoon::RemoteDB::Cursor
get_value(size_t *sp, bool step=false)kyototycoon::RemoteDB::Cursor
get_value(std::string *value, bool step=false)kyototycoon::RemoteDB::Cursor
jump()kyototycoon::RemoteDB::Cursor
jump(const char *kbuf, size_t ksiz)kyototycoon::RemoteDB::Cursor
jump(const std::string &key)kyototycoon::RemoteDB::Cursor
jump_back()kyototycoon::RemoteDB::Cursor
jump_back(const char *kbuf, size_t ksiz)kyototycoon::RemoteDB::Cursor
jump_back(const std::string &key)kyototycoon::RemoteDB::Cursor
RemoteDB (defined in kyototycoon::RemoteDB::Cursor)kyototycoon::RemoteDB::Cursor [friend]
remove()kyototycoon::RemoteDB::Cursor
seize(size_t *ksp, const char **vbp, size_t *vsp, int64_t *xtp=NULL)kyototycoon::RemoteDB::Cursor
seize(std::string *key, std::string *value, int64_t *xtp=NULL)kyototycoon::RemoteDB::Cursor
set_value(const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX, bool step=false)kyototycoon::RemoteDB::Cursor
set_value_str(const std::string &value, int64_t xt=kc::INT64MAX, bool step=false)kyototycoon::RemoteDB::Cursor
step()kyototycoon::RemoteDB::Cursor
step_back()kyototycoon::RemoteDB::Cursor
~Cursor()kyototycoon::RemoteDB::Cursor [virtual]
kyototycoon-0.9.56/doc/api/functions_0x6a.html0000644000175000017500000001262111757471600020302 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- j -

kyototycoon-0.9.56/doc/api/ktremotedb_8h.html0000644000175000017500000001344611757471600020201 0ustar mikiomikio Kyoto Tycoon: ktremotedb.h File Reference
ktremotedb.h File Reference

remote database More...

#include <ktcommon.h>
#include <ktutil.h>
#include <ktsocket.h>
#include <ktthserv.h>
#include <kthttp.h>
#include <ktrpc.h>
#include <ktulog.h>
#include <ktshlib.h>
#include <kttimeddb.h>
#include <ktdbext.h>

Classes

class  kyototycoon::RemoteDB
 Remote database. More...
class  kyototycoon::RemoteDB::Cursor
 Cursor to indicate a record. More...
class  kyototycoon::RemoteDB::Error
 Error data. More...
struct  kyototycoon::RemoteDB::BulkRecord
 Record for bulk operation. More...
struct  kyototycoon::RemoteDB::OrderedKey
 Key with the order.
class  kyototycoon::ReplicationClient
 Replication client. More...

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.



Detailed Description

remote database

kyototycoon-0.9.56/doc/api/functions_func_0x76.html0000644000175000017500000001225111757471600021242 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/functions_0x70.html0000644000175000017500000002057311757471600020227 0ustar mikiomikio Kyoto Tycoon: Class Members kyototycoon-0.9.56/doc/api/ktplugdb_8h.html0000644000175000017500000001201411757471600017643 0ustar mikiomikio Kyoto Tycoon: ktplugdb.h File Reference
ktplugdb.h File Reference

pluggable database interface More...

#include <ktcommon.h>
#include <ktutil.h>
#include <ktsocket.h>
#include <ktthserv.h>
#include <kthttp.h>
#include <ktrpc.h>
#include <ktulog.h>
#include <ktshlib.h>
#include <kttimeddb.h>
#include <ktdbext.h>
#include <ktremotedb.h>

Classes

class  kyototycoon::PluggableDB
 Interface of pluggable database abstraction. More...

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.


Typedefs

typedef PluggableDB *(* kyototycoon::KTDBINIT )()
 Initializer of a database implementation.

Variables

const char *const kyototycoon::KTDBINITNAME = "ktdbinit"
 The name of the initializer function.

Detailed Description

pluggable database interface

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1UpdateLogger-members.html0000644000175000017500000001221011757471600025450 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::UpdateLogger Member List
This is the complete list of members for kyototycoon::UpdateLogger, including all inherited members.
clock()kyototycoon::UpdateLogger
clock_pure()kyototycoon::UpdateLogger [static]
close()kyototycoon::UpdateLogger
list_files(std::vector< FileStatus > *fstvec)kyototycoon::UpdateLogger
open(const std::string &path, int64_t limsiz=-1, double asi=-1)kyototycoon::UpdateLogger
UpdateLogger()kyototycoon::UpdateLogger [explicit]
write(const char *mbuf, size_t msiz, uint64_t ts=0)kyototycoon::UpdateLogger
write_bulk(const std::vector< std::string > &mvec, uint64_t ts=0)kyototycoon::UpdateLogger
write_volatile(char *mbuf, size_t msiz, uint64_t ts=0)kyototycoon::UpdateLogger
~UpdateLogger()kyototycoon::UpdateLogger
kyototycoon-0.9.56/doc/api/functions_0x6c.html0000644000175000017500000001453311757471600020310 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- l -

kyototycoon-0.9.56/doc/api/namespacekyototycoon.html0000644000175000017500000021736711757471600021730 0ustar mikiomikio Kyoto Tycoon: kyototycoon Namespace Reference
kyototycoon Namespace Reference

All symbols of Kyoto Tycoon. More...

Classes

class  MapReduce
 MapReduce framework. More...
class  URL
 URL accessor. More...
class  HTTPClient
 HTTP client. More...
class  HTTPServer
 HTTP server. More...
class  PluggableDB
 Interface of pluggable database abstraction. More...
class  PluggableServer
 Interface of pluggable server abstraction. More...
class  RemoteDB
 Remote database. More...
class  ReplicationClient
 Replication client. More...
class  RPCClient
 RPC client. More...
class  RPCServer
 RPC server. More...
class  SharedLibrary
 Shared library. More...
class  Pollable
 Interface of poolable I/O event. More...
class  Socket
 Network stream abstraction based on TCP/IP. More...
class  ServerSocket
 Network server abstraction based on TCP/IP. More...
class  Poller
 I/O event notification. More...
class  ThreadedServer
 Threaded TCP Server. More...
class  TimedDB
 Timed database. More...
class  UpdateLogger
 Update logger. More...

Typedefs

typedef PluggableDB *(* KTDBINIT )()
 Initializer of a database implementation.
typedef PluggableServer *(* KTSERVINIT )()
 Initializer of a server implementation.

Functions

bool setkillsignalhandler (void(*handler)(int))
 Set the signal handler for termination signals.
bool maskthreadsignal ()
 Set the signal mask of the current to ignore all.
bool daemonize ()
 Switch the process into the background.
int32_t executecommand (const std::vector< std::string > &args)
 Execute a shell command.
const char * strmapget (const std::map< std::string, std::string > &map, const char *key, size_t *sp=NULL)
 Get the C-style string value of a record in a string map.
void printstrvec (const std::vector< std::string > &vec, std::ostream &strm=std::cout)
 Print all records in a string vector.
void printstrmap (const std::map< std::string, std::string > &map, std::ostream &strm=std::cout)
 Print all records in a string map.
void urlbreak (const char *url, std::map< std::string, std::string > *elems)
 Break up a URL into elements.
char * xmlescape (const char *str)
 Escape meta characters in a string with the entity references of XML.
char * xmlunescape (const char *str)
 Unescape meta characters in a string with the entity references of XML.
void wwwformtomap (const std::string &str, std::map< std::string, std::string > *map)
 Parse a www-form-urlencoded string and store each records into a map.
void maptowwwform (const std::map< std::string, std::string > &map, std::string *str)
 Serialize a string map into a www-form-urlencoded string.
void tsvtomap (const std::string &str, std::map< std::string, std::string > *map)
 Parse a TSV string and store each records into a map.
void maptotsv (const std::map< std::string, std::string > &map, std::string *str)
 Serialize a string map into a TSV string.
void tsvmapencode (std::map< std::string, std::string > *map, int32_t mode)
 Encode each record of a string map.
void tsvmapdecode (std::map< std::string, std::string > *map, int32_t mode)
 Decode each record of a string map.
int32_t checkmapenc (const std::map< std::string, std::string > &map)
 Check the best suited encoding of a string map.
char * strcapitalize (char *str)
 Capitalize letters of a string.
bool strisalnum (const char *str)
 Check a string is composed of alphabets or numbers only.
void strtokenize (const char *str, std::vector< std::string > *tokens)
 Tokenize a string separating by space characters.
void getcalendar (int64_t t, int32_t jl, int32_t *yearp=NULL, int32_t *monp=NULL, int32_t *dayp=NULL, int32_t *hourp=NULL, int32_t *minp=NULL, int32_t *secp=NULL)
 Get the Gregorian calendar of a time.
void datestrwww (int64_t t, int32_t jl, char *buf)
 Format a date as a string in W3CDTF.
void datestrwww (double t, int32_t jl, int32_t acr, char *buf)
 Format a date as a string in W3CDTF with the fraction part.
void datestrhttp (int64_t t, int32_t jl, char *buf)
 Format a date as a string in RFC 1123 format.
int64_t strmktime (const char *str)
 Get the time value of a date string.
int32_t jetlag ()
 Get the jet lag of the local time.
int32_t dayofweek (int32_t year, int32_t mon, int32_t day)
 Get the day of week of a date.
bool getlocaltime (time_t time, struct std::tm *result)
 Get the local time of a time.
bool getgmtime (time_t time, struct std::tm *result)
 Get the GMT local time of a time.
time_t mkgmtime (struct std::tm *tm)
 Make the GMT from a time structure.

Variables

const char *const KTDBINITNAME = "ktdbinit"
 The name of the initializer function.
const char *const KTSERVINITNAME = "ktservinit"
 The name of the initializer function.
const char *const VERSION
 The package version.
const int32_t LIBVER
 The library version.
const int32_t LIBREV
 The library revision.
const char *const FEATURES
 The extra feature list.
const int32_t DEFPORT = 1978
 The default port number.

Detailed Description

All symbols of Kyoto Tycoon.

Common namespace of Kyoto Tycoon.


Typedef Documentation

Initializer of a database implementation.

Note:
Each shared library of a pluggable database module must implement a function whose name is "ktdbinit" and return a new instance of a derived class of the PluggableDB class. The instance will be deleted implicitly by the caller.

Initializer of a server implementation.

Note:
Each shared library of a pluggable server module must implement a function whose name is "ktservinit" and return a new instance of a derived class of the PluggableServer class. The instance will be deleted implicitly by the caller.

Function Documentation

bool kyototycoon::setkillsignalhandler ( void(*)(int)  handler)

Set the signal handler for termination signals.

Parameters:
handlerthe function pointer of the signal handler.
Returns:
true on success, or false on failure.

Set the signal mask of the current to ignore all.

Returns:
true on success, or false on failure.

Switch the process into the background.

Returns:
true on success, or false on failure.
int32_t kyototycoon::executecommand ( const std::vector< std::string > &  args)

Execute a shell command.

Parameters:
argsan array of the command name and its arguments.
Returns:
the exit code of the command or `INT32_MIN' on failure.
Note:
The command name and the arguments are quoted and meta characters are escaped.
const char * kyototycoon::strmapget ( const std::map< std::string, std::string > &  map,
const char *  key,
size_t *  sp = NULL 
)

Get the C-style string value of a record in a string map.

Parameters:
mapthe target string map.
keythe key.
spthe pointer to the variable into which the size of the region of the return value is assigned. If it is NULL, it is ignored.
Returns:
the C-style string value of the corresponding record, or NULL if there is no corresponding record.
void kyototycoon::printstrvec ( const std::vector< std::string > &  vec,
std::ostream &  strm = std::cout 
)

Print all records in a string vector.

Parameters:
vecthe target string vector.
strmthe output stream.
void kyototycoon::printstrmap ( const std::map< std::string, std::string > &  map,
std::ostream &  strm = std::cout 
)

Print all records in a string map.

Parameters:
mapthe target string map.
strmthe output stream.
void kyototycoon::urlbreak ( const char *  url,
std::map< std::string, std::string > *  elems 
)

Break up a URL into elements.

Parameters:
urlthe URL string.
elemsthe map object to contain the result elements. The key "self" indicates the URL itself. "scheme" indicates the scheme. "host" indicates the host of the server. "port" indicates the port number of the server. "authority" indicates the authority information. "path" indicates the path of the resource. "file" indicates the file name without the directory section. "query" indicates the query string. "fragment" indicates the fragment string.
Note:
Supported schema are HTTP, HTTPS, FTP, and FILE. Both of absolute URL and relative URL are supported.
char * kyototycoon::xmlescape ( const char *  str)

Escape meta characters in a string with the entity references of XML.

Parameters:
strthe string.
Returns:
the escaped string.
Note:
Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
char * kyototycoon::xmlunescape ( const char *  str)

Unescape meta characters in a string with the entity references of XML.

Parameters:
strthe string.
Returns:
the unescaped string.
Note:
Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
void kyototycoon::wwwformtomap ( const std::string &  str,
std::map< std::string, std::string > *  map 
)

Parse a www-form-urlencoded string and store each records into a map.

Parameters:
strthe source string.
mapthe destination string map.
void kyototycoon::maptowwwform ( const std::map< std::string, std::string > &  map,
std::string *  str 
)

Serialize a string map into a www-form-urlencoded string.

Parameters:
mapthe source string map.
strthe destination string.
void kyototycoon::tsvtomap ( const std::string &  str,
std::map< std::string, std::string > *  map 
)

Parse a TSV string and store each records into a map.

Parameters:
strthe source string.
mapthe destination string map.
void kyototycoon::maptotsv ( const std::map< std::string, std::string > &  map,
std::string *  str 
)

Serialize a string map into a TSV string.

Parameters:
mapthe source string map.
strthe destination string.
void kyototycoon::tsvmapencode ( std::map< std::string, std::string > *  map,
int32_t  mode 
)

Encode each record of a string map.

Parameters:
mapthe string map.
modethe encoding mode. 'B' for Base64 encoding, 'Q' for Quoted-printable encoding, 'U' for URL encoding.
void kyototycoon::tsvmapdecode ( std::map< std::string, std::string > *  map,
int32_t  mode 
)

Decode each record of a string map.

Parameters:
mapthe string map.
modethe encoding mode. 'B' for Base64 encoding, 'Q' for Quoted-printable encoding, 'U' for URL encoding.
int32_t kyototycoon::checkmapenc ( const std::map< std::string, std::string > &  map)

Check the best suited encoding of a string map.

Parameters:
mapthe string map.
Returns:
the the best suited encoding. 0 for the raw format, 'B' for Base64 encoding, 'Q' for Quoted-printable encoding,
char * kyototycoon::strcapitalize ( char *  str)

Capitalize letters of a string.

Parameters:
strthe string to convert.
Returns:
the string itself.
bool kyototycoon::strisalnum ( const char *  str)

Check a string is composed of alphabets or numbers only.

Returns:
true if it is composed of alphabets or numbers only, or false if not.
void kyototycoon::strtokenize ( const char *  str,
std::vector< std::string > *  tokens 
)

Tokenize a string separating by space characters.

Parameters:
strthe source string.
tokensa string vector to contain the result tokens.
void kyototycoon::getcalendar ( int64_t  t,
int32_t  jl,
int32_t *  yearp = NULL,
int32_t *  monp = NULL,
int32_t *  dayp = NULL,
int32_t *  hourp = NULL,
int32_t *  minp = NULL,
int32_t *  secp = NULL 
)

Get the Gregorian calendar of a time.

Parameters:
tthe source time in seconds from the epoch. If it is kyotocabinet::INT64MAX, the current time is specified.
jlthe jet lag of a location in seconds. If it is kyotocabinet::INT32MAX, the local jet lag is specified.
yearpthe pointer to a variable to which the year is assigned. If it is NULL, it is not used.
monpthe pointer to a variable to which the month is assigned. If it is NULL, it is not used. 1 means January and 12 means December.
daypthe pointer to a variable to which the day of the month is assigned. If it is NULL, it is not used.
hourpthe pointer to a variable to which the hours is assigned. If it is NULL, it is not used.
minpthe pointer to a variable to which the minutes is assigned. If it is NULL, it is not used.
secpthe pointer to a variable to which the seconds is assigned. If it is NULL, it is not used.
void kyototycoon::datestrwww ( int64_t  t,
int32_t  jl,
char *  buf 
)

Format a date as a string in W3CDTF.

Parameters:
tthe source time in seconds from the epoch. If it is kyotocabinet::INT64MAX, the current time is specified.
jlthe jet lag of a location in seconds. If it is kyotocabinet::INT32MAX, the local jet lag is specified.
bufthe pointer to the region into which the result string is written. The size of the buffer should be equal to or more than 48 bytes.
void kyototycoon::datestrwww ( double  t,
int32_t  jl,
int32_t  acr,
char *  buf 
)

Format a date as a string in W3CDTF with the fraction part.

Parameters:
tthe source time in seconds from the epoch. If it is Not-a-Number, the current time is specified.
jlthe jet lag of a location in seconds. If it is kyotocabinet::INT32MAX, the local jet lag is specified.
acrthe accuracy of time by the number of columns of the fraction part.
bufthe pointer to the region into which the result string is written. The size of the buffer should be equal to or more than 48 bytes.
void kyototycoon::datestrhttp ( int64_t  t,
int32_t  jl,
char *  buf 
)

Format a date as a string in RFC 1123 format.

Parameters:
tthe source time in seconds from the epoch. If it is kyotocabinet::INT64MAX, the current time is specified.
jlthe jet lag of a location in seconds. If it is kyotocabinet::INT32MAX, the local jet lag is specified.
bufthe pointer to the region into which the result string is written. The size of the buffer should be equal to or more than 48 bytes.
int64_t kyototycoon::strmktime ( const char *  str)

Get the time value of a date string.

Parameters:
strthe date string in decimal, hexadecimal, W3CDTF, or RFC 822 (1123). Decimal can be trailed by "s" for in seconds, "m" for in minutes, "h" for in hours, and "d" for in days.
Returns:
the time value of the date or INT64_MIN if the format is invalid.
int32_t kyototycoon::jetlag ( )

Get the jet lag of the local time.

Returns:
the jet lag of the local time in seconds.
int32_t kyototycoon::dayofweek ( int32_t  year,
int32_t  mon,
int32_t  day 
)

Get the day of week of a date.

Parameters:
yearthe year of a date.
monthe month of the date.
daythe day of the date.
Returns:
the day of week of the date. 0 means Sunday and 6 means Saturday.
bool kyototycoon::getlocaltime ( time_t  time,
struct std::tm *  result 
)

Get the local time of a time.

Parameters:
timethe time.
resultthe resulb buffer.
Returns:
true on success, or false on failure.
bool kyototycoon::getgmtime ( time_t  time,
struct std::tm *  result 
)

Get the GMT local time of a time.

Parameters:
timethe time.
resultthe resulb buffer.
Returns:
true on success, or false on failure.
time_t kyototycoon::mkgmtime ( struct std::tm *  tm)

Make the GMT from a time structure.

Parameters:
tmthe pointer to the time structure.
Returns:
the GMT.

Variable Documentation

const char* const kyototycoon::KTDBINITNAME = "ktdbinit"

The name of the initializer function.

const char* const kyototycoon::KTSERVINITNAME = "ktservinit"

The name of the initializer function.

const char* const kyototycoon::VERSION

The package version.

const int32_t kyototycoon::LIBVER

The library version.

const int32_t kyototycoon::LIBREV

The library revision.

const char* const kyototycoon::FEATURES

The extra feature list.

const int32_t kyototycoon::DEFPORT = 1978

The default port number.

kyototycoon-0.9.56/doc/api/functions_0x65.html0000644000175000017500000002067311757471600020234 0ustar mikiomikio Kyoto Tycoon: Class Members kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer_1_1Session_1_1Data.html0000644000175000017500000001102211757471600026507 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RPCServer::Session::Data Class Reference
kyototycoon::RPCServer::Session::Data Class Reference

Interface of session local data. More...

#include <ktrpc.h>

List of all members.

Public Member Functions

virtual ~Data ()
 Destructor.

Detailed Description

Interface of session local data.


Constructor & Destructor Documentation

Destructor.

Reimplemented from kyototycoon::HTTPServer::Session::Data.

kyototycoon-0.9.56/doc/api/annotated.html0000644000175000017500000002416111757471600017413 0ustar mikiomikio Kyoto Tycoon: Class List
Class List
Here are the classes, structs, unions and interfaces with brief descriptions:
kyototycoon::RemoteDB::BulkRecordRecord for bulk operation
kyototycoon::RemoteDB::CursorCursor to indicate a record
kyototycoon::TimedDB::CursorCursor to indicate a record
kyototycoon::ThreadedServer::Session::DataInterface of session local data
kyototycoon::HTTPServer::Session::DataInterface of session local data
kyototycoon::RPCServer::Session::DataInterface of session local data
kyototycoon::RemoteDB::ErrorError data
kyototycoon::UpdateLogger::FileStatusStatus of each log file
kyototycoon::HTTPClientHTTP client
kyototycoon::HTTPServerHTTP server
kyototycoon::ThreadedServer::LoggerInterface to log internal information and errors
kyototycoon::RPCServer::LoggerInterface to log internal information and errors
kyototycoon::HTTPServer::LoggerInterface to log internal information and errors
kyototycoon::MapReduceMapReduce framework
kyototycoon::PluggableDBInterface of pluggable database abstraction
kyototycoon::PluggableServerInterface of pluggable server abstraction
kyototycoon::PollableInterface of poolable I/O event
kyototycoon::PollerI/O event notification
kyototycoon::UpdateLogger::ReaderReader of update logs
kyototycoon::MapReduce::ReduceTaskQueue::ReduceTaskTask for parallel reducer
kyototycoon::RemoteDBRemote database
kyototycoon::ReplicationClientReplication client
kyototycoon::RPCClientRPC client
kyototycoon::RPCServerRPC server
kyototycoon::ServerSocketNetwork server abstraction based on TCP/IP
kyototycoon::ThreadedServer::SessionInterface to access each session data
kyototycoon::HTTPServer::SessionInterface to access each session data
kyototycoon::RPCServer::SessionInterface to log internal information and errors
kyototycoon::SharedLibraryShared library
kyototycoon::SocketNetwork stream abstraction based on TCP/IP
kyototycoon::ThreadedServerThreaded TCP Server
kyototycoon::TimedDBTimed database
kyototycoon::UpdateLoggerUpdate logger
kyototycoon::TimedDB::UpdateTriggerInterface to trigger update operations
kyototycoon::URLURL accessor
kyototycoon::MapReduce::ValueIteratorValue iterator for the reducer
kyototycoon::TimedDB::VisitorInterface to access a record
kyototycoon::HTTPServer::WorkerInterface to process each request
kyototycoon::ThreadedServer::WorkerInterface to process each request
kyototycoon::RPCServer::WorkerInterface to process each request
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1TimedDB_1_1UpdateTrigger.html0000644000175000017500000002067311757471600026051 0ustar mikiomikio Kyoto Tycoon: kyototycoon::TimedDB::UpdateTrigger Class Reference
kyototycoon::TimedDB::UpdateTrigger Class Reference

Interface to trigger update operations. More...

#include <kttimeddb.h>

List of all members.

Public Member Functions

virtual ~UpdateTrigger ()
 Destructor.
virtual void trigger (const char *mbuf, size_t msiz)=0
 Trigger an update operation.
virtual void begin_transaction ()=0
 Begin transaction.
virtual void end_transaction (bool commit)=0
 End transaction.

Detailed Description

Interface to trigger update operations.


Constructor & Destructor Documentation

Destructor.


Member Function Documentation

virtual void kyototycoon::TimedDB::UpdateTrigger::trigger ( const char *  mbuf,
size_t  msiz 
) [pure virtual]

Trigger an update operation.

Parameters:
mbufthe pointer to the message region.
msizthe size of the message region.

Begin transaction.

virtual void kyototycoon::TimedDB::UpdateTrigger::end_transaction ( bool  commit) [pure virtual]

End transaction.

Parameters:
committrue to commit the transaction, or false to abort the transaction.
kyototycoon-0.9.56/doc/api/nav_h.png0000644000175000017500000000014111757471600016341 0ustar mikiomikio‰PNG  IHDR ,é@(IDATxíݱ 0 A½2°ÁU¶— !kÜJrª¯ƒžZýÿÆo‡üèIEND®B`‚kyototycoon-0.9.56/doc/api/classkyototycoon_1_1PluggableServer-members.html0000644000175000017500000000764711757471600026201 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::PluggableServer Member List
This is the complete list of members for kyototycoon::PluggableServer, including all inherited members.
configure(TimedDB *dbary, size_t dbnum, ThreadedServer::Logger *logger, uint32_t logkinds, const char *expr)=0kyototycoon::PluggableServer [pure virtual]
finish()=0kyototycoon::PluggableServer [pure virtual]
start()=0kyototycoon::PluggableServer [pure virtual]
stop()=0kyototycoon::PluggableServer [pure virtual]
~PluggableServer()kyototycoon::PluggableServer [virtual]
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer-members.html0000644000175000017500000001365011757471600026006 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::ThreadedServer Member List
This is the complete list of members for kyototycoon::ThreadedServer, including all inherited members.
aborted()kyototycoon::ThreadedServer
connection_count()kyototycoon::ThreadedServer
finish()kyototycoon::ThreadedServer
log(Logger::Kind kind, const char *format,...)kyototycoon::ThreadedServer
log_v(Logger::Kind kind, const char *format, va_list ap)kyototycoon::ThreadedServer
set_logger(Logger *logger, uint32_t kinds=Logger::SYSTEM|Logger::ERROR)kyototycoon::ThreadedServer
set_network(const std::string &expr, double timeout=-1)kyototycoon::ThreadedServer
set_worker(Worker *worker, size_t thnum=1)kyototycoon::ThreadedServer
start()kyototycoon::ThreadedServer
stop()kyototycoon::ThreadedServer
task_count()kyototycoon::ThreadedServer
ThreadedServer()kyototycoon::ThreadedServer [explicit]
~ThreadedServer()kyototycoon::ThreadedServer
kyototycoon-0.9.56/doc/api/functions_func_0x71.html0000644000175000017500000001045211757471600021236 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions
 

- q -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer-members.html0000644000175000017500000001233211757471600024706 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RPCServer Member List
This is the complete list of members for kyototycoon::RPCServer, including all inherited members.
finish()kyototycoon::RPCServer
log(Logger::Kind kind, const char *format,...)kyototycoon::RPCServer
log_v(Logger::Kind kind, const char *format, va_list ap)kyototycoon::RPCServer
reveal_core()kyototycoon::RPCServer
RPCServer()kyototycoon::RPCServer [explicit]
set_logger(Logger *logger, uint32_t kinds=Logger::SYSTEM|Logger::ERROR)kyototycoon::RPCServer
set_network(const std::string &expr, double timeout=-1)kyototycoon::RPCServer
set_worker(Worker *worker, size_t thnum=1)kyototycoon::RPCServer
start()kyototycoon::RPCServer
stop()kyototycoon::RPCServer
~RPCServer()kyototycoon::RPCServer
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ReplicationClient-members.html0000644000175000017500000001071611757471600026507 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::ReplicationClient Member List
This is the complete list of members for kyototycoon::ReplicationClient, including all inherited members.
alive()kyototycoon::ReplicationClient
close()kyototycoon::ReplicationClient
open(const std::string &host="", int32_t port=DEFPORT, double timeout=-1, uint64_t ts=0, uint16_t sid=0, uint32_t opts=0)kyototycoon::ReplicationClient
Option enum namekyototycoon::ReplicationClient
read(size_t *sp, uint64_t *tsp)kyototycoon::ReplicationClient
ReplicationClient()kyototycoon::ReplicationClient [explicit]
WHITESID enum valuekyototycoon::ReplicationClient
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1PluggableDB-members.html0000644000175000017500000000524611757471600025211 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::PluggableDB Member List
This is the complete list of members for kyototycoon::PluggableDB, including all inherited members.
~PluggableDB()kyototycoon::PluggableDB [virtual]
kyototycoon-0.9.56/doc/api/functions_0x76.html0000644000175000017500000001272611757471600020236 0ustar mikiomikio Kyoto Tycoon: Class Members
Here is a list of all documented class members with links to the class documentation for each member:

- v -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1PluggableServer.html0000644000175000017500000002477411757471600024551 0ustar mikiomikio Kyoto Tycoon: kyototycoon::PluggableServer Class Reference
kyototycoon::PluggableServer Class Reference

Interface of pluggable server abstraction. More...

#include <ktplugserv.h>

List of all members.

Public Member Functions

virtual ~PluggableServer ()
 Destructor.
virtual void configure (TimedDB *dbary, size_t dbnum, ThreadedServer::Logger *logger, uint32_t logkinds, const char *expr)=0
 Configure server settings.
virtual bool start ()=0
 Start the service.
virtual bool stop ()=0
 Stop the service.
virtual bool finish ()=0
 Finish the service.

Detailed Description

Interface of pluggable server abstraction.


Constructor & Destructor Documentation

Destructor.


Member Function Documentation

virtual void kyototycoon::PluggableServer::configure ( TimedDB dbary,
size_t  dbnum,
ThreadedServer::Logger logger,
uint32_t  logkinds,
const char *  expr 
) [pure virtual]

Configure server settings.

Parameters:
dbaryan array of the database objects.
dbnumthe number of the database objects.
loggerthe logger object.
logkindskinds of logged messages by bitwise-or: Logger::DEBUG for debugging, Logger::INFO for normal information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error.
expran expression given in the command line.
virtual bool kyototycoon::PluggableServer::start ( ) [pure virtual]

Start the service.

Returns:
true on success, or false on failure.
virtual bool kyototycoon::PluggableServer::stop ( ) [pure virtual]

Stop the service.

Returns:
true on success, or false on failure.
virtual bool kyototycoon::PluggableServer::finish ( ) [pure virtual]

Finish the service.

Returns:
true on success, or false on failure.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer_1_1Logger.html0000644000175000017500000001103311757471600025206 0ustar mikiomikio Kyoto Tycoon: kyototycoon::HTTPServer::Logger Class Reference
kyototycoon::HTTPServer::Logger Class Reference

Interface to log internal information and errors. More...

#include <kthttp.h>

List of all members.

Public Member Functions

virtual ~Logger ()
 Destructor.

Detailed Description

Interface to log internal information and errors.


Constructor & Destructor Documentation

Destructor.

Reimplemented from kyototycoon::ThreadedServer::Logger.

Reimplemented in kyototycoon::RPCServer::Logger.

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer_1_1Session-members.html0000644000175000017500000001030111757471600027037 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::HTTPServer::Session Member List
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer_1_1Session_1_1Data.html0000644000175000017500000001133511757471600026651 0ustar mikiomikio Kyoto Tycoon: kyototycoon::HTTPServer::Session::Data Class Reference
kyototycoon::HTTPServer::Session::Data Class Reference

Interface of session local data. More...

#include <kthttp.h>

List of all members.

Public Member Functions

virtual ~Data ()
 Destructor.

Detailed Description

Interface of session local data.


Constructor & Destructor Documentation

kyototycoon-0.9.56/doc/api/functions_0x63.html0000644000175000017500000002127011757471600020224 0ustar mikiomikio Kyoto Tycoon: Class Members kyototycoon-0.9.56/doc/api/classkyototycoon_1_1HTTPServer.html0000644000175000017500000007003211757471600023412 0ustar mikiomikio Kyoto Tycoon: kyototycoon::HTTPServer Class Reference
kyototycoon::HTTPServer Class Reference

HTTP server. More...

#include <kthttp.h>

List of all members.

Classes

class  Logger
 Interface to log internal information and errors. More...
class  Session
 Interface to access each session data. More...
class  Worker
 Interface to process each request. More...
class  WorkerAdapter
 Adapter for the worker.

Public Member Functions

 HTTPServer ()
 Default constructor.
 ~HTTPServer ()
 Destructor.
void set_network (const std::string &expr, double timeout=-1, const std::string &name="")
 Set the network configurations.
void set_logger (Logger *logger, uint32_t kinds=Logger::SYSTEM|Logger::ERROR)
 Set the logger to process each log message.
void set_worker (Worker *worker, size_t thnum=1)
 Set the worker to process each request.
bool start ()
 Start the service.
bool stop ()
 Stop the service.
bool finish ()
 Finish the service.
void log (Logger::Kind kind, const char *format,...)
 Log a message.
void log_v (Logger::Kind kind, const char *format, va_list ap)
 Log a message.
ThreadedServerreveal_core ()
 Reveal the internal TCP server.

Static Public Member Functions

static const char * status_name (int32_t code)
 Get the name of a status code.
static const char * media_type (const std::string &url)
 Guess the media type of a URL.
static std::string localize_path (const std::string &path)
 Convert the path element of a URL into the local path.

Detailed Description

HTTP server.


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

void kyototycoon::HTTPServer::set_network ( const std::string &  expr,
double  timeout = -1,
const std::string &  name = "" 
)

Set the network configurations.

Parameters:
expran expression of the address and the port of the server.
timeoutthe timeout of each network operation in seconds. If it is not more than 0, no timeout is specified.
namethe name of the server. If it is an empty string, the host name is specified.
void kyototycoon::HTTPServer::set_logger ( Logger logger,
uint32_t  kinds = Logger::SYSTEM | Logger::ERROR 
)

Set the logger to process each log message.

Parameters:
loggerthe logger object.
kindskinds of logged messages by bitwise-or: Logger::DEBUG for debugging, Logger::INFO for normal information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error.
void kyototycoon::HTTPServer::set_worker ( Worker worker,
size_t  thnum = 1 
)

Set the worker to process each request.

Parameters:
workerthe worker object.
thnumthe number of worker threads.

Start the service.

Returns:
true on success, or false on failure.
Note:
This function blocks until the server stops by the HTTPServer::stop method.

Stop the service.

Returns:
true on success, or false on failure.

Finish the service.

Returns:
true on success, or false on failure.
void kyototycoon::HTTPServer::log ( Logger::Kind  kind,
const char *  format,
  ... 
)

Log a message.

Parameters:
kindthe kind of the event. Logger::DEBUG for debugging, Logger::INFO for normal information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error.
formatthe printf-like format string. The conversion character `' can be used with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `'.
...used according to the format string.
void kyototycoon::HTTPServer::log_v ( Logger::Kind  kind,
const char *  format,
va_list  ap 
)

Log a message.

Note:
Equal to the original Cursor::set_value method except that the last parameters is va_list.

Reveal the internal TCP server.

Returns:
the internal TCP server.
static const char* kyototycoon::HTTPServer::status_name ( int32_t  code) [static]

Get the name of a status code.

Returns:
the name of a status code.
static const char* kyototycoon::HTTPServer::media_type ( const std::string &  url) [static]

Guess the media type of a URL.

Parameters:
urlthe URL.
Returns:
the media type string, or NULL on failure.
static std::string kyototycoon::HTTPServer::localize_path ( const std::string &  path) [static]

Convert the path element of a URL into the local path.

Parameters:
paththe path element of a URL.
Returns:
the local path.
kyototycoon-0.9.56/doc/api/functions_eval.html0000644000175000017500000002737111757471600020463 0ustar mikiomikio Kyoto Tycoon: Class Members - Enumerator
 

- b -

- d -

- e -

- i -

- l -

- m -

- n -

- r -

- s -

- t -

- w -

- x -

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1Poller.html0000644000175000017500000004441711757471600022711 0ustar mikiomikio Kyoto Tycoon: kyototycoon::Poller Class Reference
kyototycoon::Poller Class Reference

I/O event notification. More...

#include <ktsocket.h>

List of all members.

Public Member Functions

 Poller ()
 Default constructor.
 ~Poller ()
 Destructor.
const char * error ()
 Get the last happened error information.
bool open ()
 Open the poller.
bool close ()
 Close the poller.
bool deposit (Pollable *event)
 Add a pollable I/O event to the monitored list.
bool withdraw (Pollable *event)
 Remove a pollable I/O from the monitored list.
Pollablenext ()
 Fetch the next notified I/O event.
bool undo (Pollable *event)
 Enable the next notification of a pollable event.
bool wait (double timeout=-1)
 Wait one or more notifying events.
bool flush ()
 Notify all registered events.
int64_t count ()
 Get the number of events to watch.
bool abort ()
 Abort the current operation.

Detailed Description

I/O event notification.


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

const char* kyototycoon::Poller::error ( )

Get the last happened error information.

Returns:
the last happened error information.

Open the poller.

Returns:
true on success, or false on failure.

Close the poller.

Returns:
true on success, or false on failure.

Add a pollable I/O event to the monitored list.

Parameters:
eventthe pollable event object.
Returns:
true on success, or false on failure.

Remove a pollable I/O from the monitored list.

Parameters:
eventthe pollable event object.
Returns:
true on success, or false on failure.

Fetch the next notified I/O event.

Returns:
the event object, or NULL on failure.

Enable the next notification of a pollable event.

Parameters:
eventthe pollable event object.
Returns:
true on success, or false on failure.
bool kyototycoon::Poller::wait ( double  timeout = -1)

Wait one or more notifying events.

Parameters:
timeoutthe timeout in seconds. If it is not more than 0, no timeout is specified.
Returns:
true on success, or false on failure.

Notify all registered events.

Returns:
true on success, or false on failure.

Get the number of events to watch.

Returns:
the number of events to watch, or -1 on failure.

Abort the current operation.

Returns:
true on success, or false on failure.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1TimedDB_1_1Visitor.html0000644000175000017500000003556311757471600024746 0ustar mikiomikio Kyoto Tycoon: kyototycoon::TimedDB::Visitor Class Reference
kyototycoon::TimedDB::Visitor Class Reference

Interface to access a record. More...

#include <kttimeddb.h>

List of all members.

Public Member Functions

virtual ~Visitor ()
 Destructor.
virtual const char * visit_full (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, size_t *sp, int64_t *xtp)
 Visit a record.
virtual const char * visit_empty (const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp)
 Visit a empty record space.
virtual void visit_before ()
 Preprocess the main operations.
virtual void visit_after ()
 Postprocess the main operations.

Static Public Attributes

static const char *const NOP
 Special pointer for no operation.
static const char *const REMOVE
 Special pointer to remove the record.

Detailed Description

Interface to access a record.


Constructor & Destructor Documentation

Destructor.


Member Function Documentation

virtual const char* kyototycoon::TimedDB::Visitor::visit_full ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz,
size_t *  sp,
int64_t *  xtp 
) [virtual]

Visit a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
spthe pointer to the variable into which the size of the region of the return value is assigned.
xtpthe pointer to the variable into which the expiration time from now in seconds is assigned. The initial value is the absolute expiration time.
Returns:
If it is the pointer to a region, the value is replaced by the content. If it is Visitor::NOP, nothing is modified. If it is Visitor::REMOVE, the record is removed.
virtual const char* kyototycoon::TimedDB::Visitor::visit_empty ( const char *  kbuf,
size_t  ksiz,
size_t *  sp,
int64_t *  xtp 
) [virtual]

Visit a empty record space.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
spthe pointer to the variable into which the size of the region of the return value is assigned.
xtpthe pointer to the variable into which the expiration time from now in seconds is assigned.
Returns:
If it is the pointer to a region, the value is replaced by the content. If it is Visitor::NOP or Visitor::REMOVE, nothing is modified.
virtual void kyototycoon::TimedDB::Visitor::visit_before ( ) [virtual]

Preprocess the main operations.

virtual void kyototycoon::TimedDB::Visitor::visit_after ( ) [virtual]

Postprocess the main operations.


Member Data Documentation

const char* const kyototycoon::TimedDB::Visitor::NOP [static]

Special pointer for no operation.

const char* const kyototycoon::TimedDB::Visitor::REMOVE [static]

Special pointer to remove the record.

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1ThreadedServer_1_1Session_1_1Data.html0000644000175000017500000001125511757471600027613 0ustar mikiomikio Kyoto Tycoon: kyototycoon::ThreadedServer::Session::Data Class Reference
kyototycoon::ThreadedServer::Session::Data Class Reference

Interface of session local data. More...

#include <ktthserv.h>

List of all members.

Public Member Functions

virtual ~Data ()
 Destructor.

Detailed Description

Interface of session local data.


Constructor & Destructor Documentation

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCServer.html0000644000175000017500000005541411757471600023266 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RPCServer Class Reference
kyototycoon::RPCServer Class Reference

RPC server. More...

#include <ktrpc.h>

List of all members.

Classes

class  Logger
 Interface to log internal information and errors. More...
class  Session
 Interface to log internal information and errors. More...
class  Worker
 Interface to process each request. More...
class  WorkerAdapter
 Adapter for the worker.

Public Member Functions

 RPCServer ()
 Default constructor.
 ~RPCServer ()
 Destructor.
void set_network (const std::string &expr, double timeout=-1)
 Set the network configurations.
void set_logger (Logger *logger, uint32_t kinds=Logger::SYSTEM|Logger::ERROR)
 Set the logger to process each log message.
void set_worker (Worker *worker, size_t thnum=1)
 Set the worker to process each request.
bool start ()
 Start the service.
bool stop ()
 Stop the service.
bool finish ()
 Finish the service.
void log (Logger::Kind kind, const char *format,...)
 Log a message.
void log_v (Logger::Kind kind, const char *format, va_list ap)
 Log a message.
HTTPServerreveal_core ()
 Reveal the internal HTTP server.

Detailed Description

RPC server.


Constructor & Destructor Documentation

Default constructor.


Member Function Documentation

void kyototycoon::RPCServer::set_network ( const std::string &  expr,
double  timeout = -1 
)

Set the network configurations.

Parameters:
expran expression of the address and the port of the server.
timeoutthe timeout of each network operation in seconds. If it is not more than 0, no timeout is specified.
void kyototycoon::RPCServer::set_logger ( Logger logger,
uint32_t  kinds = Logger::SYSTEM | Logger::ERROR 
)

Set the logger to process each log message.

Parameters:
loggerthe logger object.
kindskinds of logged messages by bitwise-or: Logger::DEBUG for debugging, Logger::INFO for normal information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error.
void kyototycoon::RPCServer::set_worker ( Worker worker,
size_t  thnum = 1 
)

Set the worker to process each request.

Parameters:
workerthe worker object.
thnumthe number of worker threads.

Start the service.

Returns:
true on success, or false on failure.
Note:
This function blocks until the server stops by the RPCServer::stop method.

Stop the service.

Returns:
true on success, or false on failure.

Finish the service.

Returns:
true on success, or false on failure.
void kyototycoon::RPCServer::log ( Logger::Kind  kind,
const char *  format,
  ... 
)

Log a message.

Parameters:
kindthe kind of the event. Logger::DEBUG for debugging, Logger::INFO for normal information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error.
formatthe printf-like format string. The conversion character `' can be used with such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `'.
...used according to the format string.
void kyototycoon::RPCServer::log_v ( Logger::Kind  kind,
const char *  format,
va_list  ap 
)

Log a message.

Note:
Equal to the original Cursor::set_value method except that the last parameters is va_list.

Reveal the internal HTTP server.

Returns:
the internal HTTP server.
kyototycoon-0.9.56/doc/api/functions_0x7e.html0000644000175000017500000002171211757471600020310 0ustar mikiomikio Kyoto Tycoon: Class Members kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RemoteDB_1_1Error.html0000644000175000017500000005737211757471600024573 0ustar mikiomikio Kyoto Tycoon: kyototycoon::RemoteDB::Error Class Reference
kyototycoon::RemoteDB::Error Class Reference

Error data. More...

#include <ktremotedb.h>

List of all members.

Public Types

enum  Code {
  SUCCESS = RPCClient::RVSUCCESS, NOIMPL = RPCClient::RVENOIMPL, INVALID = RPCClient::RVEINVALID, LOGIC = RPCClient::RVELOGIC,
  TIMEOUT = RPCClient::RVETIMEOUT, INTERNAL = RPCClient::RVEINTERNAL, NETWORK = RPCClient::RVENETWORK, EMISC = RPCClient::RVEMISC
}
 Error codes. More...

Public Member Functions

 Error ()
 Default constructor.
 Error (const Error &src)
 Copy constructor.
 Error (Code code, const std::string &message)
 Constructor.
 ~Error ()
 Destructor.
void set (Code code, const std::string &message)
 Set the error information.
Code code () const
 Get the error code.
const char * name () const
 Get the readable string of the code.
const char * message () const
 Get the supplement message.
Erroroperator= (const Error &right)
 Assignment operator from the self type.
 operator int32_t () const
 Cast operator to integer.

Static Public Member Functions

static const char * codename (Code code)
 Get the readable string of an error code.

Detailed Description

Error data.


Member Enumeration Documentation

Error codes.

Enumerator:
SUCCESS 

success

NOIMPL 

not implemented

INVALID 

invalid operation

LOGIC 

logical inconsistency

TIMEOUT 

timeout

INTERNAL 

internal error

NETWORK 

network error

EMISC 

miscellaneous error


Constructor & Destructor Documentation

Default constructor.

Copy constructor.

Parameters:
srcthe source object.
kyototycoon::RemoteDB::Error::Error ( Code  code,
const std::string &  message 
) [explicit]

Constructor.

Parameters:
codean error code.
messagea supplement message.

Member Function Documentation

void kyototycoon::RemoteDB::Error::set ( Code  code,
const std::string &  message 
)

Set the error information.

Parameters:
codean error code.
messagea supplement message.

Get the error code.

Returns:
the error code.
const char* kyototycoon::RemoteDB::Error::name ( ) const

Get the readable string of the code.

Returns:
the readable string of the code.

Get the supplement message.

Returns:
the supplement message.
static const char* kyototycoon::RemoteDB::Error::codename ( Code  code) [static]

Get the readable string of an error code.

Parameters:
codethe error code.
Returns:
the readable string of the error code.
Error& kyototycoon::RemoteDB::Error::operator= ( const Error right)

Assignment operator from the self type.

Parameters:
rightthe right operand.
Returns:
the reference to itself.
kyototycoon::RemoteDB::Error::operator int32_t ( ) const

Cast operator to integer.

Returns:
the error code.
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1TimedDB.html0000644000175000017500000044654511757471600022734 0ustar mikiomikio Kyoto Tycoon: kyototycoon::TimedDB Class Reference

Timed database. More...

#include <kttimeddb.h>

List of all members.

Classes

class  Cursor
 Cursor to indicate a record. More...
struct  MergeLine
 Front line of a merging list.
class  TimedMetaTrigger
 Trigger of meta database operations.
class  TimedVisitor
 Visitor to handle records with time stamps.
class  UpdateTrigger
 Interface to trigger update operations. More...
class  Visitor
 Interface to access a record. More...

Public Types

enum  MergeMode { MSET, MADD, MREPLACE, MAPPEND }
 Merge modes. More...

Public Member Functions

 TimedDB ()
 Default constructor.
virtual ~TimedDB ()
 Destructor.
bool set_internal_db (kc::BasicDB *db)
 Set the internal database object.
kc::BasicDB::Error error () const
 Get the last happened error.
void set_error (kc::BasicDB::Error::Code code, const char *message)
 Set the error information.
bool open (const std::string &path=":", uint32_t mode=kc::BasicDB::OWRITER|kc::BasicDB::OCREATE)
 Open a database file.
bool close ()
 Close the database file.
bool accept (const char *kbuf, size_t ksiz, Visitor *visitor, bool writable=true)
 Accept a visitor to a record.
bool accept_bulk (const std::vector< std::string > &keys, Visitor *visitor, bool writable=true)
 Accept a visitor to multiple records at once.
bool iterate (Visitor *visitor, bool writable=true, kc::BasicDB::ProgressChecker *checker=NULL)
 Iterate to accept a visitor for each record.
bool scan_parallel (Visitor *visitor, size_t thnum, kc::BasicDB::ProgressChecker *checker=NULL)
 Scan each record in parallel.
bool synchronize (bool hard=false, kc::BasicDB::FileProcessor *proc=NULL, kc::BasicDB::ProgressChecker *checker=NULL)
 Synchronize updated contents with the file and the device.
bool occupy (bool writable=true, kc::BasicDB::FileProcessor *proc=NULL)
 Occupy database by locking and do something meanwhile.
bool copy (const std::string &dest, kc::BasicDB::ProgressChecker *checker=NULL)
 Create a copy of the database file.
bool begin_transaction (bool hard=false)
 Begin transaction.
bool begin_transaction_try (bool hard=false)
 Try to begin transaction.
bool end_transaction (bool commit=true)
 End transaction.
bool clear ()
 Remove all records.
int64_t count ()
 Get the number of records.
int64_t size ()
 Get the size of the database file.
std::string path ()
 Get the path of the database file.
bool status (std::map< std::string, std::string > *strmap)
 Get the miscellaneous status information.
bool set (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)
 Set the value of a record.
bool set (const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)
 Set the value of a record.
bool add (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)
 Add a record.
bool add (const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)
 Set the value of a record.
bool replace (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)
 Replace the value of a record.
bool replace (const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)
 Replace the value of a record.
bool append (const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)
 Append the value of a record.
bool append (const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)
 Set the value of a record.
int64_t increment (const char *kbuf, size_t ksiz, int64_t num, int64_t orig=0, int64_t xt=kc::INT64MAX)
 Add a number to the numeric integer value of a record.
int64_t increment (const std::string &key, int64_t num, int64_t orig=0, int64_t xt=kc::INT64MAX)
 Add a number to the numeric integer value of a record.
double increment_double (const char *kbuf, size_t ksiz, double num, double orig=0, int64_t xt=kc::INT64MAX)
 Add a number to the numeric double value of a record.
double increment_double (const std::string &key, double num, double orig=0, int64_t xt=kc::INT64MAX)
 Add a number to the numeric double value of a record.
bool cas (const char *kbuf, size_t ksiz, const char *ovbuf, size_t ovsiz, const char *nvbuf, size_t nvsiz, int64_t xt=kc::INT64MAX)
 Perform compare-and-swap.
bool cas (const std::string &key, const std::string &ovalue, const std::string &nvalue, int64_t xt=kc::INT64MAX)
 Perform compare-and-swap.
bool remove (const char *kbuf, size_t ksiz)
 Remove a record.
bool remove (const std::string &key)
 Remove a record.
char * get (const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp=NULL)
 Retrieve the value of a record.
bool get (const std::string &key, std::string *value, int64_t *xtp=NULL)
 Retrieve the value of a record.
int32_t get (const char *kbuf, size_t ksiz, char *vbuf, size_t max, int64_t *xtp=NULL)
 Retrieve the value of a record.
int32_t check (const char *kbuf, size_t ksiz, int64_t *xtp=NULL)
 Check the existence of a record.
int32_t check (const std::string &key, int64_t *xtp=NULL)
 Check the existence of a record.
char * seize (const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp=NULL)
 Retrieve the value of a record and remove it atomically.
bool seize (const std::string &key, std::string *value, int64_t *xtp=NULL)
 Retrieve the value of a record and remove it atomically.
int64_t set_bulk (const std::map< std::string, std::string > &recs, int64_t xt=kc::INT64MAX, bool atomic=true)
 Store records at once.
int64_t remove_bulk (const std::vector< std::string > &keys, bool atomic=true)
 Remove records at once.
int64_t get_bulk (const std::vector< std::string > &keys, std::map< std::string, std::string > *recs, bool atomic=true)
 Retrieve records at once.
bool dump_snapshot (std::ostream *dest, kc::BasicDB::ProgressChecker *checker=NULL)
 Dump records into a data stream.
bool dump_snapshot (const std::string &dest, kc::BasicDB::ProgressChecker *checker=NULL)
 Dump records into a file.
bool load_snapshot (std::istream *src, kc::BasicDB::ProgressChecker *checker=NULL)
 Load records from a data stream.
bool load_snapshot (const std::string &src, kc::BasicDB::ProgressChecker *checker=NULL)
 Load records from a file.
bool dump_snapshot_atomic (const std::string &dest, kc::Compressor *zcomp=NULL, kc::BasicDB::ProgressChecker *checker=NULL)
 Dump records atomically into a file.
bool load_snapshot_atomic (const std::string &src, kc::Compressor *zcomp=NULL, kc::BasicDB::ProgressChecker *checker=NULL)
 Load records atomically from a file.
kc::BasicDB * reveal_inner_db ()
 Reveal the inner database object.
bool vacuum (int64_t step=0)
 Scan the database and eliminate regions of expired records.
bool recover (const char *mbuf, size_t msiz)
 Recover the database with an update log message.
int64_t match_prefix (const std::string &prefix, std::vector< std::string > *strvec, int64_t max=-1, kc::BasicDB::ProgressChecker *checker=NULL)
 Get keys matching a prefix string.
int64_t match_regex (const std::string &regex, std::vector< std::string > *strvec, int64_t max=-1, kc::BasicDB::ProgressChecker *checker=NULL)
 Get keys matching a regular expression string.
int64_t match_similar (const std::string &origin, size_t range, bool utf, std::vector< std::string > *strvec, int64_t max=-1, kc::BasicDB::ProgressChecker *checker=NULL)
 Get keys similar to a string in terms of the levenshtein distance.
bool merge (TimedDB **srcary, size_t srcnum, MergeMode mode=MSET, kc::BasicDB::ProgressChecker *checker=NULL)
 Merge records from other databases.
Cursorcursor ()
 Create a cursor object.
bool tune_logger (kc::BasicDB::Logger *logger, uint32_t kinds=kc::BasicDB::Logger::WARN|kc::BasicDB::Logger::ERROR)
 Set the internal logger.
bool tune_update_trigger (UpdateTrigger *trigger)
 Set the internal update trigger.

Static Public Member Functions

static bool tokenize_update_log (const char *mbuf, size_t msiz, std::vector< std::string > *tokens)
 Tokenize an update log message.
static bool status_snapshot_atomic (const std::string &src, uint64_t *tsp=NULL, int64_t *cntp=NULL, int64_t *sizp=NULL)
 Get status of an atomic snapshot file.

Static Public Attributes

static const int32_t XTWIDTH = 5
 The width of expiration time.
static const int64_t XTMAX = (1LL << (XTWIDTH * 8)) - 1
 The maximum number of expiration time.

Detailed Description

Timed database.

Note:
This class is a concrete class of a wrapper for the polymorphic database to add expiration features. This class can be inherited but overwriting methods is forbidden. Before every database operation, it is necessary to call the TimedDB::open method in order to open a database file and connect the database object to it. To avoid data missing or corruption, it is important to close every database file by the TimedDB::close method when the database is no longer in use. It is forbidden for multible database objects in a process to open the same database at the same time.

Member Enumeration Documentation

Merge modes.

Enumerator:
MSET 

overwrite the existing value

MADD 

keep the existing value

MREPLACE 

modify the existing record only

MAPPEND 

append the new value


Constructor & Destructor Documentation

Default constructor.

virtual kyototycoon::TimedDB::~TimedDB ( ) [virtual]

Destructor.


Member Function Documentation

bool kyototycoon::TimedDB::set_internal_db ( kc::BasicDB *  db)

Set the internal database object.

Parameters:
dbthe internal database object. Its possession is transferred inside and the object is deleted automatically.
Returns:
true on success, or false on failure.
kc::BasicDB::Error kyototycoon::TimedDB::error ( ) const

Get the last happened error.

Returns:
the last happened error.
void kyototycoon::TimedDB::set_error ( kc::BasicDB::Error::Code  code,
const char *  message 
)

Set the error information.

Parameters:
codean error code.
messagea supplement message.
bool kyototycoon::TimedDB::open ( const std::string &  path = ":",
uint32_t  mode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE 
)

Open a database file.

Parameters:
paththe path of a database file. The same as with kc::PolyDB. In addition, the following tuning parameters are supported. "ktopts" sets options and the value can contain "p" for the persistent option. "ktcapcnt" sets the capacity by record number. "ktcapsiz" sets the capacity by database size.
modethe connection mode. The same as with kc::PolyDB.
Returns:
true on success, or false on failure.

Close the database file.

Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::accept ( const char *  kbuf,
size_t  ksiz,
Visitor visitor,
bool  writable = true 
)

Accept a visitor to a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
visitora visitor object.
writabletrue for writable operation, or false for read-only operation.
Returns:
true on success, or false on failure.
Note:
the operation for each record is performed atomically and other threads accessing the same record are blocked.
bool kyototycoon::TimedDB::accept_bulk ( const std::vector< std::string > &  keys,
Visitor visitor,
bool  writable = true 
)

Accept a visitor to multiple records at once.

Parameters:
keysspecifies a string vector of the keys.
visitora visitor object.
writabletrue for writable operation, or false for read-only operation.
Returns:
true on success, or false on failure.
Note:
The operations for specified records are performed atomically and other threads accessing the same records are blocked. To avoid deadlock, any database operation must not be performed in this function.
bool kyototycoon::TimedDB::iterate ( Visitor visitor,
bool  writable = true,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Iterate to accept a visitor for each record.

Parameters:
visitora visitor object.
writabletrue for writable operation, or false for read-only operation.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.
Note:
The whole iteration is performed atomically and other threads are blocked.
bool kyototycoon::TimedDB::scan_parallel ( Visitor visitor,
size_t  thnum,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Scan each record in parallel.

Parameters:
visitora visitor object.
thnumthe number of worker threads.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.
Note:
This function is for reading records and not for updating ones. The return value of the visitor is just ignored. To avoid deadlock, any explicit database operation must not be performed in this function.
bool kyototycoon::TimedDB::synchronize ( bool  hard = false,
kc::BasicDB::FileProcessor *  proc = NULL,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Synchronize updated contents with the file and the device.

Parameters:
hardtrue for physical synchronization with the device, or false for logical synchronization with the file system.
proca postprocessor object. If it is NULL, no postprocessing is performed.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.
Note:
The operation of the postprocessor is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this function.
bool kyototycoon::TimedDB::occupy ( bool  writable = true,
kc::BasicDB::FileProcessor *  proc = NULL 
)

Occupy database by locking and do something meanwhile.

Parameters:
writabletrue to use writer lock, or false to use reader lock.
proca processor object. If it is NULL, no processing is performed.
Returns:
true on success, or false on failure.
Note:
The operation of the processor is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this function.
bool kyototycoon::TimedDB::copy ( const std::string &  dest,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Create a copy of the database file.

Parameters:
destthe path of the destination file.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::begin_transaction ( bool  hard = false)

Begin transaction.

Parameters:
hardtrue for physical synchronization with the device, or false for logical synchronization with the file system.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::begin_transaction_try ( bool  hard = false)

Try to begin transaction.

Parameters:
hardtrue for physical synchronization with the device, or false for logical synchronization with the file system.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::end_transaction ( bool  commit = true)

End transaction.

Parameters:
committrue to commit the transaction, or false to abort the transaction.
Returns:
true on success, or false on failure.

Remove all records.

Returns:
true on success, or false on failure.

Get the number of records.

Returns:
the number of records, or -1 on failure.

Get the size of the database file.

Returns:
the size of the database file in bytes, or -1 on failure.
std::string kyototycoon::TimedDB::path ( )

Get the path of the database file.

Returns:
the path of the database file, or an empty string on failure.
bool kyototycoon::TimedDB::status ( std::map< std::string, std::string > *  strmap)

Get the miscellaneous status information.

Parameters:
strmapa string map to contain the result.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::set ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX 
)

Set the value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, a new record is created. If the corresponding record exists, the value is overwritten.
bool kyototycoon::TimedDB::set ( const std::string &  key,
const std::string &  value,
int64_t  xt = kc::INT64MAX 
)

Set the value of a record.

Note:
Equal to the original DB::set method except that the parameters are std::string.
bool kyototycoon::TimedDB::add ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX 
)

Add a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, a new record is created. If the corresponding record exists, the record is not modified and false is returned.
bool kyototycoon::TimedDB::add ( const std::string &  key,
const std::string &  value,
int64_t  xt = kc::INT64MAX 
)

Set the value of a record.

Note:
Equal to the original DB::add method except that the parameters are std::string.
bool kyototycoon::TimedDB::replace ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX 
)

Replace the value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, no new record is created and false is returned. If the corresponding record exists, the value is modified.
bool kyototycoon::TimedDB::replace ( const std::string &  key,
const std::string &  value,
int64_t  xt = kc::INT64MAX 
)

Replace the value of a record.

Note:
Equal to the original DB::replace method except that the parameters are std::string.
bool kyototycoon::TimedDB::append ( const char *  kbuf,
size_t  ksiz,
const char *  vbuf,
size_t  vsiz,
int64_t  xt = kc::INT64MAX 
)

Append the value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the value region.
vsizthe size of the value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, a new record is created. If the corresponding record exists, the given value is appended at the end of the existing value.
bool kyototycoon::TimedDB::append ( const std::string &  key,
const std::string &  value,
int64_t  xt = kc::INT64MAX 
)

Set the value of a record.

Note:
Equal to the original DB::append method except that the parameters are std::string.
int64_t kyototycoon::TimedDB::increment ( const char *  kbuf,
size_t  ksiz,
int64_t  num,
int64_t  orig = 0,
int64_t  xt = kc::INT64MAX 
)

Add a number to the numeric integer value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
numthe additional number.
origthe origin number if no record corresponds to the key. If it is INT64MIN and no record corresponds, this function fails. If it is INT64MAX, the value is set as the additional number regardless of the current value.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
the result value, or kyotocabinet::INT64MIN on failure.
Note:
The value is serialized as an 8-byte binary integer in big-endian order, not a decimal string. If existing value is not 8-byte, this function fails.
int64_t kyototycoon::TimedDB::increment ( const std::string &  key,
int64_t  num,
int64_t  orig = 0,
int64_t  xt = kc::INT64MAX 
)

Add a number to the numeric integer value of a record.

Note:
Equal to the original DB::increment method except that the parameter is std::string.
double kyototycoon::TimedDB::increment_double ( const char *  kbuf,
size_t  ksiz,
double  num,
double  orig = 0,
int64_t  xt = kc::INT64MAX 
)

Add a number to the numeric double value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
numthe additional number.
origthe origin number if no record corresponds to the key. If it is negative infinity and no record corresponds, this function fails. If it is positive infinity, the value is set as the additional number regardless of the current value.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
the result value, or Not-a-number on failure.
Note:
The value is serialized as an 16-byte binary fixed-point number in big-endian order, not a decimal string. If existing value is not 16-byte, this function fails.
double kyototycoon::TimedDB::increment_double ( const std::string &  key,
double  num,
double  orig = 0,
int64_t  xt = kc::INT64MAX 
)

Add a number to the numeric double value of a record.

Note:
Equal to the original DB::increment_double method except that the parameter is std::string.
bool kyototycoon::TimedDB::cas ( const char *  kbuf,
size_t  ksiz,
const char *  ovbuf,
size_t  ovsiz,
const char *  nvbuf,
size_t  nvsiz,
int64_t  xt = kc::INT64MAX 
)

Perform compare-and-swap.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
ovbufthe pointer to the old value region. NULL means that no record corresponds.
ovsizthe size of the old value region.
nvbufthe pointer to the new value region. NULL means that the record is removed.
nvsizthe size of new old value region.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::cas ( const std::string &  key,
const std::string &  ovalue,
const std::string &  nvalue,
int64_t  xt = kc::INT64MAX 
)

Perform compare-and-swap.

Note:
Equal to the original DB::cas method except that the parameters are std::string.
bool kyototycoon::TimedDB::remove ( const char *  kbuf,
size_t  ksiz 
)

Remove a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
Returns:
true on success, or false on failure.
Note:
If no record corresponds to the key, false is returned.
bool kyototycoon::TimedDB::remove ( const std::string &  key)

Remove a record.

Note:
Equal to the original DB::remove method except that the parameter is std::string.
char* kyototycoon::TimedDB::get ( const char *  kbuf,
size_t  ksiz,
size_t *  sp,
int64_t *  xtp = NULL 
)

Retrieve the value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
spthe pointer to the variable into which the size of the region of the return value is assigned.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
Returns:
the pointer to the value region of the corresponding record, or NULL on failure.
Note:
If no record corresponds to the key, NULL is returned. Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a C-style string. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
bool kyototycoon::TimedDB::get ( const std::string &  key,
std::string *  value,
int64_t *  xtp = NULL 
)

Retrieve the value of a record.

Note:
Equal to the original DB::get method except that the first parameters is the key string and the second parameter is a string to contain the result and the return value is bool for success.
int32_t kyototycoon::TimedDB::get ( const char *  kbuf,
size_t  ksiz,
char *  vbuf,
size_t  max,
int64_t *  xtp = NULL 
)

Retrieve the value of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
vbufthe pointer to the buffer into which the value of the corresponding record is written.
maxthe size of the buffer.
xtpthe pointer to the variable into which the expiration time from now in seconds is assigned. If it is NULL, it is ignored.
Returns:
the size of the value, or -1 on failure.
int32_t kyototycoon::TimedDB::check ( const char *  kbuf,
size_t  ksiz,
int64_t *  xtp = NULL 
)

Check the existence of a record.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
Returns:
the size of the value, or -1 on failure.
int32_t kyototycoon::TimedDB::check ( const std::string &  key,
int64_t *  xtp = NULL 
)

Check the existence of a record.

Note:
Equal to the original DB::check method except that the first parameters is the key string.
char* kyototycoon::TimedDB::seize ( const char *  kbuf,
size_t  ksiz,
size_t *  sp,
int64_t *  xtp = NULL 
)

Retrieve the value of a record and remove it atomically.

Parameters:
kbufthe pointer to the key region.
ksizthe size of the key region.
spthe pointer to the variable into which the size of the region of the return value is assigned.
xtpthe pointer to the variable into which the absolute expiration time is assigned. If it is NULL, it is ignored.
Returns:
the pointer to the value region of the corresponding record, or NULL on failure.
Note:
If no record corresponds to the key, NULL is returned. Because an additional zero code is appended at the end of the region of the return value, the return value can be treated as a C-style string. Because the region of the return value is allocated with the the new[] operator, it should be released with the delete[] operator when it is no longer in use.
bool kyototycoon::TimedDB::seize ( const std::string &  key,
std::string *  value,
int64_t *  xtp = NULL 
)

Retrieve the value of a record and remove it atomically.

Note:
Equal to the original DB::get method except that the first parameters is the key string and the second parameter is a string to contain the result and the return value is bool for success.
int64_t kyototycoon::TimedDB::set_bulk ( const std::map< std::string, std::string > &  recs,
int64_t  xt = kc::INT64MAX,
bool  atomic = true 
)

Store records at once.

Parameters:
recsthe records to store.
xtthe expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time.
atomictrue to perform all operations atomically, or false for non-atomic operations.
Returns:
the number of stored records, or -1 on failure.
int64_t kyototycoon::TimedDB::remove_bulk ( const std::vector< std::string > &  keys,
bool  atomic = true 
)

Remove records at once.

Parameters:
keysthe keys of the records to remove.
atomictrue to perform all operations atomically, or false for non-atomic operations.
Returns:
the number of removed records, or -1 on failure.
int64_t kyototycoon::TimedDB::get_bulk ( const std::vector< std::string > &  keys,
std::map< std::string, std::string > *  recs,
bool  atomic = true 
)

Retrieve records at once.

Parameters:
keysthe keys of the records to retrieve.
recsa string map to contain the retrieved records.
atomictrue to perform all operations atomically, or false for non-atomic operations.
Returns:
the number of retrieved records, or -1 on failure.
bool kyototycoon::TimedDB::dump_snapshot ( std::ostream *  dest,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Dump records into a data stream.

Parameters:
destthe destination stream.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::dump_snapshot ( const std::string &  dest,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Dump records into a file.

Parameters:
destthe path of the destination file.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::load_snapshot ( std::istream *  src,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Load records from a data stream.

Parameters:
srcthe source stream.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::load_snapshot ( const std::string &  src,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Load records from a file.

Parameters:
srcthe path of the source file.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::dump_snapshot_atomic ( const std::string &  dest,
kc::Compressor *  zcomp = NULL,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Dump records atomically into a file.

Parameters:
destthe path of the destination file.
zcompthe data compressor object. If it is NULL, no compression is performed.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::load_snapshot_atomic ( const std::string &  src,
kc::Compressor *  zcomp = NULL,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Load records atomically from a file.

Parameters:
srcthe path of the source file.
zcompthe data compressor object. If it is NULL, no decompression is performed.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.

Reveal the inner database object.

Returns:
the inner database object, or NULL on failure.
bool kyototycoon::TimedDB::vacuum ( int64_t  step = 0)

Scan the database and eliminate regions of expired records.

Parameters:
stepthe number of steps. If it is not more than 0, the whole region is scanned.
Returns:
true on success, or false on failure.
bool kyototycoon::TimedDB::recover ( const char *  mbuf,
size_t  msiz 
)

Recover the database with an update log message.

Parameters:
mbufthe pointer to the message region.
msizthe size of the message region.
Returns:
true on success, or false on failure.
int64_t kyototycoon::TimedDB::match_prefix ( const std::string &  prefix,
std::vector< std::string > *  strvec,
int64_t  max = -1,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Get keys matching a prefix string.

Parameters:
prefixthe prefix string.
strveca string vector to contain the result.
maxthe maximum number to retrieve. If it is negative, no limit is specified.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
the number of retrieved keys or -1 on failure.
int64_t kyototycoon::TimedDB::match_regex ( const std::string &  regex,
std::vector< std::string > *  strvec,
int64_t  max = -1,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Get keys matching a regular expression string.

Parameters:
regexthe regular expression string.
strveca string vector to contain the result.
maxthe maximum number to retrieve. If it is negative, no limit is specified.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
the number of retrieved keys or -1 on failure.
int64_t kyototycoon::TimedDB::match_similar ( const std::string &  origin,
size_t  range,
bool  utf,
std::vector< std::string > *  strvec,
int64_t  max = -1,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Get keys similar to a string in terms of the levenshtein distance.

Parameters:
originthe origin string.
rangethe maximum distance of keys to adopt.
utfflag to treat keys as UTF-8 strings.
strveca string vector to contain the result.
maxthe maximum number to retrieve. If it is negative, no limit is specified.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
the number of retrieved keys or -1 on failure.
bool kyototycoon::TimedDB::merge ( TimedDB **  srcary,
size_t  srcnum,
MergeMode  mode = MSET,
kc::BasicDB::ProgressChecker *  checker = NULL 
)

Merge records from other databases.

Parameters:
srcaryan array of the source detabase objects.
srcnumthe number of the elements of the source array.
modethe merge mode. TimedDB::MSET to overwrite the existing value, TimedDB::MADD to keep the existing value, TimedDB::MREPLACE to modify the existing record only, TimedDB::MAPPEND to append the new value.
checkera progress checker object. If it is NULL, no checking is performed.
Returns:
true on success, or false on failure.

Create a cursor object.

Returns:
the return value is the created cursor object.
Note:
Because the object of the return value is allocated by the constructor, it should be released with the delete operator when it is no longer in use.
bool kyototycoon::TimedDB::tune_logger ( kc::BasicDB::Logger *  logger,
uint32_t  kinds = kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR 
)

Set the internal logger.

Parameters:
loggerthe logger object. The same as with kc::BasicDB.
kindskinds of logged messages by bitwise-or: The same as with kc::BasicDB.
Returns:
true on success, or false on failure.

Set the internal update trigger.

Parameters:
triggerthe trigger object.
Returns:
true on success, or false on failure.
static bool kyototycoon::TimedDB::tokenize_update_log ( const char *  mbuf,
size_t  msiz,
std::vector< std::string > *  tokens 
) [static]

Tokenize an update log message.

Parameters:
mbufthe pointer to the message region.
msizthe size of the message region.
tokensa string vector to contain the result.
Returns:
true on success, or false on failure.
static bool kyototycoon::TimedDB::status_snapshot_atomic ( const std::string &  src,
uint64_t *  tsp = NULL,
int64_t *  cntp = NULL,
int64_t *  sizp = NULL 
) [static]

Get status of an atomic snapshot file.

Parameters:
srcthe path of the source file.
tspthe pointer to the variable into which the time stamp of the snapshot data is assigned. If it is NULL, it is ignored.
cntpthe pointer to the variable into which the number of records in the original database is assigned. If it is NULL, it is ignored.
sizpthe pointer to the variable into which the size of the original database is assigned. If it is NULL, it is ignored.
Returns:
true on success, or false on failure.

Member Data Documentation

const int32_t kyototycoon::TimedDB::XTWIDTH = 5 [static]

The width of expiration time.

const int64_t kyototycoon::TimedDB::XTMAX = (1LL << (XTWIDTH * 8)) - 1 [static]

The maximum number of expiration time.

kyototycoon-0.9.56/doc/api/classkyototycoon_1_1RPCClient-members.html0000644000175000017500000001535611757471600024667 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::RPCClient Member List
This is the complete list of members for kyototycoon::RPCClient, including all inherited members.
call(const std::string &name, const std::map< std::string, std::string > *inmap=NULL, std::map< std::string, std::string > *outmap=NULL)kyototycoon::RPCClient
close(bool grace=true)kyototycoon::RPCClient
expression()kyototycoon::RPCClient
open(const std::string &host="", int32_t port=DEFPORT, double timeout=-1)kyototycoon::RPCClient
ReturnValue enum namekyototycoon::RPCClient
reveal_core()kyototycoon::RPCClient
RPCClient()kyototycoon::RPCClient
RVEINTERNAL enum valuekyototycoon::RPCClient
RVEINVALID enum valuekyototycoon::RPCClient
RVELOGIC enum valuekyototycoon::RPCClient
RVEMISC enum valuekyototycoon::RPCClient
RVENETWORK enum valuekyototycoon::RPCClient
RVENOIMPL enum valuekyototycoon::RPCClient
RVETIMEOUT enum valuekyototycoon::RPCClient
RVSUCCESS enum valuekyototycoon::RPCClient
~RPCClient()kyototycoon::RPCClient
kyototycoon-0.9.56/doc/api/classkyototycoon_1_1SharedLibrary.html0000644000175000017500000002136511757471600024204 0ustar mikiomikio Kyoto Tycoon: kyototycoon::SharedLibrary Class Reference
kyototycoon::SharedLibrary Class Reference

Shared library. More...

#include <ktshlib.h>

List of all members.

Public Member Functions

 SharedLibrary ()
 Default constructor.
 ~SharedLibrary ()
 Destructor.
bool open (const char *path)
 Open a shared library.
bool close ()
 Close the shared library.
void * symbol (const char *name)
 Get the pointer to a symbol.

Detailed Description

Shared library.


Constructor & Destructor Documentation


Member Function Documentation

bool kyototycoon::SharedLibrary::open ( const char *  path)

Open a shared library.

Parameters:
paththe path of the shared library file.
Returns:
true on success, or false on failure.

Close the shared library.

Returns:
true on success, or false on failure.
void* kyototycoon::SharedLibrary::symbol ( const char *  name)

Get the pointer to a symbol.

Parameters:
namethe name of the symbol.
Returns:
the pointer to the symbol, or NULL on failure.
kyototycoon-0.9.56/doc/api/kttimeddb_8h.html0000644000175000017500000001300411757471600017776 0ustar mikiomikio Kyoto Tycoon: kttimeddb.h File Reference
kttimeddb.h File Reference

timed database More...

#include <ktcommon.h>
#include <ktutil.h>
#include <ktulog.h>
#include <ktshlib.h>

Classes

class  kyototycoon::TimedDB
 Timed database. More...
class  kyototycoon::TimedDB::Cursor
 Cursor to indicate a record. More...
class  kyototycoon::TimedDB::Visitor
 Interface to access a record. More...
class  kyototycoon::TimedDB::UpdateTrigger
 Interface to trigger update operations. More...
class  kyototycoon::TimedDB::TimedVisitor
 Visitor to handle records with time stamps.
class  kyototycoon::TimedDB::TimedMetaTrigger
 Trigger of meta database operations.
struct  kyototycoon::TimedDB::MergeLine
 Front line of a merging list.

Namespaces

namespace  kyototycoon
 

All symbols of Kyoto Tycoon.



Detailed Description

timed database

kyototycoon-0.9.56/doc/api/functions_func.html0000644000175000017500000001445611757471600020467 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/api/classkyototycoon_1_1TimedDB-members.html0000644000175000017500000005670411757471600024356 0ustar mikiomikio Kyoto Tycoon: Member List
kyototycoon::TimedDB Member List
This is the complete list of members for kyototycoon::TimedDB, including all inherited members.
accept(const char *kbuf, size_t ksiz, Visitor *visitor, bool writable=true)kyototycoon::TimedDB
accept_bulk(const std::vector< std::string > &keys, Visitor *visitor, bool writable=true)kyototycoon::TimedDB
add(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
add(const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
append(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
append(const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
begin_transaction(bool hard=false)kyototycoon::TimedDB
begin_transaction_try(bool hard=false)kyototycoon::TimedDB
cas(const char *kbuf, size_t ksiz, const char *ovbuf, size_t ovsiz, const char *nvbuf, size_t nvsiz, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
cas(const std::string &key, const std::string &ovalue, const std::string &nvalue, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
check(const char *kbuf, size_t ksiz, int64_t *xtp=NULL)kyototycoon::TimedDB
check(const std::string &key, int64_t *xtp=NULL)kyototycoon::TimedDB
clear()kyototycoon::TimedDB
close()kyototycoon::TimedDB
copy(const std::string &dest, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
count()kyototycoon::TimedDB
cursor()kyototycoon::TimedDB
dump_snapshot(std::ostream *dest, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
dump_snapshot(const std::string &dest, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
dump_snapshot_atomic(const std::string &dest, kc::Compressor *zcomp=NULL, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
end_transaction(bool commit=true)kyototycoon::TimedDB
error() const kyototycoon::TimedDB
get(const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp=NULL)kyototycoon::TimedDB
get(const std::string &key, std::string *value, int64_t *xtp=NULL)kyototycoon::TimedDB
get(const char *kbuf, size_t ksiz, char *vbuf, size_t max, int64_t *xtp=NULL)kyototycoon::TimedDB
get_bulk(const std::vector< std::string > &keys, std::map< std::string, std::string > *recs, bool atomic=true)kyototycoon::TimedDB
increment(const char *kbuf, size_t ksiz, int64_t num, int64_t orig=0, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
increment(const std::string &key, int64_t num, int64_t orig=0, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
increment_double(const char *kbuf, size_t ksiz, double num, double orig=0, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
increment_double(const std::string &key, double num, double orig=0, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
iterate(Visitor *visitor, bool writable=true, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
load_snapshot(std::istream *src, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
load_snapshot(const std::string &src, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
load_snapshot_atomic(const std::string &src, kc::Compressor *zcomp=NULL, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
MADD enum valuekyototycoon::TimedDB
MAPPEND enum valuekyototycoon::TimedDB
match_prefix(const std::string &prefix, std::vector< std::string > *strvec, int64_t max=-1, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
match_regex(const std::string &regex, std::vector< std::string > *strvec, int64_t max=-1, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
match_similar(const std::string &origin, size_t range, bool utf, std::vector< std::string > *strvec, int64_t max=-1, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
merge(TimedDB **srcary, size_t srcnum, MergeMode mode=MSET, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
MergeMode enum namekyototycoon::TimedDB
MREPLACE enum valuekyototycoon::TimedDB
MSET enum valuekyototycoon::TimedDB
occupy(bool writable=true, kc::BasicDB::FileProcessor *proc=NULL)kyototycoon::TimedDB
open(const std::string &path=":", uint32_t mode=kc::BasicDB::OWRITER|kc::BasicDB::OCREATE)kyototycoon::TimedDB
path()kyototycoon::TimedDB
recover(const char *mbuf, size_t msiz)kyototycoon::TimedDB
remove(const char *kbuf, size_t ksiz)kyototycoon::TimedDB
remove(const std::string &key)kyototycoon::TimedDB
remove_bulk(const std::vector< std::string > &keys, bool atomic=true)kyototycoon::TimedDB
replace(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
replace(const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
reveal_inner_db()kyototycoon::TimedDB
scan_parallel(Visitor *visitor, size_t thnum, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
seize(const char *kbuf, size_t ksiz, size_t *sp, int64_t *xtp=NULL)kyototycoon::TimedDB
seize(const std::string &key, std::string *value, int64_t *xtp=NULL)kyototycoon::TimedDB
set(const char *kbuf, size_t ksiz, const char *vbuf, size_t vsiz, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
set(const std::string &key, const std::string &value, int64_t xt=kc::INT64MAX)kyototycoon::TimedDB
set_bulk(const std::map< std::string, std::string > &recs, int64_t xt=kc::INT64MAX, bool atomic=true)kyototycoon::TimedDB
set_error(kc::BasicDB::Error::Code code, const char *message)kyototycoon::TimedDB
set_internal_db(kc::BasicDB *db)kyototycoon::TimedDB
size()kyototycoon::TimedDB
status(std::map< std::string, std::string > *strmap)kyototycoon::TimedDB
status_snapshot_atomic(const std::string &src, uint64_t *tsp=NULL, int64_t *cntp=NULL, int64_t *sizp=NULL)kyototycoon::TimedDB [static]
synchronize(bool hard=false, kc::BasicDB::FileProcessor *proc=NULL, kc::BasicDB::ProgressChecker *checker=NULL)kyototycoon::TimedDB
TimedDB()kyototycoon::TimedDB [explicit]
tokenize_update_log(const char *mbuf, size_t msiz, std::vector< std::string > *tokens)kyototycoon::TimedDB [static]
tune_logger(kc::BasicDB::Logger *logger, uint32_t kinds=kc::BasicDB::Logger::WARN|kc::BasicDB::Logger::ERROR)kyototycoon::TimedDB
tune_update_trigger(UpdateTrigger *trigger)kyototycoon::TimedDB
vacuum(int64_t step=0)kyototycoon::TimedDB
XTMAXkyototycoon::TimedDB [static]
XTWIDTHkyototycoon::TimedDB [static]
~TimedDB()kyototycoon::TimedDB [virtual]
kyototycoon-0.9.56/doc/api/tab_b.png0000644000175000017500000000026211757471600016321 0ustar mikiomikio‰PNG  IHDR$ÇÇ[yIDATxíÝÛ Â €Ñ?|SVÓˆ´bB#P®½8³‰O¾:É™D>ßm{SûIí'¹äz(!•TBÞ‰y#¤WìJDp¾ã|Ã…†ó »ìR˜]áá æ™Ð6q·‰›]ç•qŠŒÓÊÕD.&0èÀ =ƒJD”ˆü=@*é*ç×IEND®B`‚kyototycoon-0.9.56/doc/api/functions_func_0x68.html0000644000175000017500000001111111757471600021235 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions
 

- h -

kyototycoon-0.9.56/doc/api/functions_func_0x7e.html0000644000175000017500000002147511757471600021331 0ustar mikiomikio Kyoto Tycoon: Class Members - Functions kyototycoon-0.9.56/doc/luadoc/0000755000175000017500000000000011757471601015243 5ustar mikiomikiokyototycoon-0.9.56/doc/luadoc/luadoc.css0000644000175000017500000001233311757471601017226 0ustar mikiomikiobody { margin-left: 1em; margin-right: 1em; font-family: arial, helvetica, geneva, sans-serif; background-color:#ffffff; margin:0px; } code { font-family: "Andale Mono", monospace; } tt { font-family: "Andale Mono", monospace; } body, td, th { font-size: 11pt; } h1, h2, h3, h4 { margin-left: 0em; } textarea, pre, tt { font-size:10pt; } body, td, th { color:#000000; } small { font-size:0.85em; } h1 { font-size:1.5em; } h2 { font-size:1.25em; } h3 { font-size:1.15em; } h4 { font-size:1.06em; } a:link { font-weight:bold; color: #004080; text-decoration: none; } a:visited { font-weight:bold; color: #006699; text-decoration: none; } a:link:hover { text-decoration:underline; } hr { color:#cccccc } img { border-width: 0px; } h3 { padding-top: 1em; } p { margin-left: 1em; } p.name { font-family: "Andale Mono", monospace; padding-top: 1em; margin-left: 0em; } blockquote { margin-left: 3em; } pre.example { background-color: rgb(245, 245, 245); border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: silver; border-right-color: silver; border-bottom-color: silver; border-left-color: silver; padding: 1em; margin-left: 1em; margin-right: 1em; font-family: "Andale Mono", monospace; font-size: smaller; } hr { margin-left: 0em; background: #00007f; border: 0px; height: 1px; } ul { list-style-type: disc; } table.index { border: 1px #00007f; } table.index td { text-align: left; vertical-align: top; } table.index ul { padding-top: 0em; margin-top: 0em; } table { border: 1px solid black; border-collapse: collapse; margin-left: auto; margin-right: auto; } th { border: 1px solid black; padding: 0.5em; } td { border: 1px solid black; padding: 0.5em; } div.header, div.footer { margin-left: 0em; } #container { margin-left: 1em; margin-right: 1em; background-color: #f0f0f0; } #product { text-align: center; border-bottom: 1px solid #cccccc; background-color: #ffffff; } #product big { font-size: 2em; } #product_logo { } #product_name { } #product_description { } #main { background-color: #f0f0f0; border-left: 2px solid #cccccc; } #navigation { float: left; width: 18em; margin: 0; vertical-align: top; background-color: #f0f0f0; overflow:visible; } #navigation h1 { background-color:#e7e7e7; font-size:1.1em; color:#000000; text-align:left; margin:0px; padding:0.2em; border-top:1px solid #dddddd; border-bottom:1px solid #dddddd; } #navigation ul { font-size:1em; list-style-type: none; padding: 0; margin: 1px; } #navigation li { text-indent: -1em; margin: 0em 0em 0em 0.5em; display: block; padding: 3px 0px 0px 12px; } #navigation li li a { padding: 0px 3px 0px -1em; } #content { margin-left: 18em; padding: 1em; border-left: 2px solid #cccccc; border-right: 2px solid #cccccc; background-color: #ffffff; } #about { clear: both; margin: 0; padding: 5px; border-top: 2px solid #cccccc; background-color: #ffffff; } @media print { body { font: 12pt "Times New Roman", "TimeNR", Times, serif; } a { font-weight:bold; color: #004080; text-decoration: underline; } #main { background-color: #ffffff; border-left: 0px; } #container { margin-left: 2%; margin-right: 2%; background-color: #ffffff; } #content { margin-left: 0px; padding: 1em; border-left: 0px; border-right: 0px; background-color: #ffffff; } #navigation { display: none; } pre.example { font-family: "Andale Mono", monospace; font-size: 10pt; page-break-inside: avoid; } } table.module_list td { border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; } table.module_list td.name { background-color: #f0f0f0; } table.module_list td.summary { width: 100%; } table.file_list { border-width: 1px; border-style: solid; border-color: #cccccc; border-collapse: collapse; } table.file_list td { border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; } table.file_list td.name { background-color: #f0f0f0; } table.file_list td.summary { width: 100%; } table.function_list { border-width: 1px; border-style: solid; border-color: #cccccc; border-collapse: collapse; } table.function_list td { border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; } table.function_list td.name { background-color: #f0f0f0; } table.function_list td.summary { width: 100%; } table.table_list { border-width: 1px; border-style: solid; border-color: #cccccc; border-collapse: collapse; } table.table_list td { border-width: 1px; padding: 3px; border-style: solid; border-color: #cccccc; } table.table_list td.name { background-color: #f0f0f0; } table.table_list td.summary { width: 100%; } dl.function dt {border-top: 1px solid #ccc; padding-top: 1em;} dl.function dd {padding-bottom: 1em;} dl.function h3 {padding: 0; margin: 0; font-size: medium;} dl.table dt {border-top: 1px solid #ccc; padding-top: 1em;} dl.table dd {padding-bottom: 1em;} dl.table h3 {padding: 0; margin: 0; font-size: medium;} table.function_list td.name { width: 20em; } kyototycoon-0.9.56/doc/luadoc/index.html0000644000175000017500000002270411757471601017245 0ustar mikiomikio Kyoto Tycoon

Scripting Extension of Kyoto Tycoon.

This module is imported by the server program (ktserver) of Kyoto Tycoon. The server must be built enabling the scripting extension by Lua.

The start-up command has the option "-scr" to specify a script file defining functions in Lua.

$ ktserver -scr myscript.lua

You can define your own functions in the global name space so that clients can call them by specifying the name of each function. The function name must be composed of ASCII alphabets and numbers because of security reasons. Each function receives two tables as arguments. The first table contains the input data specified by clients. The second table is to contain the output data to send to clients.

In the scripting environment, the global variable "__kyototycoon__" is defined by default. It contains objects to access server resources. The most important one is "__kyototycoon__.db", which is the primary database managed by the server. "__kyototycoon__.dbs" is an array of databases managed by the server. The return value of each function must be "__kyototycoon__.RVSUCCESS" for success or a related code for error.

Because the server uses respective instances of the Lua processor for each native thread, you cannot use global variables to share data among sessions. Use a cache database managed by the server for that purpose.

The following is an example code.

kt = __kyototycoon__
db = kt.db

-- log the start-up message
if kt.thid == 0 then
   kt.log("system", "the Lua script has been loaded")
end

-- echo back the input data as the output data
function echo(inmap, outmap)
   for key, value in pairs(inmap) do
      outmap[key] = value
   end
   return kt.RVSUCCESS
end

-- report the internal state of the server
function report(inmap, outmap)
   outmap["__kyototycoon__.VERSION"] = kt.VERSION
   outmap["__kyototycoon__.thid"] = kt.thid
   outmap["__kyototycoon__.db"] = tostring(kt.db)
   for i = 1, #kt.dbs do
      local key = "__kyototycoon__.dbs[" .. i .. "]"
      outmap[key] = tostring(kt.dbs[i])
   end
   local names = ""
   for name, value in pairs(kt.dbs) do
      if #names > 0 then names = names .. "," end
      names = names .. name
   end
   outmap["names"] = names
   return kt.RVSUCCESS
end

-- log a message
function log(inmap, outmap)
   local kind = inmap.kind
   local message = inmap.message
   if not message then
      return kt.RVEINVALID
   end
   if not kind then
      kind = "info"
   end
   kt.log(kind, message)
   return kt.RVSUCCESS
end

-- store a record
function set(inmap, outmap)
   local key = inmap.key
   local value = inmap.value
   if not key or not value then
      return kt.RVEINVALID
   end
   local xt = inmap.xt
   if not db:set(key, value, xt) then
      return kt.RVEINTERNAL
   end
   return kt.RVSUCCESS
end

-- remove a record
function remove(inmap, outmap)
   local key = inmap.key
   if not key then
      return kt.RVEINVALID
   end
   if not db:remove(key) then
      local err = db:error()
      if err:code() == kt.Error.NOREC then
         return kt.RVELOGIC
      end
      return kt.RVEINTERNAL
   end
   return kt.RVSUCCESS
end

-- increment the numeric string value
function increment(inmap, outmap)
   local key = inmap.key
   local num = inmap.num
   if not key or not num then
      return kt.RVEINVALID
   end
   local function visit(rkey, rvalue, rxt)
      rvalue = tonumber(rvalue)
      if not rvalue then rvalue = 0 end
      num = rvalue + num
      return num
   end
   if not db:accept(key, visit) then
      return kt.REINTERNAL
   end
   outmap.num = num
   return kt.RVSUCCESS
end

-- retrieve the value of a record
function get(inmap, outmap)
   local key = inmap.key
   if not key then
      return kt.RVEINVALID
   end
   local value, xt = db:get(key)
   if value then
      outmap.value = value
      outmap.xt = xt
   else
      local err = db:error()
      if err:code() == kt.Error.NOREC then
         return kt.RVELOGIC
      end
      return kt.RVEINTERNAL
   end
   return kt.RVSUCCESS
end

-- store records at once
function setbulk(inmap, outmap)
   local num = db:set_bulk(inmap)
   if num < 0 then
      return kt.RVEINTERNAL
   end
   outmap["num"] = num
   return kt.RVSUCCESS
end

-- remove records at once
function removebulk(inmap, outmap)
   local keys = {}
   for key, value in pairs(inmap) do
      table.insert(keys, key)
   end
   local num = db:remove_bulk(keys)
   if num < 0 then
      return kt.RVEINTERNAL
   end
   outmap["num"] = num
   return kt.RVSUCCESS
end

-- retrieve records at once
function getbulk(inmap, outmap)
   local keys = {}
   for key, value in pairs(inmap) do
      table.insert(keys, key)
   end
   local res = db:get_bulk(keys)
   if not res then
      return kt.RVEINTERNAL
   end
   for key, value in pairs(res) do
      outmap[key] = value
   end
   return kt.RVSUCCESS
end

-- move the value of a record to another
function move(inmap, outmap)
   local srckey = inmap.src
   local destkey = inmap.dest
   if not srckey or not destkey then
      return kt.RVEINVALID
   end
   local keys = { srckey, destkey }
   local first = true
   local srcval = nil
   local srcxt = nil
   local function visit(key, value, xt)
      if first then
         srcval = value
         srcxt = xt
         first = false
         return kt.Visitor.REMOVE
      end
      if srcval then
         return srcval, srcxt
      end
      return kt.Visitor.NOP
   end
   if not db:accept_bulk(keys, visit) then
      return kt.REINTERNAL
   end
   if not srcval then
      return kt.RVELOGIC
   end
   return kt.RVSUCCESS
end

-- list all records
function list(inmap, outmap)
   local cur = db:cursor()
   cur:jump()
   while true do
      local key, value, xt = cur:get(true)
      if not key then break end
      outmap[key] = value
   end
   return kt.RVSUCCESS
end

-- upcate all characters in the value of a record
function upcase(inmap, outmap)
   local key = inmap.key
   if not key then
      return kt.RVEINVALID
   end
   local function visit(key, value, xt)
      if not value then
         return kt.Visitor.NOP
      end
      return string.upper(value)
   end
   if not db:accept(key, visit) then
      return kt.RVEINTERNAL
   end
   return kt.RVSUCCESS
end

-- prolong the expiration time of a record
function survive(inmap, outmap)
   local key = inmap.key
   if not key then
      return kt.RVEINVALID
   end
   local function visit(key, value, xt)
      if not value then
         return kt.Visitor.NOP
      end
      outmap.old_xt = xt
      if xt > kt.time() + 3600 then
         return kt.Visitor.NOP
      end
      return value, 3600
   end
   if not db:accept(key, visit) then
      return kt.RVEINTERNAL
   end
   return kt.RVSUCCESS
end

-- count words with the MapReduce framework
function countwords(inmap, outmap)
   local function map(key, value, emit)
      local values = kt.split(value, " ")
      for i = 1, #values do
         local word = kt.regex(values[i], "[ .?!:;]", "")
         word = string.lower(word)
         if #word > 0 then
            if not emit(word, "") then
               return false
            end
         end
      end
      return true
   end
   local function reduce(key, iter)
      local count = 0
      while true do
         local value = iter()
         if not value then
            break
         end
         count = count + 1
      end
      outmap[key] = count
      return true
   end
   if not db:mapreduce(map, reduce, nil, kt.DB.XNOLOCK) then
      return kt.RVEINTERNAL
   end
   return kt.RVSUCCESS
end

To call the above functions, execute the following commands.

$ ktremotemgr script -arg key1 value1 -arg key2 value2 echo
$ ktremotemgr script report
$ ktremotemgr script -arg kind info -arg message hello log
$ ktremotemgr script -arg key one -arg value first set
$ ktremotemgr script -arg key two -arg value second set
$ ktremotemgr script -arg key three -arg value third set
$ ktremotemgr script -arg key three remove
$ ktremotemgr script -arg key two get
$ ktremotemgr script list

Modules

kyototycoon The scripting extension of Kyoto Tycoon.
Kyoto Tycoon Manual
kyototycoon-0.9.56/doc/luadoc/modules/0000755000175000017500000000000011757471601016713 5ustar mikiomikiokyototycoon-0.9.56/doc/luadoc/modules/kyototycoon.html0000644000175000017500000020120311757471601022200 0ustar mikiomikio Kyoto Tycoon

Module kyototycoon

The scripting extension of Kyoto Tycoon.

Functions

DB:delete_ptr (ptr) Delete a database object.
DB:new (ptr) Create a database object.
DB:new_ptr () Create a database object.
DB:process (proc, path, mode) Process a database by a functor.
Error:new (code, message) Create an error object.
FileProcessor:new () Create a file processor object.
Visitor:new () Create a visitor object.
arraydump (src) Serialize an array into a string.
arrayload (src) Deserialize a string into an array.
atof (str) Convert a string to a real number.
atoi (str) Convert a string to an integer.
atoix (str) Convert a string with a metric prefix to an integer.
bit (mode, num, aux) Perform bit operation of an integer.
codec (mode, str) Encode or decode a string.
cursor:__call (db) Get a pair of the key and the value of the current record.
cursor:__tostring () Get the string expression.
cursor:accept (visitor, writable, step) Accept a visitor to the current record.
cursor:db () Get the database object.
cursor:disable () Disable the cursor.
cursor:error () Get the last happened error.
cursor:get (step) Get a pair of the key and the value of the current record.
cursor:get_key (step) Get the key of the current record.
cursor:get_value (step) Get the value of the current record.
cursor:jump (key) Jump the cursor to a record for forward scan.
cursor:jump_back (key) Jump the cursor to a record for backward scan.
cursor:remove () Remove the current record.
cursor:seize () Get a pair of the key and the value of the current record and remove it atomically.
cursor:set_value (value, xt, step) Set the value of the current record.
cursor:step () Step the cursor to the next record.
cursor:step_back () Step the cursor to the previous record.
db:__index (key) Retrieve the value of a record.
db:__newindex (key, value) Set the value of a record.
db:__tostring () Get the string expression.
db:accept (key, visitor, writable) Accept a visitor to a record.
db:accept_bulk (keys, visitor, writable) Accept a visitor to multiple records at once.
db:add (key, value, xt) Add a record.
db:append (key, value, xt) Append the value of a record.
db:begin_transaction (hard) Begin transaction.
db:cas (key, oval, nval, xt) Perform compare-and-swap.
db:check (key) Check the existence of a record.
db:clear () Remove all records.
db:close () Close the database file.
db:copy (dest) Create a copy of the database file.
db:count () Get the number of records.
db:cursor () Create a cursor object.
db:cursor_process (proc) Process a cursor by a functor.
db:dump_snapshot (dest) Dump records into a snapshot file.
db:end_transaction (commit) End transaction.
db:get (key) Retrieve the value of a record.
db:get_bulk (keys, atomic) Retrieve records at once.
db:increment (key, num, orig, xt) Add a number to the numeric integer value of a record.
db:increment_double (key, num, orig, xt) Add a number to the numeric double value of a record.
db:iterate (visitor, writable) Iterate to accept a visitor for each record.
db:load_snapshot (src) Load records from a snapshot file.
db:mapreduce (map, reduce, tmppath, opts, dbnum, clim, cbnum, log, proc) Execute a MapReduce process.
db:match_prefix (prefix, max) Get keys matching a prefix string.
db:match_regex (regex, max) Get keys matching a regular expression string.
db:match_similar (origin, range, utf, max) Get keys similar to a string in terms of the levenshtein distance.
db:merge (srcary, mode) Merge records from other databases.
db:occupy (writable, proc) Occupy database by locking and do something meanwhile.
db:open (path, mode) Open a database file.
db:pairs () Create three objects for the generic "for" loop.
db:path () Get the path of the database file.
db:remove (key) Remove a record.
db:remove_bulk (keys, atomic) Remove records at once.
db:replace (key, value, xt) Replace the value of a record.
db:seize (key) Retrieve the value of a record and remove it atomically.
db:set (key, value, xt) Set the value of a record.
db:set_bulk (recs, atomic, xt) Store records at once.
db:size () Get the size of the database file.
db:status () Get the miscellaneous status information.
db:synchronize (hard, proc) Synchronize updated contents with the file and the device.
db:transaction (proc, hard) Perform entire transaction by a functor.
error:__tostring () Get the string expression.
error:code () Get the error code.
error:message () Get the supplement message.
error:name () Get the readable string of the code.
error:set (code, message) Set the error information.
fileprocessor:process (path, count, size) Process the database file.
hash_fnv (str) Get the hash value of a string by FNV hashing.
hash_murmur (str) Get the hash value of a string by MurMur hashing.
levdist (a, b, utf) Calculate the levenshtein distance of two strings.
log (kind, message) Log a message
mapdump (src) Serialize a map into a string.
mapload (src) Deserialize a string into a map.
pack (format, ary, ...) Serialize an array of numbers into a string.
regex (str, pattern, alt) Perform pattern matching or replacement with regular expressions.
sleep (sec) Suspend execution of the current thread.
split (str, delims) Split a string into substrings.
strbwm (str, pattern) Perform backward matching without evaluating any meta character.
strfwm (str, pattern) Perform forward matching without evaluating any meta character.
strstr (str, pattern, alt) Perform substring matching or replacement without evaluating any meta character.
time () Get the time of day in seconds.
unpack (format, str) Deserialize a binary string into an array of numbers.
visitor:visit_after () Postprocess the main operations.
visitor:visit_before () Preprocess the main operations.
visitor:visit_empty (key) Visit a empty record space.
visitor:visit_full (key, value, xt) Visit a record.

Tables

Cursor Interface of cursor to indicate a record.
DB Interface of database abstraction.
Error Error data.
FileProcessor Interface to process the database file.
Visitor Interface to access a record.
__kyototycoon__ Running environment.


Functions

DB:delete_ptr (ptr)
Delete a database object.

Parameters

  • ptr: a light user data of the pointer to the database object.

Return value:

always nil.
DB:new (ptr)
Create a database object.

Parameters

  • ptr: a light user data of the pointer to a database object to use internally. If it is omitted, the internal database object is created and destroyed implicitly.

Return value:

the database object.
DB:new_ptr ()
Create a database object.

Return value:

a light user data of the pointer to the created database object. It should be released with the delete_ptr method when it is no longer in use.
DB:process (proc, path, mode)
Process a database by a functor.

Parameters

  • proc: the functor to process the database, whose object is passd as the parameter.
  • path: the same to the one of the open method.
  • mode: the same to the one of the open method.

Return value:

nil on success, or an error object on failure.
Error:new (code, message)
Create an error object.

Parameters

  • code: the error code.
  • message: the supplement message.

Return value:

the error object.
FileProcessor:new ()
Create a file processor object.

Return value:

the file processor object.
Visitor:new ()
Create a visitor object.

Return value:

the visitor object.
arraydump (src)
Serialize an array into a string.

Parameters

  • src: the source table.

Return value:

the result string.
arrayload (src)
Deserialize a string into an array.

Parameters

  • src: the source string.

Return value:

the result map.
atof (str)
Convert a string to a real number.

Parameters

  • str: the string.

Return value:

the real number. If the string does not contain numeric expression, 0.0 is returned.
atoi (str)
Convert a string to an integer.

Parameters

  • str: the string.

Return value:

the integer. If the string does not contain numeric expression, 0 is returned.
atoix (str)
Convert a string with a metric prefix to an integer.

Parameters

  • str: the string, which can be trailed by a binary metric prefix. "K", "M", "G", "T", "P", and "E" are supported. They are case-insensitive.

Return value:

the integer. If the string does not contain numeric expression, 0 is returned. If the integer overflows the domain, INT64_MAX or INT64_MIN is returned according to the sign.
bit (mode, num, aux)
Perform bit operation of an integer.

Parameters

  • mode: the operator; "and" for bitwise-and operation, "or" for bitwise-or operation, "xor" for bitwise-xor operation, "not" for bitwise-not operation, "left" for left shift operation, "right" for right shift operation.
  • num: the integer, which is treated as an unsigned 32-bit integer.
  • aux: the auxiliary operand for some operators.

Return value:

the result value.
codec (mode, str)
Encode or decode a string.

Parameters

  • mode: the encoding method; "url" for URL encoding, "~url" for URL decoding, "base" for Base64 encoding, "~base" for Base64 decoding, "hex" for hexadecimal encoding, "~hex" for hexadecimal decoding, "zlib" for ZLIB raw compressing, "~zlib" for ZLIB raw decompressing, "deflate" for ZLIB deflate compressing, "~deflate" for ZLIB deflate decompressing, "gzip" for ZLIB gzip compressing, "~gzip" for ZLIB gzip decompressing.
  • str: the string.

Return value:

the result string.
cursor:__call (db)
Get a pair of the key and the value of the current record.

Parameters

  • db: ignored. This is just for compatibility with the "next" function for the generic "for" loop.

Usage:

If the cursor is invalidated, nil is returned.

Return value:

a pair of the key and the value of the current record, or nil on failure.
cursor:__tostring ()
Get the string expression.

Return value:

the string expression.
cursor:accept (visitor, writable, step)
Accept a visitor to the current record.

Parameters

  • visitor: a visitor object which implements the Visitor interface, or a function object which receives the key and the value.
  • writable: true for writable operation, or false for read-only operation. If it is omitted, true is specified.
  • step: true to move the cursor to the next record, or false for no move. If it is omitted, false is specified.

Usage:

The operation for each record is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this method.

Return value:

true on success, or false on failure.
cursor:db ()
Get the database object.

Return value:

the database object.
cursor:disable ()
Disable the cursor.

Usage:

This method should be called explicitly when the cursor is no longer in use.

Return value:

always nil.
cursor:error ()
Get the last happened error.

Return value:

the last happened error.
cursor:get (step)
Get a pair of the key and the value of the current record.

Parameters

  • step: true to move the cursor to the next record, or false for no move. If it is omitted, false is specified.

Usage:

If the cursor is invalidated, nil is returned.

Return value:

a trio of the key and the value and the expiration time of the current record, or nil on failure.
cursor:get_key (step)
Get the key of the current record.

Parameters

  • step: true to move the cursor to the next record, or false for no move. If it is omitted, false is specified.

Usage:

If the cursor is invalidated, nil is returned.

Return value:

the key of the current record, or nil on failure.
cursor:get_value (step)
Get the value of the current record.

Parameters

  • step: true to move the cursor to the next record, or false for no move. If it is omitted, false is specified.

Usage:

If the cursor is invalidated, nil is returned.

Return value:

the value of the current record, or nil on failure.
cursor:jump (key)
Jump the cursor to a record for forward scan.

Parameters

  • key: the key of the destination record. if it is omitted, the destination is the first record.

Return value:

true on success, or false on failure.
cursor:jump_back (key)
Jump the cursor to a record for backward scan.

Parameters

  • key: the key of the destination record. if it is omitted, the destination is the last record.

Usage:

This method is dedicated to tree databases. Some database types, especially hash databases, will provide a dummy implementation.

Return value:

true on success, or false on failure.
cursor:remove ()
Remove the current record.

Usage:

If no record corresponds to the key, false is returned. The cursor is moved to the next record implicitly.

Return value:

true on success, or false on failure.
cursor:seize ()
Get a pair of the key and the value of the current record and remove it atomically.

Usage:

If the cursor is invalidated, nil is returned. The cursor is moved to the next record implicitly.

Return value:

a trio of the key and the value and the expiration time of the current record, or nil on failure.
cursor:set_value (value, xt, step)
Set the value of the current record.

Parameters

  • value: the value.
  • xt: the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
  • step: true to move the cursor to the next record, or false for no move. If it is omitted, false is specified.

Return value:

true on success, or false on failure.
cursor:step ()
Step the cursor to the next record.

Return value:

true on success, or false on failure.
cursor:step_back ()
Step the cursor to the previous record.

Usage:

This method is dedicated to tree databases. Some database types, especially hash databases, will provide a dummy implementation.

Return value:

true on success, or false on failure.
db:__index (key)
Retrieve the value of a record.

Parameters

  • key: the key.

Return value:

the value of the corresponding record, or nil on failure.
db:__newindex (key, value)
Set the value of a record.

Parameters

  • key: the key.
  • value: the value. If it is nil, the record is removed.

Usage:

If no record corresponds to the key, a new record is created. If the corresponding record exists, the value is overwritten.

Return value:

true on success, or false on failure.
db:__tostring ()
Get the string expression.

Return value:

the string expression.
db:accept (key, visitor, writable)
Accept a visitor to a record.

Parameters

  • key: the key.
  • visitor: a visitor object which implements the Visitor interface, or a function object which receives the key and the value.
  • writable: true for writable operation, or false for read-only operation. If it is omitted, true is specified.

Usage:

The operation for each record is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this method.

Return value:

true on success, or false on failure.
db:accept_bulk (keys, visitor, writable)
Accept a visitor to multiple records at once.

Parameters

  • keys: specifies an array of the keys.
  • visitor: a visitor object which implements the Visitor interface, or a function object which receives the key and the value.
  • writable: true for writable operation, or false for read-only operation. If it is omitted, true is specified.

Usage:

The operations for specified records are performed atomically and other threads accessing the same records are blocked. To avoid deadlock, any explicit database operation must not be performed in this method.

Return value:

true on success, or false on failure.
db:add (key, value, xt)
Add a record.

Parameters

  • key: the key.
  • value: the value.
  • xt: the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.

Usage:

If no record corresponds to the key, a new record is created. If the corresponding record exists, the record is not modified and false is returned.

Return value:

true on success, or false on failure.
db:append (key, value, xt)
Append the value of a record.

Parameters

  • key: the key.
  • value: the value.
  • xt: the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.

Usage:

If no record corresponds to the key, a new record is created. If the corresponding record exists, the given value is appended at the end of the existing value.

Return value:

true on success, or false on failure.
db:begin_transaction (hard)
Begin transaction.

Parameters

  • hard: true for physical synchronization with the device, or false for logical synchronization with the file system. If it is omitted, false is specified.

Return value:

true on success, or false on failure.
db:cas (key, oval, nval, xt)
Perform compare-and-swap.

Parameters

  • key: the key.
  • oval: the old value. nil means that no record corresponds.
  • nval: the new value. nil means that the record is removed.
  • xt: the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.

Return value:

true on success, or false on failure.
db:check (key)
Check the existence of a record.

Parameters

  • key: the key.

Return value:

the size of the value, or -1 on failure.
db:clear ()
Remove all records.

Return value:

true on success, or false on failure.
db:close ()
Close the database file.

Return value:

true on success, or false on failure.
db:copy (dest)
Create a copy of the database file.

Parameters

  • dest: the path of the destination file.

Return value:

true on success, or false on failure.
db:count ()
Get the number of records.

Return value:

the number of records, or -1 on failure.
db:cursor ()
Create a cursor object.

Return value:

the return value is the created cursor object. Each cursor should be disabled with the Cursor#disable method when it is no longer in use.
db:cursor_process (proc)
Process a cursor by a functor.

Parameters

  • proc: the functor of operations for the cursor. The cursor is disabled implicitly after the block.

Return value:

always nil.
db:dump_snapshot (dest)
Dump records into a snapshot file.

Parameters

  • dest: the name of the destination file.

Return value:

true on success, or false on failure.
db:end_transaction (commit)
End transaction.

Parameters

  • commit: true to commit the transaction, or false to abort the transaction. If it is omitted, true is specified.

Return value:

true on success, or false on failure.
db:get (key)
Retrieve the value of a record.

Parameters

  • key: the key.

Return value:

the value of the corresponding record, or nil on failure. The absolute expiration time is also returned as the second value.
db:get_bulk (keys, atomic)
Retrieve records at once.

Parameters

  • keys: an array of the keys of the records to retrieve.
  • atomic: true to perform all operations atomically, or false for non-atomic operations. If it is omitted, true is specified.

Return value:

a table of retrieved records, or nil on failure.
db:increment (key, num, orig, xt)
Add a number to the numeric integer value of a record.

Parameters

  • key: the key.
  • num: the additional number. if it is omitted, 0 is specified.
  • orig: the origin number if no record corresponds to the key. If it is omitted, 0 is specified. If it is negative infinity and no record corresponds, this method fails. If it is positive infinity, the value is set as the additional number regardless of the current value.
  • xt: the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.

Usage:

The value is serialized as an 8-byte binary integer in big-endian order, not a decimal string. If existing value is not 8-byte, this method fails.

Return value:

the result value, or nil on failure.
db:increment_double (key, num, orig, xt)
Add a number to the numeric double value of a record.

Parameters

  • key: the key.
  • num: the additional number. if it is omitted, 0 is specified.
  • orig: the origin number if no record corresponds to the key. If it is omitted, 0 is specified. If it is negative infinity and no record corresponds, this method fails. If it is positive infinity, the value is set as the additional number regardless of the current value.
  • xt: the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.

Usage:

The value is serialized as an 16-byte binary fixed-point number in big-endian order, not a decimal string. If existing value is not 16-byte, this method fails.

Return value:

the result value, or nil on failure.
db:iterate (visitor, writable)
Iterate to accept a visitor for each record.

Parameters

  • visitor: a visitor object which implements the Visitor interface, or a function object which receives the key and the value.
  • writable: true for writable operation, or false for read-only operation. If it is omitted, true is specified.

Usage:

The whole iteration is performed atomically and other threads are blocked. To avoid deadlock, any explicit database operation must not be performed in this method.

Return value:

true on success, or false on failure.
db:load_snapshot (src)
Load records from a snapshot file.

Parameters

  • src: the name of the source file.

Return value:

true on success, or false on failure.
db:mapreduce (map, reduce, tmppath, opts, dbnum, clim, cbnum, log, proc)
Execute a MapReduce process.

Parameters

  • map: a function to map a record data. It is called for each record in the database and receives the key, the value, and a function to emit the mapped records. The emitter function receives a key and a value. The mapper function should return true normally or false on failure.
  • reduce: a function to reduce a record data. It is called for each record generated by emitted records by the map function and receives the key and a function to iterate to get each value. The reducer function should return true normally or false on failure.
  • tmppath: the path of a directory for the temporary data storage. If it is omitted, temporary data are handled on memory.
  • opts: the optional features by bitwise-or: DB.XNOLOCK to avoid locking against update operations by other threads, DB.XNOCOMP to avoid compression of temporary databases.
  • dbnum: the number of temporary databases. If it is omitted, the default setting is specified.
  • clim: the limit size of the internal cache. If it is omitted, the default setting is specified.
  • cbnum: the bucket number of the internal cache. If it is omitted, the default setting is specified.
  • log: a function to log each progression message. If it is omitted, log messages are ignored.
  • proc: a function called before the mapper, between the mapper and the reducer, and after the reducer. In the first two calls, the function receives a function to emit the mapped records. If it is omitted, such triggers are ignored.

Return value:

true on success, or false on failure.
db:match_prefix (prefix, max)
Get keys matching a prefix string.

Parameters

  • prefix: the prefix string.
  • max: the maximum number to retrieve. If it is omitted or negative, no limit is specified.

Return value:

an array of matching keys, or nil on failure.
db:match_regex (regex, max)
Get keys matching a regular expression string.

Parameters

  • regex: the regular expression string.
  • max: the maximum number to retrieve. If it is omitted or negative, no limit is specified.

Return value:

an array of matching keys, or nil on failure.
db:match_similar (origin, range, utf, max)
Get keys similar to a string in terms of the levenshtein distance.

Parameters

  • origin: the origin string.
  • range: the maximum distance of keys to adopt. If it is omitted, 1 is specified.
  • utf: flag to treat keys as UTF-8 strings. If it is omitted, false is specified.
  • max: the maximum number to retrieve. If it is omitted or negative, no limit is specified.

Return value:

an array of matching keys, or nil on failure.
db:merge (srcary, mode)
Merge records from other databases.

Parameters

  • srcary: an array of the source detabase objects.
  • mode: the merge mode. DB.MSET to overwrite the existing value, DB.MADD to keep the existing value, DB.MAPPEND to append the new value. If it is omitted, DB.MSET is specified.

Return value:

true on success, or false on failure.
db:occupy (writable, proc)
Occupy database by locking and do something meanwhile.

Parameters

  • writable: true to use writer lock, or false to use reader lock. If it is omitted, false is specified.
  • proc: a processor object which implements the FileProcessor interface, or a function object which receives the same parameters. If it is omitted or nil, no processing is performed.

Usage:

The operation of the processor is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this method.

Return value:

true on success, or false on failure.
db:open (path, mode)
Open a database file.

Parameters

  • path: the path of a database file. If it is "-", the database will be a prototype hash database. If it is "+", the database will be a prototype tree database. If it is ":", the database will be a stash database. If it is "*", the database will be a cache hash database. If it is "%", the database will be a cache tree database. If its suffix is ".kch", the database will be a file hash database. If its suffix is ".kct", the database will be a file tree database. If its suffix is ".kcd", the database will be a directory hash database. If its suffix is ".kcf", the database will be a directory tree database. If its suffix is ".kcx", the database will be a plain text database. Otherwise, this function fails. Tuning parameters can trail the name, separated by "#". Each parameter is composed of the name and the value, separated by "=". If the "type" parameter is specified, the database type is determined by the value in "-", "+", ":", "*", "%", "kch", "kct", "kcd", kcf", and "kcx". All database types support the logging parameters of "log", "logkinds", and "logpx". The prototype hash database and the prototype tree database do not support any other tuning parameter. The stash database supports "bnum". The cache hash database supports "opts", "bnum", "zcomp", "capcnt", "capsiz", and "zkey". The cache tree database supports all parameters of the cache hash database except for capacity limitation, and supports "psiz", "rcomp", "pccap" in addition. The file hash database supports "apow", "fpow", "opts", "bnum", "msiz", "dfunit", "zcomp", and "zkey". The file tree database supports all parameters of the file hash database and "psiz", "rcomp", "pccap" in addition. The directory hash database supports "opts", "zcomp", and "zkey". The directory tree database supports all parameters of the directory hash database and "psiz", "rcomp", "pccap" in addition. The plain text database does not support any other tuning parameter.
  • mode: the connection mode. DB.OWRITER as a writer, DB.OREADER as a reader. The following may be added to the writer mode by bitwise-or: DB.OCREATE, which means it creates a new database if the file does not exist, DB.OTRUNCATE, which means it creates a new database regardless if the file exists, DB.OAUTOTRAN, which means each updating operation is performed in implicit transaction, DB.OAUTOSYNC, which means each updating operation is followed by implicit synchronization with the file system. The following may be added to both of the reader mode and the writer mode by bitwise-or: DB.ONOLOCK, which means it opens the database file without file locking, DB.OTRYLOCK, which means locking is performed without blocking, DB.ONOREPAIR, which means the database file is not repaired implicitly even if file destruction is detected. If it is omitted, DB.OWRITER + DB.OCREATE is specified.

Usage:

The tuning parameter "log" is for the original "tune_logger" and the value specifies the path of the log file, or "-" for the standard output, or "+" for the standard error. "logkinds" specifies kinds of logged messages and the value can be "debug", "info", "warn", or "error". "logpx" specifies the prefix of each log message. "opts" is for "tune_options" and the value can contain "s" for the small option, "l" for the linear option, and "c" for the compress option. "bnum" corresponds to "tune_bucket". "zcomp" is for "tune_compressor" and the value can be "zlib" for the ZLIB raw compressor, "def" for the ZLIB deflate compressor, "gz" for the ZLIB gzip compressor, "lzo" for the LZO compressor, "lzma" for the LZMA compressor, or "arc" for the Arcfour cipher. "zkey" specifies the cipher key of the compressor. "capcnt" is for "cap_count". "capsiz" is for "cap_size". "psiz" is for "tune_page". "rcomp" is for "tune_comparator" and the value can be "lex" for the lexical comparator or "dec" for the decimal comparator. "pccap" is for "tune_page_cache". "apow" is for "tune_alignment". "fpow" is for "tune_fbp". "msiz" is for "tune_map". "dfunit" is for "tune_defrag". Every opened database must be closed by the DB::close method when it is no longer in use. It is not allowed for two or more database objects in the same process to keep their connections to the same database file at the same time.

Return value:

true on success, or false on failure.
db:pairs ()
Create three objects for the generic "for" loop.

Return value:

multiple values composed of the "next" functor, the database object itself, and nil.
db:path ()
Get the path of the database file.

Return value:

the path of the database file, or nil on failure.
db:remove (key)
Remove a record.

Parameters

  • key: the key.

Usage:

If no record corresponds to the key, false is returned.

Return value:

true on success, or false on failure.
db:remove_bulk (keys, atomic)
Remove records at once.

Parameters

  • keys: an array of the keys of the records to remove.
  • atomic: true to perform all operations atomically, or false for non-atomic operations. If it is omitted, true is specified.

Return value:

the number of removed records, or -1 on failure.
db:replace (key, value, xt)
Replace the value of a record.

Parameters

  • key: the key.
  • value: the value.
  • xt: the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.

Usage:

If no record corresponds to the key, no new record is created and false is returned. If the corresponding record exists, the value is modified.

Return value:

true on success, or false on failure.
db:seize (key)
Retrieve the value of a record and remove it atomically.

Parameters

  • key: the key.

Return value:

the value of the corresponding record, or nil on failure. The absolute expiration time is also returned as the second value.
db:set (key, value, xt)
Set the value of a record.

Parameters

  • key: the key.
  • value: the value.
  • xt: the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.

Usage:

If no record corresponds to the key, a new record is created. If the corresponding record exists, the value is overwritten.

Return value:

true on success, or false on failure.
db:set_bulk (recs, atomic, xt)
Store records at once.

Parameters

  • recs: a table of the records to store.
  • atomic: true to perform all operations atomically, or false for non-atomic operations. If it is omitted, true is specified.
  • xt: the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.

Return value:

the number of stored records, or -1 on failure.
db:size ()
Get the size of the database file.

Return value:

the size of the database file in bytes, or -1 on failure.
db:status ()
Get the miscellaneous status information.

Return value:

a table of the status information, or nil on failure.
db:synchronize (hard, proc)
Synchronize updated contents with the file and the device.

Parameters

  • hard: true for physical synchronization with the device, or false for logical synchronization with the file system. If it is omitted, false is specified.
  • proc: a postprocessor object which implements the FileProcessor interface, or a function object which receives the same parameters. If it is omitted or nil, no postprocessing is performed.

Usage:

The operation of the processor is performed atomically and other threads accessing the same record are blocked. To avoid deadlock, any explicit database operation must not be performed in this method.

Return value:

true on success, or false on failure.
db:transaction (proc, hard)
Perform entire transaction by a functor.

Parameters

  • proc: the functor of operations during transaction. If the function returns true, the transaction is committed. If the function returns false or an exception is thrown, the transaction is aborted.
  • hard: true for physical synchronization with the device, or false for logical synchronization with the file system. If it is omitted, false is specified.

Return value:

true on success, or false on failure.
error:__tostring ()
Get the string expression.

Return value:

the string expression.
error:code ()
Get the error code.

Return value:

the error code.
error:message ()
Get the supplement message.

Return value:

the supplement message.
error:name ()
Get the readable string of the code.

Return value:

the readable string of the code.
error:set (code, message)
Set the error information.

Parameters

  • code: the error code.
  • message: the supplement message.

Return value:

always nil.
fileprocessor:process (path, count, size)
Process the database file.

Parameters

  • path: the path of the database file.
  • count: the number of records.
  • size: the size of the available region.

Return value:

true on success, or false on failure.
hash_fnv (str)
Get the hash value of a string by FNV hashing.

Parameters

  • str: the string.

Return value:

the hash value.
hash_murmur (str)
Get the hash value of a string by MurMur hashing.

Parameters

  • str: the string.

Return value:

the hash value.
levdist (a, b, utf)
Calculate the levenshtein distance of two strings.

Parameters

  • a: one string.
  • b: the other string.
  • utf: flag to treat keys as UTF-8 strings. If it is omitted, false is specified.

Return value:

the levenshtein distance.
log (kind, message)
Log a message

Parameters

  • kind: the kind of the event. "debug" for debugging, "info" for normal information, "system" for system information, and "error" for fatal error.
  • message: the supplement message.

Return value:

always nil.
mapdump (src)
Serialize a map into a string.

Parameters

  • src: the source table.

Return value:

the result string.
mapload (src)
Deserialize a string into a map.

Parameters

  • src: the source string.

Return value:

the result map.
pack (format, ary, ...)
Serialize an array of numbers into a string.

Parameters

  • format: the format string. It should be composed of conversion characters. "c" for int8_t, "C" for uint8_t, "s" for int16_t, "S" for uint16_t, "i" for int32_t, "I" for uint32_t, "l" for int64_t, "L" for uint64_t, "f" for float, "d" for double, "n" for uint16_t in network byte order, "N" for uint32_t in network byte order, "M" for uint64_t in network byte order, and "w" for BER encoding. They can be trailed by a numeric expression standing for the iteration count or by "*" for the rest all iteration.
  • ary: the array of numbers. It can be trailed optional arguments, which are treated as additional elements of the array.
  • ...:

Return value:

the serialized string.
regex (str, pattern, alt)
Perform pattern matching or replacement with regular expressions.

Parameters

  • str: the source string.
  • pattern: the pattern of regular expressions.
  • alt: the alternative string corresponding for the pattern. If it is not defined, matching check is performed.

Return value:

If the alternative string is specified, the converted string is returned. If the alternative string is not specified, the boolean value of whether the source string matches the pattern is returned.
sleep (sec)
Suspend execution of the current thread.

Parameters

  • sec: the interval of the suspension in seconds. If it is omitted, the processor is yielded from the current thread.
split (str, delims)
Split a string into substrings.

Parameters

  • str: the string
  • delims: a string including separator characters. If it is omitted, the zero code is specified.

Return value:

an array of substrings.
strbwm (str, pattern)
Perform backward matching without evaluating any meta character.

Parameters

  • str: the source string.
  • pattern: the matching pattern.

Return value:

true if they matches, or false if not.
strfwm (str, pattern)
Perform forward matching without evaluating any meta character.

Parameters

  • str: the source string.
  • pattern: the matching pattern.

Return value:

true if they matches, or false if not.
strstr (str, pattern, alt)
Perform substring matching or replacement without evaluating any meta character.

Parameters

  • str: the source string.
  • pattern: the matching pattern.
  • alt: the alternative string corresponding for the pattern. If it is omitted, matching check is performed.

Return value:

If the alternative string is specified, the converted string is returned. If the alternative string is not specified, the index of the substring matching the given pattern or 0 is returned.
time ()
Get the time of day in seconds.

Return value:

the time of day in seconds. The accuracy is in microseconds.
unpack (format, str)
Deserialize a binary string into an array of numbers.

Parameters

  • format: the format string. It should be composed of conversion characters as with the pack function.
  • str: the binary string.

Return value:

the deserialized array.
visitor:visit_after ()
Postprocess the main operations.
visitor:visit_before ()
Preprocess the main operations.
visitor:visit_empty (key)
Visit a empty record space.

Parameters

  • key: the key.

Return value:

If it is a string, the value is replaced by the content. If it is Visitor.NOP or Visitor.REMOVE, nothing is modified. The expiration time can be also returned as the second value.
visitor:visit_full (key, value, xt)
Visit a record.

Parameters

  • key: the key.
  • value: the value.
  • xt: the absolute expiration time.

Return value:

If it is a string, the value is replaced by the content. If it is Visitor.NOP, nothing is modified. If it is Visitor.REMOVE, the record is removed. The expiration time can be also returned as the second value.

Tables

Cursor
Interface of cursor to indicate a record.
DB
Interface of database abstraction.
Fields
  • OREADER: open mode: open as a reader
  • OWRITER: open mode: open as a writer
  • OCREATE: open mode: writer creating
  • OTRUNCATE: open mode: writer truncating
  • OAUTOTRAN: open mode: auto transaction
  • OAUTOSYNC: open mode: auto synchronization
  • ONOLOCK: open mode: open without locking
  • OTRYLOCK: open mode: lock without blocking
  • ONOREPAIR: open mode: open without auto repair
  • MSET: merge mode: overwrite the existing value
  • MADD: merge mode: keep the existing value
  • MREPLACE: merge mode: modify the existing record only
  • MAPPEND: merge mode: append the new value
  • XNOLOCK: mapreduce option: avoid locking against update operations
  • XNOCOMP: mapreduce option: avoid compression of temporary databases
Error
Error data.
Fields
  • SUCCESS: error code: success
  • NOIMPL: error code: not implemented
  • INVALID: error code: invalid operation
  • NOREPOS: error code: no repository
  • NOPERM: error code: no permission
  • BROKEN: error code: broken file
  • DUPREC: error code: record duplication
  • NOREC: error code: no record
  • LOGIC: error code: logical inconsistency
  • SYSTEM: error code: system error
  • MISC: error code: miscellaneous error
FileProcessor
Interface to process the database file.
Visitor
Interface to access a record.
Fields
  • NOP: magic data: no operation
  • REMOVE: magic data: remove the record
__kyototycoon__
Running environment.
Fields
  • RVSUCCESS: status code: success
  • RVENOIMPL: status code: not implemented
  • RVEINVALID: status code: invalid operation
  • RVELOGIC: status code: logical inconsistency
  • RVEINTERNAL: status code: internal error
  • VERSION: the version information
  • thid: the ID number of the worker thread
  • db: the primary database object
  • dbs: an array of database objects
Kyoto Tycoon Manual
kyototycoon-0.9.56/doc/icon16.png0000644000175000017500000000046011450617400015566 0ustar mikiomikio‰PNG  IHDR(-SsRGB®Îé3PLTE379W4†`G‘NSUydqrp€‚“•’¡‘¸´ªÆ´¶³ÌÂØÏÒÖèèïûýúé tRNS@æØfbKGDˆH pHYs  šœtIMEÙ  oç=ŒiIDATÓUÎÑ€ @Q L”þÿkCœLïæËÙ@R"žÑÓ“ÇߌµôðiÑ 5ƒ ‹u‡ 貞9âà{*ØÛAªî¡#F'4+4[ø¶@»Åþ^#‘Ih€ðÙé?™í€òÉ{µIEND®B`‚kyototycoon-0.9.56/doc/index.html0000644000175000017500000001163711757471567016014 0ustar mikiomikio Kyoto Tycoon: a handy cache/storage server

Kyoto Tycoon: a handy cache/storage server

Copyright (C) 2009-2012 FAL Labs
Last Update: Fri, 25 May 2012 02:44:22 +0900

Overview

Kyoto Tycoon is a lightweight database server with auto expiration mechanism, which is useful to handle cache data and persistent data of various applications. Kyoto Tycoon is also a package of network interface to the DBM called Kyoto Cabinet. Though the DBM has high performance and high concurrency, you might bother in case that multiple processes share the same database, or remote processes access the database. Thus, Kyoto Tycoon is provided for concurrent and remote connections to Kyoto Cabinet. Kyoto Tycoon is composed of the server process managing multiple databases and its access library for client applications.

The network protocol between the server and clients is HTTP so that you can write client applications and client libraries in almost all popular languages. Both of RESTful-style interface by the GET, HEAD, PUT, DELETE methods and RPC-style inteface by the POST method are supported. The server can handle more than 10 thousand connections at the same time because it uses modern I/O event notification facilities such as "epoll" and "kqueue" of underlying systems. The server supports high availability mechanisms, which are hot backup, update logging, and asynchronous replication. The server can embed Lua, a lightweight script language so that you can define arbitrary operations of the database.

The server program of Kyoto Tycoon is written in the C++ language. It is available on platforms which have API conforming to C++03 with the TR1 library extensions. Kyoto Tycoon is a free software licensed under the GNU General Public License.


Documents

The following are documents of Kyoto Tycoon. They are contained also in the source package.


Packages

The following are the source packages of Kyoto Tycoon. As for binary packages, see the site of each distributor.


Information

Kyoto Tycoon was written and is maintained by FAL Labs. You can contact the author by e-mail to `info@fallabs.com'.


kyototycoon-0.9.56/doc/spex.html0000644000175000017500000025363311757471567015670 0ustar mikiomikio Fundamental Specifications of Kyoto Tycoon Version 1

Fundamental Specifications of Kyoto Tycoon Version 1

Copyright (C) 2009-2012 FAL Labs
Last Update: Fri, 25 May 2012 02:44:22 +0900

Table of Contents

  1. Introduction
  2. Installation
  3. Tutorial
  4. Tips and Hacks
  5. Protocol
  6. License

Introduction

Kyoto Tycoon is a lightweight database server with automatic expiration mechanism, which is useful to handle cache data and persistent data of various applications. Kyoto Tycoon is also a package of network interface to the DBM called Kyoto Cabinet. Although the DBM has high performance and high concurrency, you might bother in case that multiple processes share the same database, or remote processes access the database. Thus, Kyoto Tycoon is provided for concurrent and remote connections to Kyoto Cabinet. Kyoto Tycoon is composed of the server process managing multiple databases and its access library for client applications.

The server features high concurrency due to thread-pool modeled implementation and the epoll/kqueue mechanism of the modern Linux/*BSD kernel. It can handle more than 10 thousand connections at the same time. Because such system-specific features as epoll/kqueue are encapsulated and abstracted as the same interface, Kyoto Tycoon has high portability and works almost all UNIX-like systems and Windows.

The server provides hot backup so that you can make backup data without stopping the server while copying the database files. Update logging is also supported and it compensates for the difference between the contents of backup files and the current database. Moreover, the server implements asynchronous replication. A server sends update logs to other servers, which evaluate the logs immediately and keep their databases catching up to the master database.

The server and its clients communicate with each other by HTTP. So, you can write client applications and client libraries in almost all popular languages. Both of RESTful-style interface by the GET, HEAD, PUT, DELETE methods and RPC-style inteface by the POST method are supported. The RPC-style interface is based on the protocol called TSV-RPC. The entity bodies of the request and the response are text data formatted as tab-separated-values so that parsing them is very easy. In addition, several operations are available in an efficient binary protocol.

The server can embed Lua, a lightweight script language. Even if you cannot find any built-in operation matching your requirement among the client API of Kyoto Tycoon, you can define arbitrary operations by defining functions in Lua. The API for Lua scripts provides full set of database operations of Kyoto Cabinet including visitor, cursor, and transaction mechanisms.

The server can load a shared library file which implements a pluggable server mechanism. It can run arbitrary network services and operate database objects shared by the main server. It is useful to implement other network protocols. An implementation to support the memcached protocol is included in the source package. In a similar way, the server can load a shared library file which implements a pluggable database mechanism. It is useful to use other database libraries except for Kyoto Cabinet.

The server program of Kyoto Tycoon is written in the C++ language. It is available on platforms which have API conforming to C++03 with the TR1 library extensions. Kyoto Tycoon is a free software licensed under the GNU General Public License. You can write client applications which are not under control of our license, by making them just communicate with the server by HTTP without using the core library.


Installation

This section describes how to install Kyoto Tycoon with the source package. As for a binary package, see its installation manual.

Preparation

Kyoto Tycoon is available on UNIX-like systems. At least, the following environments are supported. Development for other platworms including Windows is now work-in-progress.

  • Linux 2.6 and later (i386/x86-64/PowerPC/Alpha/SPARC)
  • Mac OS X 10.5 and later (x86-64)

gcc (GNU Compiler Collection) 4.2 or later and make (GNU Make) are required to install Kyoto Tycoon with the source package. They are installed by default on Linux, FreeBSD and so on.

As Kyoto Tycoon depends on the following libraries, install them beforehand.

  • ZLIB : for loss-less data compression. 1.2.3 or later is required.
  • Kyoto Cabinet : lightweight embedded database library. 1.2.42 or later is required.

Installation

When an archive file of Kyoto Tycoon is extracted, change the current working directory to the generated directory and perform installation.

Run the configuration script.

$ ./configure

Build programs.

$ make

Perform self-diagnostic test. This takes a while.

$ make check

Install programs. This operation must be carried out by the root user.

# make install

Result

When a series of work finishes, the following files will be installed.

/usr/local/include/ktcommon.h
/usr/local/include/ktutil.h
/usr/local/include/ktsocket.h
/usr/local/include/ktthserv.h
/usr/local/include/kthttp.h
/usr/local/include/ktrpc.h
/usr/local/include/ktulog.h
/usr/local/include/ktshlib.h
/usr/local/include/kttimeddb.h
/usr/local/include/ktremotedb.h
/usr/local/include/ktplugserv.h
/usr/local/include/ktplugdb.h
/usr/local/lib/libkyototycoon.a
/usr/local/lib/libkyototycoon.so.x.y.z
/usr/local/lib/libkyototycoon.so.x
/usr/local/lib/libkyototycoon.so
/usr/local/lib/pkgconfig/kyototycoon.pc
/usr/local/libexec/ktplugservmemc.so
/usr/local/libexec/ktplugdbvoid.so
/usr/local/bin/ktutiltest
/usr/local/bin/ktutilmgr
/usr/local/bin/ktutilserv
/usr/local/bin/kttimedtest
/usr/local/bin/kttimedmgr
/usr/local/bin/ktserver
/usr/local/bin/ktremotetest
/usr/local/bin/ktremotemgr
/usr/local/man/man1/...
/usr/local/share/doc/kyototycoon/...

Options of Configure

The following options can be specified with `./configure'.

  • --enable-debug : build for debugging. Enable debugging symbols, do not perform optimization, and perform static linking.
  • --enable-devel : build for development. Enable debugging symbols, perform optimization, and perform dynamic linking.
  • --enable-profile : build for profiling. Enable profiling symbols, perform optimization, and perform dynamic linking.
  • --enable-static : build by static linking.
  • --disable-shared : avoid to build shared libraries.
  • --disable-event : avoid to use system-specific event notifiers.
  • --enable-lua : enable the scripting extension by Lua.

`--prefix' and other options are also available as with usual UNIX software packages. If you want to install Kyoto Tycoon under `/usr' not `/usr/local', specify `--prefix=/usr'. As well, the library search path does not include `/usr/local/lib', it is necessary to set the environment variable `LD_LIBRARY_PATH' to include `/usr/local/lib' before running applications of Kyoto Tycoon.

How to Use the Library

Kyoto Tycoon provides API of the C++ language and it is available by programs conforming to the C++03 standard. As the header files of Kyoto Tycoon are provided as `ktutil.h', `ktremotedb.h', and so on, applications should include one or more of them accordingly to use the API. As the library is provided as `libkyototycoon.a' and `libkyototycoon.so' and they depends on underlying system libraries, linker options corresponding to them are required by the build command. The typical build command is the following.

$ g++ -I/usr/local/include example.cc -o example \
  -L/usr/local/lib -lkyototycoon -lkyotocabinet -lz -lstdc++ \
  -lresolv -lnsl -ldl -lrt -lpthread -lm -lc

If you don't use the core library of C++ but an HTTP library in another language, you don't have to know the above messy rules.


Tutorial

This section describes how to use Kyoto Tycoon with the command line utilities and some sample application programs.

Kick-start

To begin with, let's run the database server program. Simply execute the following commnad. Some log messages are printed on the terminal.

$ ktserver
2010-10-03T16:24:38.467252+09:00: [SYSTEM]: ================ [START]: pid=19069
2010-10-03T16:24:38.467473+09:00: [SYSTEM]: opening a database: path=:
2010-10-03T16:24:38.467645+09:00: [SYSTEM]: starting the server: expr=:1978
2010-10-03T16:24:38.467751+09:00: [SYSTEM]: server socket opened: expr=:1978 timeout=30.0
2010-10-03T16:24:38.467775+09:00: [SYSTEM]: listening server socket started: fd=3

The command `ktserver' starts network service accepting commands from clients on local or remote machines. By default, an unnamed on-memory database is opened and managed by the server through the port 1978. To finish the server, input `Ctrl-C' on the terminal or send such termination signals as `SIGINT' or `SIGTERM' from another terminal.

Next, insert some records into the database. Execute the follwoing command on another terminal. Corresponding access logs will be printed on the server terminal.

$ ktremotemgr set japan tokyo
$ ktremotemgr set korea seoul
$ ktremotemgr set china beijing

The command `ktremotemgr' is a tool kit to manage the database as a client. The sub command "set" is to set a record. The first argument next to the sub command name is the key of a record and the second argument is the value of the record.

Retrieve the records by the key of each record using the sub command "get".

$ ktremotemgr get japan
tokyo
$ ktremotemgr get korea
seoul
$ ktremotemgr get china
beijing

Remove a record by the key using the sub command "remove".

$ ktremotemgr remove japan

Print the keys of all records using the sub command "list".

$ ktremotemgr list
korea
china

That's all for the fundamental operations. The KVS family have been improving performance thanks to discarding the functionality. See the specification of `ktserver' and `ktremotemgr' for more details.

Using HTTP Clients

Because every operation of the database is called via HTTP, you can use any HTTP client utility such as `curl' to operate the database.

# setting records
$ curl "http://localhost:1978/rpc/set?key=japan&value=tokyo"

# retrieving records
$ curl "http://localhost:1978/rpc/get?key=japan"
value   tokyo

# removing records
$ curl "http://localhost:1978/rpc/remove?key=japan"

RESTful-style interface is also supported in addition to the above RPC-style interface.

# setting records
$ echo -n tokyo | curl -X PUT -T - "http://localhost:1978/japan"

# retrieving records
$ curl "http://localhost:1978/japan"
tokyo

# removing records
$ curl -X DELETE "http://localhost:1978/japan"

Of cource, you can use your favorite scripting languages and libraries for more complex use cases. Because Kyoto Tycoon supports keep-alive connection mechanism, using libraries which support keep-alive is strongly suggested for performance reason.

Expiration of Records

One of the most important features of Kyoto Tycoon is expiration mechanism of records. That is, you can specify the expiration time when inserting a record. The record is automatically deleted after the current time exceeds the expiration time.

To insert a record which will be expired one minute after, execute the following command.

$ ktremotemgr set -xt 60 japan tokyo

Check the record immediately before the expiration. The "-pt" option shows the expiration time in seconds from the epoch.

$ ktremotemgr get -pt japan
tokyo   1286108387

Wait for more than one minute, and then retrieve the record again. It will be missing.

$ ktremotemgr get -pt japan
ktremotemgr: DB::get failed: :1978: 2: logical inconsistency: DB: 7: no record: no record

You can do the same things with an arbitrary HTTP client by specifiying the "xt" parameter.

$ curl "http://localhost:1978/rpc/set?key=japan&value=tokyo&xt=60"
$ curl "http://localhost:1978/rpc/get?key=japan"
value   tokyo
xt      1286109204
$ sleep 60
$ curl "http://localhost:1978/rpc/get?key=japan"
ERROR   DB: 7: no record: no record

Sample Application of the Remote Database

Leaving command line interface, let's write a sample application program handling a remote database. See the following source code.

#include <ktremotedb.h>

using namespace std;
using namespace kyototycoon;

// main routine
int main(int argc, char** argv) {

  // create the database object
  RemoteDB db;

  // open the database
  if (!db.open()) {
    cerr << "open error: " << db.error().name() << endl;
  }

  // store records
  if (!db.set("foo", "hop") ||
      !db.set("bar", "step") ||
      !db.set("baz", "jump")) {
    cerr << "set error: " << db.error().name() << endl;
  }

  // retrieve a record
  string value;
  if (db.get("foo", &value)) {
    cout << value << endl;
  } else {
    cerr << "get error: " << db.error().name() << endl;
  }

  // traverse records
  RemoteDB::Cursor* cur = db.cursor();
  cur->jump();
  string ckey, cvalue;
  while (cur->get(&ckey, &cvalue, NULL, true)) {
    cout << ckey << ":" << cvalue << endl;
  }
  delete cur;

  // close the database
  if (!db.close()) {
    cerr << "close error: " << db.error().name() << endl;
  }

  return 0;
}

Save the above code as a file "example.cc". Then, perform the following command line. The command `kcutilmgr conf' prints the building configuration.

$ g++ `ktutilmgr conf -i` -o example example.cc `ktutilmgr conf -l`

Execute the application program built by the above. Of course, run the database server on another terminal beforehand.

$ ./example
hop
foo:hop
bar:step
baz:jump

The API of the remote database is defined in the header `ktremote.h'. So, include the header near the front of a source file. All symbols of Kyoto Tycoon are packaged in the name space `kyototycoon'. You can use them without any prefix by importing the name space.

#include <ktremotedb.h>
using namespace kyototycoon;

The class `RemoteDB' contains all functionality of the remote database and each instance expresses a remote database file.

RemoteDB db;

Each connection must be opened by the `open' method before any database operation. Although it takes three parameters, all of them can be omitted. The first parameter specifies the host name of the server and the default value is the name of the local host. The second parameter specifies the port number and the default value is 1978 which is the same as the default port of the database server. The third parameter specifies the timeout of network operation in seconds and the default value is no timeout.

db.open();

Every opened connection should be closed by the `close' method when it is no longer in use.

db.close();

To store a record, use the `set' method with the key and the value.

db.put("foo", "hop");

To retrieve the value of a record, use the `get' method with the key. On success, the return value is true and the result is assigned into the string object pointed to by the second parameter.

string value;
if (db.get("foo", &value)) {
  cout << value << endl;
}

Except for `set' and `get', there are other methods; `add', `replace', `append', `remove', `increment', and `cas'. Each method has two versions; for `std::string' parameters and for `char*' and `size_t' parameters.

Traversing records is a bit complicated task. It needs a cursor object, which expresses the current position in the sequence of all records in the database. Each cursor is created by the `cursor' method of the database object. Each cursor should be initialized by `jump' method before actual record operations.

RemoteDB::Cursor* cur = db.cursor();
cur->jump();

The cursor class has such methods against the record at the current position as `set_value', `remove', `get_key', `get_value', and `get'. Most methods have an optional stepping parameter to shift the current position to the next record atomically. Therefore, iterating such methods with the stepping parameter results in that all records are visited.

string ckey, cvalue;
while (cur->get(&ckey, &cvalue, NULL, true)) {
  cout << ckey << ":" << cvalue << endl;
}

Please see the the API documents for details. Writing your own sample application is the best way to learn this library.

Scripting Extension

If you configured Kyoto Tycoon with the "--enable-lua" option, the scripting extension by Lua is available. The following is an example code to define a simple operation to store a record.

kt = __kyototycoon__
db = kt.db

function set(inmap, outmap)
   local key = inmap.key
   local value = inmap.value
   if not key or not value then
      return kt.RVEINVALID
   end
   local xt = inmap.xt
   if not db:set(key, value, xt) then
      return kt.RVEINTERNAL
   end
   return kt.RVSUCCESS
end

If you save the above code as "test.lua", you can embed the operation by stating the server as the following.

$ ktserver -scr test.lua

To call the operation, execute the following command.

$ ktremotemgr script set key japan value japan xt 60

See the specification of the scripting extension for more details. If you edit the script file and want to make the server reload it, send the `SIGUSR1' signal to the server. If the server is a daemon, sending the `SIGHUP' signal causes the same effect.


Tips and Hacks

This section describes tips and hacks to use Kyoto Tycoon.

Typical Server Setting

On the assumption that you runs the server of Kyoto Tycoon on an machine with 16GB main memory and stores 10 million records into a file hash database, the following setting is suggested.

$ ktserver -port 1978 -tout 10 \
  -log /var/data/ktserver.log -ls \
  -dmn -pid /var/data/ktserver.pid \
  '/var/data/casket.kch#opts=l#bnum=20000000#msiz=12g#dfunit=8'

To improve performance, the bucket number of the hash table by the "bnum" parameter should be two times or more of the number of records. The size of mapped memory by the "msiz" parameter should be largest as far as the main memory is available. The unit number of automatic defragmentation by the "dfunit" parameter should be about 8 which means every eight detected fragmentations causes a series of automatic defragmentation steps. If you want higher availability at the cost of performance, using automatic transaction by the "-oat" option is a good idea. For details about database tuning, see the tips of Kyoto Cabinet.

The option "-dmn" switches the process into the background, which is called daemon. To stop or restart a daemon process, the PID files should be specified by the "-pid" option. The PID file contains the process ID by which you can send signals.

By default, verbose log messages are output and printed into the standard output. For usual use case, the "-ls" option which filters them is suggested. The "-log" option specifies the file to store log messages.

To stop the above daemon process, execute the following command.

$ kill -TERM `cat /var/data/ktserver.pid`

To rotate the log file of the above daemon process, execute the following command.

$ mv -f /var/data/ktserver.log /var/data/ktserver.log.`date '+%Y%M%d%H%M%S'`
$ kill -HUP `cat /var/data/ktserver.pid`

On-memory Server Setting

You can use Kyoto Tycoon as a volatile (not persistent) cache server with an on-memory database. In most cases, space efficiency of Kyoto Tycoon is better than that of memcached. If it is expected that 10 million records are cached in the database using 10GB memory, the following setting is suggested.

$ ktserver ':#bnum=20000000#ktcapsiz=10g'

Note that the capacity tuning parameter limits the total size of memory allocation in the "user land" layer. So, actual memory usage will be probably higher than the limit size. For peaceful operation, the limit should be up to 65% of the total memory size of the machine.

In addition, automatic deletion by the capacity limit is performed at random. In that case, fresh records may also be deleted soon. So, setting effectual expiration time not to reach the limit is very important. If you cannot calculate effectual expiration time beforehand, use the cache hash database instead of the default stash database. The following setting is suggested.

$ ktserver '*#bnum=20000000#capsiz=8g'

Note that the space effiency of the cache hash database is worse than that of the stash database. The limit should be up to 50% of the total memory size of the machine. However, automatic deletion by the "capsiz" parameter (not "ktcapsiz") of the cache hash database is based on LRU algorithm, which prevents fresh records from sudden deletion.

Background Snapshot for On-memory Databases

Kyoto Tycoon supports the "background snapshot" mechanism for on-memory databases. This mechanism is similar to the one in Redis. If background snapshot is enabled, the server saves all records in on-memory databases into files in a directory periodically. Because snapshot operations are performed in background by child processes forked from the server process, any foreground operation called by clients is not blocked. Due to the copy-on-write memory mechanism by the operating system, each snapshot operation is performed atomically in logical view.

Snapshot files are saved in a directory specified when the server starts. Each snapshot operation runs periodically by the given interval and additionally when the server finishes. If there are snapshot files when the server starts, they are read and all records are restored. The following setting is an example.

$ ktserver -bgs mysnap -bgsi 30

Insert some records and wait for 30 seconds. Then you'll see a snapshot file named "00000000.ktss" in the "mysnap" directory.

$ ktremotemgr set france paris
$ ktremotemgr set germany berlin

Terminate the server by Ctrl-C and restart the server.

$ ktserver -bgs mysnap -bgsi 30

Make sure that the records before termination were restored.

$ ktremotemgr list -pv
germany berlin
france  paris

Because snapshot data are serialized in an compact format and the IO operations are in sequential order, the IO loading of the underlying storage device is much lower than those in file databases. In order to lower the IO loading at the cost of CPU time, you can use a compression algorithm by the "-bgsc" option. The supported compression algorithms are "zlib", "lzo" and , "lzma", although the latter two are optional support when building Kyoto Cabinet. Probably, using "lzo" is a good choice for most use cases.

Inside Expiration

The timed database is a database type of wrapper of the polymorphic database of Kyoto Cabinet. The value of each record in the timed database has the 5 bytes prefix to contain the expiration time in seconds from the epoch. When a database operation accesses a record, the current time and the expiration time of the record is compared. If the former is larger, the record is regarded as expired.

In order to eliminate or reuse regions of expired records, the timed database has an implicit cursor called "GC cursor". Every several updating operations have the GC cursor scan the database gradually. If a scanned record has been expired, the record is removed and its region is registered to the reusable list. When the GC cursor reaches the end of the database, the tail end unused regions are discarded and the size of the database file is reduced. Thus, meta data such as "count" and "size" have latency from the current status.

The above algorithm means that the GC cursor does not work while the database is not being updated. However, while the server is idle, the GC cursor works implicitly so that the database keeps compact. Moreover, If you want to cause the full GC operation explicitly, you can call the "vacuum" procedure.

$ ktremotemgr vacuum

If you use Kyoto Tycoon not for cache but for data storage, create the database with the persistent option by "#ktopts=p" parameter to disable the GC cursor and omit the time stamp region of each record, for the sake of time and space efficiency. Note that the persistent option works when creating a database and it does not work for existing databases.

If you want to manage a database without the persistent option directly on a local machine, use the `kttimedmgr' command. Do not use commands of Kyoto Cabinet such as `kchashmgr' and `kcpolymgr' for that purpose. If you managed Tycoon's "timed" database by Cabinet's command, you would see 5-byte garbage at the beginning of each record. If you managed Cabinet's "normal" database by Tycoon's command, you couldn't see the first 5-bytes data.

Signal Waiting and Sending

The signal mechanism is useful to monitor a record to be updated. Every RPC call can wait for a signal before its operation and can send a signal after its operation. Each signal is binded to a named condition variable. If you want to retrieve the new value of a record "hello" immediately after a signal is sent to "hello", execute the following code. Although you can use a different name of the condition variable from the key of a record to be monigored, using the same strings is straightforward.

db.set_signal_waiting("hello", 60);
string value;
db.get("hello", &value);

You can do the same thing by the following command line.

$ ktremotemgr get -swname hello -swtime 60 hello

If you want to update the record "hello" and then send a signal to "hello", execute the following code.

db.set_signal_sending("hello", true);
db.set("hello", "world");

You can do the same thing by the following command line.

$ ktremotemgr set -ssname hello -ssbrd hello world

The signal mechanism is useful to realize a job queue as well. In that case, you should choose one of B+ tree databases as its storage and store job data whose keys are time stamps so that records are always sorted in the accending order of time stamps. Task producers are to store task data and send a signal for each operation. Each task workers is to wait for a signal and then retrieve the first record in the queue. If you want a single queue on a server, use an empty string as the signal name. If you want plural queues on a server, open plural databases to match the queues and use different signal names to distinguish task kinds.

Note that an RPC call waiting for a signal occupies the thread during its operation. So, it should be avoided that an unspecified number of clients wait for signals. The signal mechanism should be used only for monitoring records by a few specified clients.

Hot Backup

You can make backup files while the server is running, which is called "hot backup". To do it, prepare the following shell script beforehand and save it as "/ktbin/dbbackup". It must have executable permissions.

#! /bin/sh
srcfile="$1"
destfile="$1.$2"
cp -f "$srcfile" "$destfile"

Run the server specifying the command search path "/ktbin".

$ ktserver -cmd /ktbin casket.kch

When you want to make a backup file, execute the following command to call the backup script.

$ ktremotemgr sync -cmd dbbackup

The "sync" sub command of the client utility makes the database synchronize, which means dirty buffers on memory are written into the database file. If the "-cmd" option is specified, an outer command is executed with two arguments. The first argument is the path of the database file. The second argument is the current time stamp. You can call arbitrary scripts other than the above sample. Using "snapshot" mechanism of the underlying operating system is a good idea to shorten the time to make a backup file.

Update Logging

Even if you take hot backup a day, update operations in 24 hours at most might be lost when an accident occurred. "update log" is provided to compensate for such data loss. It keeps track of every update operation in "record-base" model, which is called "row-base" in the context of RDBMS. You can recover the database entirely by applying update logs to the latest backup database file.

Run the server with update logging enabled. The "-ulog" option specifies the directory to contain the update log files. The "-sid" option specifies the server ID between 0 to 65535. The "-cmd" option enables hot backup by the above instruction.

$ ktserver -ulog 0001-ulog -sid 1 casket.kch -cmd /ktbin casket.kch

Insert some records.

$ ktremotemgr set one first
$ ktremotemgr set two second

Take a backup file.

$ ktremotemgr sync -cmd dbbackup

Insert more records.

$ ktremotemgr set three third
$ ktremotemgr set four fourth

Terminate the server by Ctrl-C and remove the database to simulate database crash.

$ rm casket.kch

Recover the database by applying update logs. "xxx..." means the time stamp of the backup database file. The "-ts" option specifies the time stamp until which old update logs are skipped.

$ cp casket.kch.xxxxxxxxxxxxxxxxxxxx casket.kch
$ kttimedmgr recover -ts xxxxxxxxxxxxxxxxxxxx casket.kch 0001-ulog
.. (2)

Confirm the records in the recovered database.

$ kttimedmgr list -pv casket.kch
one     first
two     second
three   third
four    fourth

Update logs are saved in respective files by constant size, which is 256MB by default. After you take a backup database file, you can remove older update logs than the time stamp of the backup database file. The command "ktremotemgr slave -uf" prints the size and the maximum time stamp in each update log file.

$ ktremotemgr slave -uf
0001-ulog/0000000001.ulog       268459706       1293335993793000167
0001-ulog/0000000002.ulog       268466346       1293336035697000149
0001-ulog/0000000003.ulog       268477224       1293336080897000091
0001-ulog/0000000004.ulog       268456392       1293336132156000021
0001-ulog/0000000005.ulog       101109851       1293336145396000029

You can remove old log files by the command "ktremotemgr slave -ur". The "-ts" option specifies the maximum time stamp of disposable logs. If the time stamp is not specified, all log files except for the current one are removed.

$ ktremotemgr slave -ur -ts 1293336080897000091

Asynchronous Replication

Even if you take hot backup and update logs, all data might be lost when the storage device or the computer itself broke down. Keep in mind that nothing is eternal. To overcome such critical situation, data replication is supported. It is a mechanism to synchronize two or more database servers for high availability and high integrity. The replication source server is called "master" and each destination server is called "slave". Replication requires the following preconditions.

  • The master must record the update log.
  • The master must specify the unique server ID.
  • Each slave must record the update log because it may become the master when fail over.
  • Each slave must specify the unique server ID because of the same reason.
  • Each slave must specify the address and the port number of the master server.
  • Each slave must specify the replication time stamp file.

This section describes how to set up one master at port 1978 and one slave at port 1979 replication. First, run the master server.

$ ktserver -port 1978 -ulog 0001-ulog -sid 1 casket-0001.kch

Next, run the slave server.

$ ktserver -port 1979 -ulog 0002-ulog -sid 2 \
  -mhost localhost -mport 1978 -rts 0002.rts casket-0002.kch

Insert some records into the master.

$ ktremotemgr set -port 1978 one first
$ ktremotemgr set -port 1978 two second

Check consistency of stored records in the master and the slave.

$ ktremotemgr list -port 1978 -pv
one     first
two     second
$ ktremotemgr list -port 1979 -pv
one     first
two     second

Simulate the case that the master is crashed. Terminate the master by Ctrl-C and remove the database file.

$ rm casket-0001.kch

Terminate the slave by Ctrl-C and restart it as the new master.

$ ktserver -port 1979 -ulog 0002-ulog -sid 2 casket-0002.kch

Add a new slave at port 1980.

$ ktserver -port 1980 -ulog 0003-ulog -sid 3 \
  -mhost localhost -mport 1979 -rts 0003.rts casket-0003.kch

Check consistency of stored records in the new master and the new slave.

$ ktremotemgr list -port 1979 -pv
one     first
two     second
$ ktremotemgr list -port 1980 -pv
one     first
two     second

Because the master server uses a dedicated worker thread for each connection to slave, the number of worker threads should be increased if you set several slave servers.

Dual-Master Topology

Kyoto Tycoon supports "dual master" replication topology which realizes higher availability. It means that two servers replicate each other so that you don't have to restart the survivor when one of them crashed.

This section describes how to set up two masters called A and B which replicate each other. First, run the server A.

$ ktserver -port 10001 -ulog 0001-ulog -sid 1 \
  -mhost localhost -mport 10002 -rts 0001.rts casket-0001.kch

Next, run the server B.

$ ktserver -port 10002 -ulog 0002-ulog -sid 2 \
  -mhost localhost -mport 10001 -rts 0002.rts casket-0002.kch

Insert some records into the server A.

$ ktremotemgr set -port 10001 one first
$ ktremotemgr set -port 10001 two second

Insert some records into the server B.

$ ktremotemgr set -port 10002 three third
$ ktremotemgr set -port 10002 four fourth

Check consistency of stored records in the two servers.

$ ktremotemgr list -port 10001 -pv
one     first
two     second
three   third
four    fourth
$ ktremotemgr list -port 10002 -pv
one     first
two     second
three   third
four    fourth

Simulate the case that the server A is crashed. Terminate the server A by Ctrl-C and remove the database file.

$ rm casket-0001.kch

Run a new server called C which replicates the server B.

$ ktserver -port 10003 -ulog 0003-ulog -sid 3 \
  -mhost localhost -mport 10002 -rts 0003.rts casket-0003.kch

Modify the replication configuration of the server B to replicate the server C.

$ ktremotemgr tunerepl -port 10002 -mport 10003 localhost

Insert some records into the server C.

$ ktremotemgr set -port 10003 five fifth
$ ktremotemgr set -port 10003 six sixth

Check consistency of stored records in the current servers.

$ ktremotemgr list -port 10002 -pv
one     first
two     second
three   third
four    fourth
five    fifth
six     sixth
$ ktremotemgr list -port 10003 -pv
one     first
two     second
three   third
four    fourth
five    fifth
six     sixth

Of course, using a backup database file to apply "difference recovery" instead of "full recovery" when adding a new server is a good idea. To apply difference recovery, specify the time stamp of the backup database file with the "-ts" option of the "ktremotemgr tunerepl" command.

Note that updating both of the servers at the same time might cause inconsistency of their databases. That is, you should use one master as a "active master" and the other as a "standby master".

Replication with Background Snapshot

Snapshot files of on-memory databases can be used as backup files. And, you use them in order to set up replication slave servers. First, run a master server handling an on-memory database.

$ ktserver -port 10001 -ulog 0001-ulog -sid 1 \
  -bgs 0001-bgs -bgsi 60 ':#bnum=10000000#ktopts=p'

Insert some records into the master server.

$ ktremotemgr setbulk -port 10001 one first two second

Wait for 60 seconds and then make sure that the above two records are saved in the snapshot file. The second field expresses the time stamp of the snapshot. The third field expresses the number of records.

$ kttimedmgr bgsinform 0001-bgs
0       1295607805662000000     2       94906353

Copy the snapshot directory as another one. Then, extract the time stamp and generate the RTS file for the slave server.

$ cp -r 0001-bgs 0002-bgs
$ kttimedmgr bgsinform 0001-bgs | cut -f 2 < 0002.rts

Start the slave server.

$ ktserver -port 10002 -sid 2 \
  -bgs 0002-bgs -bgsi 60 -mhost localhost -mport 10001 -rts 0002.rts \
  ':#bnum=10000000#ktopts=p'

Of cource, you can also set up dual master replicatoin of on-memory databases. It realizes extremely fast and enough robust database solution.

Pluggable Server

If you want other protocols except for HTTP, the "pluggable server" mechanism is useful. The server can load a shared library which implements arbitrary network services and operate database objects shared by the main server. The shared library "ktplugservmemc.so" installed under "/usr/local/libexec" implements the memcached protocol. The following command starts the normal server at the default port 1978 and starts the pluggable server for the memcached protocol at another port 2001 simultaneously. If your application doesn't access the main server, the number of the main thread should be set 1 by specifying "-th 1".

$ ktserver -th 1 -plsv /usr/local/libexec/ktplugservmemc.so -plex 'port=2010'

Confirm the functionality by the telnet command.

$ telnet localhost 2010
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
set japan 0 0 5
tokyo
STORED
get japan
VALUE japan 0 5
tokyo
END
quit
Connection closed by foreign host.

This implementation supports a portion of commands supported by the original memcached server. As for now, "set", "add", "replace", "get", "delete", "incr", "decr", "stats", "flush_all", and "quit" are available. For the sake of interoperability with HTTP, the "flags" option of some update commands are ignored by default. If you want to handle the flags, enable the mechanism by adding "#opts=f" in the argument of the "-plex" option. The mechanism of "cas unique" is not implemented.

The configuration expression by the "-plex" option is composed of named parameters separated by "#". Each parameter is composed of the name and the value separated by "=". The supported parameter names are "host", "port", "tout", "th", and "opts". The default port is 11211, which is the same as the original memcached server. Don't forget "#opts=f" if your client library uses "flags" to determine the data type of each record. By default, "flags" are disabled for compatibility of the record format to HTTP.

The most important advantage of the pluggable server mechanism is to share database objects with the main server. Update operations by a pluggable server is reflected to the main server immediately and vice versa. Moreover, update operations are written as update logs and picked up by slave servers of replication. You can implement your own pluggable server. See the source code in "ktplugservmemc.cc" for details.

Pluggable Database

If you want other database implementations except for Kyoto Cabinet, the "pluggable database" mechanism is useful. The server can load a shared library which implements arbitrary storage services conforming to the interface of associative array. The shared library "ktplugdbvoid.so" installed under "/usr/local/libexec" implements the "void database" mechanism, which is similar to "blackhole storage engine" of MySQL. It is so-called "no-op" database and do nothing except for writing update logs. It is useful to get rid of the load of the master server and level the load in the time axis. The following command starts the replication master server opening a void database.

$ ktserver -port 1978 -ulog 0001-ulog -sid 1 -pldb /usr/local/libexec/ktplugdbvoid.so

The following command starts the replication slave server opening a file hash database.

$ ktserver -port 1979 -sid 2 -mhost localhost -mport 1978 -rts 2.rts casket.kch

Store a record into the master server and confirm that the record is discarded.

$ ktremotemgr set -port 1978 foo bar
$ ktremotemgr get -port 1978 foo
ktremotemgr: DB::get failed: :1978: 3: logical inconsistency: DB: 7: no record: no record

Confirm that the record exists in the database of the slave server.

$ ktremotemgr get -port 1979 foo
bar

The most important advantage of the pluggable database mechanism is to give networking functionality to other DBM-style database libraries such as BerkeleyDB and GDBM. You can implement your own pluggable database. See the source code in "ktplugdbvoid.cc" for details.

Slave Agent

If you want to replicate update operations from a server of Kyoto Tycoon to another database system like RDBMS, it is useful to pull update logs by the command "ktremotemgr slave" and process each log by your own script command. The master server setting is not particular.

$ ktserver -ulog 0001-ulog -sid 1 casket.kch

To generate update logs in the master server, perform some opdate operations.

$ ktremotemgr clear
$ ktremotemgr set one first
$ ktremotemgr set two second
$ ktremotemgr remove one

Pull the above update logs.

$ ktremotemgr slave
1293014011013000000     1       0       clear
1293014017613000000     1       0       set     b25l    //////9maXJzdA==
1293014022052000000     1       0       set     dHdv    //////9zZWNvbmQ=
1293014027262000000     1       0       remove  b25l

The output is in TSV format. Each line expresses each update operation. The fields are the time stamp of the update operation, the server ID number, the database ID number, the command name, and Base64-encoded arguments of the command. The first 5 bytes in the value of the "set" command specifies the expiration time. You can give the output to another command for post processing via pipe.

$ ktremotemgr slave -ts "`cat sometime.rts`" -uw | dosomething

The file "sometime.rts" should contain the time stamp of the last pulled update log, which should be recorded by the post processing command. The "-uw" option is to wait for future update logs forever even when the reader has reached the end of the log files. A sample implementation of a post processing command in Ruby is included as "example/ktreplprint.rb" in the source package.

Message Queue over Memcached Protocol

The memcached pluggable server can work as a message queue server. If the database is one of tree databases (GrassDB, TreeDB, ForestDB) and the "#opts=q" option is specified, behaviors of "set", "get", and "delete" are overwritten. The default timeout of "get" is 10 seconds and it can be modified by the "qtout" option. The following is a typical configuration.

$ ktserver -th 1 -plsv /usr/local/libexec/ktplugservmemc.so \
  -plex 'port=11211#opts=fq#qtout=5' 'casket.kct#ktopts=p'

Some clients can store messages with arbitrary keys. Messages are organized by names in the accending order of time stamps. Some clients can fetch messages with arbitrary keys. Fetched messages are hidden atomically in order to avoid race condition. So, multiple clients can monitor the same key simultaneously. If a client has done with a message, he should delete the message explicitly. If a client closes the connection witout deleting messages he fetched, those message are registered into the database implicitly. So, even if a client dies unexpectedly, no message won't be lost.

A typical client to write messages, called "job producer", is implemented like the following pseudo-code.

memc = Memcached::connect("localhost", 11211)
memc.set("foo", jobdata)

A typical client to read messages, called "job worker", is implemented like the following pseudo-code.

memc = Memcached::connect("localhost", 11211)
while (true) {
  value = memc.get("foo")
  if (value) {
    if (do_something(value)) {
      memc.delete("foo")
    }
  }
}

"set" and "get" operations are synchronized by the singal mechanism. When there is no message corresponding to the specified key, the "get" method blocks for 10 seconds or until a corresponding record is stored. So, the event loop of job workers does not cause useless network traffic or latency as in busy "polling" model.


Protocol

This section describes detail specifications of the protocol of Kyoto Tycoon.

Overview

The server program of Kyoto Cabinet communicates with clients by HTTP. Although the default service port number is 1978, it can be changed by setting. The server understands requests of HTTP/1.0 and HTTP/1.1 and sends responses corresponding to each request.

If the request is HTTP/1.1 and the value of the "Content-Type" header is not "close", the server try to perform keep-alive connection. Keep-alive connection is strongly suggested to access the server for performance reason. However, usual intermissive connection is also allowed for legacy clients.

Kyoto Cabinet uses an RPC model called TSV-RPC, which is similar to XML-RPC but uses TSV rather than XML. Although TSV is inferior to XML in terms of expressive ability, TSV is superior to XML in terms of simplicity, space efficiency, and processing effectiveness.

TSV-RPC

TSV-RPC is a client-server modeled synchronous RPC protocol over HTTP. The following pseudo code is the common interface of each procedure. TSV is used to serialize the input data and the output data.

int call(String name, StringMap inmap, StringMap outmap);

Each procedure has its entry point under the path "/rpc/" of URL. For example the entry point of the command "set" is "/rpc/set". Clients call each command by the POST method specifying the entry point. Each procedure receives the input data of an associative array composed of key/value string records. The associative array is expressed by the entity body formatted in TSV text. Each line expresses a record. The first column is the key and the second column is the value. The value of the "Content-Type" header must be "text/tab-separated-values". The following is a typical request message.

POST /rpc/set HTTP/1.1
Host: localhost:1978
Content-Type: text/tab-separated-values
Content-Length: 22

key     japan
value   tokyo

If a column includes one or more special characters such as tab, line-feed, and control characters, every column must be encoded by one of the following algorithms.

  • Base64 encoding: colenc=B
  • Quoted-printable: colenc=Q
  • URL encoding: colenc=U

The encoding name must be described as an attribute of the value of the Content-Type header. The following is a typical request message with encoded TSV data.

POST /rpc/hello HTTP/1.1
Host: localhost:1978
Content-Type: text/tab-separated-values; colenc=B
Content-Length: 24

aWQ=    MTIzNDU=
YWdl    MzE=

As a facile method, clients can send the input data by the entity body in HTML-form format. That is, the key and the value of a record are encoded respectively in URL encoding and they are concatenated with the "=" character. All serialized record expressions are concatenated with the "&" character. The value of the Content-Type header is "application/x-www-form-urlencoded". The following is a typical request with HTML-form data.

POST /rpc/goodbye HTTP/1.1
Host: localhost:1978
Content-Type: application/x-www-form-urlencoded
Content-Length: 31

id=1234&name=%e5%b9%b9%e9%9b%84

As a more facile method, clients can use the GET method and specify the input data as the query string with the target path. The following is an example.

GET /rpc/paint?color=red&x=30&y=20 HTTP/1.1
Host: localhost:1978

Clients can select one of TSV, HTML-form, and query string arbitrarily. However, not that the query string has limit of length, which is 8192 bytes as for Kyoto Tycoon. TSV with Base64 encoding is recommended for arbitrary string and binary data because its space efficiency is the best of the three formats.

After receiving a request, the server send the result of computation in the response. The status code of HTTP is one of the follwoing.

  • 200: the procedure was done successfully.
  • 400: the format of the request was invalid or the arguments are short for the called procedure.
  • 450: the procedure was done but the result did not fulfill the application logic.
  • 500: the procedure was aborted by fatal error of the server program or the environment.
  • 501: the specified procedure is not implemented.
  • 503: the procedure was not done within the given time so aborted.

200 and 450 is in normality. 400 indicates bugs in the client side. 500 indicates bugs in the server side. 501 is in the literature.

If the status code is 200, the output data of the procedure is sent as the entity body of the response message. The output data is also an associative array composed of key/value string records. The format rules are the same as the ones of the input data. The following is a typical response message.

HTTP/1.1 200 OK
Content-Type: text/tab-separated-values; colenc=U
Content-Length: 25

value   %e5%b9%b3%e6%9e%97

If the status code is other than 200, error information is sent as the entity body of the response message. It is an assiciative array including one record whose key is "ERROR" and value is the error message. The following is an example.

HTTP/1.1 501 Not Implemented
Content-Type: text/tab-separated-values
Content-Length: 24

ERROR   no such procedure

The server select the best encoding by scanning the output data. That is, raw data is selected if encoding is not needed. URL encoding is selected if ASCII characters are relatively many. Base64 is selected in the other cases. Because Quoted-printable is never selected by the server, clients don't have to implement it.

Common Arguments

The input data of each procedure can be regarded as named paramters. Although each procedure needs various parameters different with each other, there are common arguments used by several procedures.

Remember that the server can handle multiple databases at the same time. Opened databases are distinguished by their ID numbers from 0 to N-1 in the order of the command line arguments. By default, the first database whose ID number is 0 is selected. The "DB" parameter specifies the identifier of the target database of each operation. If the identifier starts with a number, it is treated as the ID number. Otherwise, it is treated as a database name. The name of each database is made of the file name after the last "/" character of the path. The following example stores a record into the database named "phone_db.kch".

POST /rpc/set HTTP/1.1
Host: localhost:1978
Content-Type: text/tab-separated-values
Content-Length: 47

DB      phone_db.kch
key     09012345678
value   John Doe

While keep-alive connection, clients can use cursor objects. Each cursor has the ID number from 0 to 2^63. Because each connection has a separate name space with each other, the same ID number can be used among different connections. The cursor ID is specified by the "CUR" parameter. If an unknown ID is specified, a new cursor with the ID numger is created. The following example creates a cursor whose ID is 8 and sets its position to the record whose key is "mikio".

POST /rpc/cur_jump HTTP/1.1
Host: localhost:1978
Content-Type: text/tab-separated-values
Content-Length: 32

DB      staff_db.kch
CUR     8
key     mikio

Cursur objects can be reused in the same connection by specifying the ID number. When each connection is closed, cursor objects created while the connection are destroyed automatically and related resources are cleaned-up.

Every procedure can wait for a signal by a named condition variable before the procedure is performed. If the "WAIT" parameter is specified, the thread waits for a condition variable whose name is the value of the parameter. Although the default timeout is 30 second, it can be modified by the "WAITTIME" parameter. If any signal is sent within the given time, the procedure is aborted. The following example waits for updating a record for up to 10 seconds and then get the new value.

GET /rpc/get HTTP/1.1
Host: localhost:1978
Content-Type: text/tab-separated-values
Content-Length: 34

WAIT    summer
WAITTIME        8
key     summer

Moreover, every procedure can send a signal to a thread waiting by a named condition variable after the procedure is performed. If the "SIGNAL" parameter is specified, a signal is sent to a thread waiting by a named condition variable whose name is the value of the parameter. If the "SIGNALBROAD" parameter is specified at the same time, the signal is sent to every corresponding thread. If a signal is sent, the response includes the paramter "SIGNALED", which expresses the number of threads waiting for the signal. The following example stores a record and then sends a signal to every thread waiting for a condition variable.

GET /rpc/set HTTP/1.1
Host: localhost:1978
Content-Type: text/tab-separated-values
Content-Length: 52

SIGNAL  summer
SIGNALBROAD
key     summer
value   sailing

Procedures

The server provides the following procedures.

/rpc/void
Do nothing, just for testing.
status code: 200.
/rpc/echo
Echo back the input data as the output data, just for testing.
input: (optional): arbitrary records.
output: (optional): corresponding records to the input data.
status code: 200.
/rpc/report
Get the report of the server information.
output: (optional): arbitrary records.
status code: 200.
/rpc/play_script
Call a procedure of the script language extension.
input: name: the name of the procedure to call.
input: (optional): arbitrary records whose keys trail the character "_".
output: (optional): arbitrary keys which trail the character "_".
status code: 200, 450 (arbitrary logical error).
/rpc/tune_replication
Set the replication configuration.
input: host: (optional): the name or the address of the master server. If it is omitted, replication is disabled.
input: port: (optional): the port numger of the server. If it is omitted, the default port is specified.
input: ts: (optional): the maximum time stamp of already read logs. If it is omitted, the current setting is not modified. If it is "now", the current time is specified.
input: iv: (optional): the interval of each replication operation in milliseconds. If it is omitted, the current setting is not modified.
status code: 200.
/rpc/status
Get the miscellaneous status information of a database.
input: DB: (optional): the database identifier.
output: count: the number of records.
output: size: the size of the database file.
output: (optional): arbitrary records for other information.
status code: 200.
/rpc/clear
Remove all records in a database.
input: DB: (optional): the database identifier.
status code: 200.
/rpc/synchronize
Synchronize updated contents with the file and the device.
input: DB: (optional): the database identifier.
input: hard: (optional): for physical synchronization with the device.
input: command: (optional): the command name to process the database file.
status code: 200, 450 (the postprocessing command failed).
/rpc/set
Set the value of a record.
input: DB: (optional): the database identifier.
input: key: the key of the record.
input: value: the value of the record.
input: xt: (optional): the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
status code: 200.
/rpc/add
Add a record.
input: DB: (optional): the database identifier.
input: key: the key of the record.
input: value: the value of the record.
input: xt: (optional): the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
status code: 200, 450 (existing record was detected).
/rpc/replace
Replace the value of a record.
input: DB: (optional): the database identifier.
input: key: the key of the record.
input: value: the value of the record.
input: xt: (optional): the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
status code: 200, 450 (no record was corresponding).
/rpc/append
Append the value of a record.
input: DB: (optional): the database identifier.
input: key: the key of the record.
input: value: the value of the record.
input: xt: (optional): the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
status code: 200.
/rpc/increment
Add a number to the numeric integer value of a record.
input: DB: (optional): the database identifier.
input: key: the key of the record.
input: num: the additional number.
input: orig: (optional): the origin number. If it is omitted, 0 is specified. "try" means INT64MIN. "set" means INT64MAX.
input: xt: (optional): the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
output: num: the result value.
status code: 200, 450 (the existing record was not compatible).
/rpc/increment_double
Add a number to the numeric double value of a record.
input: DB: (optional): the database identifier.
input: key: the key of the record.
input: num: the additional number.
input: orig: (optional): the origin number. If it is omitted, 0 is specified. "try" means negative infinity. "set" means positive infinity.
input: xt: (optional): the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
output: num: the result value.
status code: 200, 450 (the existing record was not compatible).
/rpc/cas
Perform compare-and-swap.
input: DB: (optional): the database identifier.
input: key: the key of the record.
input: oval: (optional): the old value. If it is omittted, no record is meant.
input: nval: (optional): the new value. If it is omittted, the record is removed.
input: xt: (optional): the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
status code: 200, 450 (the old value assumption was failed).
/rpc/remove
Remove a record.
input: DB: (optional): the database identifier.
input: key: the key of the record.
status code: 200, 450 (no record was found).
/rpc/get
Retrieve the value of a record.
input: DB: (optional): the database identifier.
input: key: the key of the record.
output: value: (optional): the value of the record.
output: xt: (optional): the absolute expiration time. If it is omitted, there is no expiration time.
status code: 200, 450 (no record was found).
/rpc/check
Check the existence of a record.
input: DB: (optional): the database identifier.
input: key: the key of the record.
output: vsiz: (optional): the size of the value of the record.
output: xt: (optional): the absolute expiration time. If it is omitted, there is no expiration time.
status code: 200, 450 (no record was found).
/rpc/seize
Retrieve the value of a record and remove it atomically.
input: DB: (optional): the database identifier.
input: key: the key of the record.
output: value: (optional): the value of the record.
output: xt: (optional): the absolute expiration time. If it is omitted, there is no expiration time.
status code: 200, 450 (no record was found).
/rpc/set_bulk
Store records at once.
input: DB: (optional): the database identifier.
input: xt: (optional): the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
input: atomic: (optional): to perform all operations atomically. If it is omitted, non-atomic operations are performed.
input: (optional): arbitrary records whose keys trail the character "_".
output: num: the number of stored reocrds.
status code: 200.
/rpc/remove_bulk
Store records at once.
input: DB: (optional): the database identifier.
input: atomic: (optional): to perform all operations atomically. If it is omitted, non-atomic operations are performed.
input: (optional): arbitrary keys which trail the character "_".
output: num: the number of removed reocrds.
status code: 200.
/rpc/get_bulk
Retrieve records at once.
input: DB: (optional): the database identifier.
input: atomic: (optional): to perform all operations atomically. If it is omitted, non-atomic operations are performed.
input: (optional): arbitrary keys which trail "_".
output: num: the number of retrieved reocrds.
output: (optional): arbitrary keys which trail the character "_".
status code: 200.
/rpc/vacuum
Scan the database and eliminate regions of expired records.
input: DB: (optional): the database identifier.
input: step: (optional): the number of steps. If it is omitted or not more than 0, the whole region is scanned.
status code: 200.
/rpc/match_prefix
Get keys matching a prefix string.
input: DB: (optional): the database identifier.
input: prefix: the prefix string.
input: max: (optional): the maximum number to retrieve. If it is omitted or negative, no limit is specified.
output: num: the number of retrieved keys.
output: (optional): arbitrary keys which trail the character "_". Each value specifies the order of the key.
status code: 200.
/rpc/match_regex
Get keys matching a ragular expression string.
input: DB: (optional): the database identifier.
input: regex: the regular expression string.
input: max: (optional): the maximum number to retrieve. If it is omitted or negative, no limit is specified.
output: num: the number of retrieved keys.
output: (optional): arbitrary keys which trail the character "_". Each value specifies the order of the key.
status code: 200.
/rpc/match_similar
Get keys similar to a string in terms of the levenshtein distance.
input: DB: (optional): the database identifier.
input: origin: the origin string.
input: range: (optional): the maximum distance of keys to adopt. If it is omitted or negative, 1 is specified.
input: utf: (optional): flag to treat keys as UTF-8 strings. If it is omitted, false is specified.
input: max: (optional): the maximum number to retrieve. If it is omitted or negative, no limit is specified.
output: num: the number of retrieved keys.
output: (optional): arbitrary keys which trail the character "_". Each value specifies the order of the key.
status code: 200.
/rpc/cur_jump
Jump the cursor to the first record for forward scan.
input: DB: (optional): the database identifier.
input: CUR: the cursor identifier.
input: key: (optional): the key of the destination record. If it is omitted, the first record is specified.
status code: 200, 450 (cursor is invalidated).
/rpc/cur_jump_back
Jump the cursor to a record for forward scan.
input: DB: (optional): the database identifier.
input: CUR: the cursor identifier.
input: key: (optional): the key of the destination record. If it is omitted, the last record is specified.
status code: 200, 450 (cursor is invalidated), 501 (not implemented).
/rpc/cur_step
Step the cursor to the next record.
input: CUR: the cursor identifier.
status code: 200, 450 (cursor is invalidated).
/rpc/cur_step_back
Step the cursor to the previous record.
input: CUR: the cursor identifier.
status code: 200, 450 (cursor is invalidated), 501 (not implemented).
/rpc/cur_set_value
Set the value of the current record.
input: CUR: the cursor identifier.
input: value: the value of the record.
input: step: (optional): to move the cursor to the next record. If it is omitted, the cursor stays at the current record.
input: xt: (optional): the expiration time from now in seconds. If it is negative, the absolute value is treated as the epoch time. If it is omitted, no expiration time is specified.
status code: 200, 450 (cursor is invalidated).
/rpc/cur_remove
Remove the current record.
input: CUR: the cursor identifier.
status code: 200, 450 (cursor is invalidated).
/rpc/cur_get_key
Get the key of the current record.
input: CUR: the cursor identifier.
input: step: (optional): to move the cursor to the next record. If it is omitted, the cursor stays at the current record.
status code: 200, 450 (cursor is invalidated).
/rpc/cur_get_value
Get the value of the current record.
input: CUR: the cursor identifier.
input: step: (optional): to move the cursor to the next record. If it is omitted, the cursor stays at the current record.
status code: 200, 450 (cursor is invalidated).
/rpc/cur_get
Get a pair of the key and the value of the current record.
input: CUR: the cursor identifier.
input: step: (optional): to move the cursor to the next record. If it is omitted, the cursor stays at the current record.
output: xt: (optional): the absolute expiration time. If it is omitted, there is no expiration time.
status code: 200, 450 (cursor is invalidated).
/rpc/cur_seize
Get a pair of the key and the value of the current record and remove it atomically.
input: CUR: the cursor identifier.
output: xt: (optional): the absolute expiration time. If it is omitted, there is no expiration time.
status code: 200, 450 (cursor is invalidated).
/rpc/cur_delete
Delete a cursor implicitly.
input: CUR: the cursor identifier.
status code: 200, 450 (cursor is invalidated).

RESTful interface

While the procedure name is described in the URL in the above RPC-style interface, it is specified by the kind of method such as GET, HEAD, PUT, DELETE in the RESTful-style interface. And, the objective record is described in the URL. Because a lot of users prefers RESTful-style interface to RPC-style one, Kyoto Tycoon supports the both. The following methods are used in the RESTful-style interface.

GET
Retrieve the value of a record.
request path: the key of the record.
response header: Content-Length: the size of the value.
response header: X-Kt-Xt: (optional): the absolute expiration time. If it is omitted, there is no expiration time.
response entity body: the value of the record.
status code: 200, 404 (no record was found).
HEAD
Retrieve the value of a record.
request path: the key of the record.
response header: Content-Length: the size of the value.
response header: X-Kt-Xt: (optional): the absolute expiration time. If it is omitted, there is no expiration time.
status code: 200, 404 (no record was found).
PUT
Set the value of a record.
request path: the key of the record.
request header: Content-Length: the size of the value.
request header: X-Kt-Mode: (optional): the method mode. "set", "add", and "replace" are supported. If it is omitted, "set" is specified.
request header: X-Kt-Xt: (optional): the absolute expiration time. If it is omitted, no expiration time is specified.
request entity body: the value of the record.
status code: 201.
DELETE
Remove a record.
request path: the key of the record.
status code: 204, 404 (no record was found).

The space efficiency of RESTful-style interface is superior to the one of RPC-style interface because the entity body does not have any data structure and no encoding is needed.

The path of the URL in the request line must be encoded by URL encoding. If the path begins with "/", the character is ignored and the trailing string is decoded. Moreover, if the path includes "/" in the middle, the segment before the middle "/" is treated as the database identifier and the next segment is decoded as the key. For example, the record whose key is "I love you" in the database "words.kch" is expressed "/words.kch/I%20love%20you" in the request line.

The format of date strings by the "X-Kt-Xt" header is the RFC 1123 date format of GMT. The server understands the W3CDTF format, the RFC 822 (1123) format, and the decimal integer of seconds from the epoch.

Binary Protocol

In order to realize the best performance, several commands in an efficient binary protocol are supported. As they are available at the same port as other HTTP commands, they can be identified by the first one byte of each request. Every numeric value are expressed in big-endian order. If some error occurred in the server, the magic data of the output would be 0xBF and no data trails.

replication
Continue to send update logs.
input: magic: (uint8_t): 0xB1: identifier.
input: flags: (uint32_t): flags of bitwise-or. 0x01 for the while SID option.
input: ts: (uint64_t): the maximum time stamp of already read logs.
input: sid: (uint16_t): the server ID number.
output: magic: (uint8_t): 0xB1: identifier.
output: ts: (uint64_t): (iteration): the time stamp of the log.
output: size: (uint32_t): (iteration): the size of the log.
output: log: (variable): (iteration): the data of the log.
note: The magic data of the output can be 0xB0. It means that the log reader has reached the current status and been waiting for the next update. In this case, the current time stamp of uint64_t trails the magic data. Clients must respond and send a one-byte message of 0xB1.
play_script
Call a procedure of the script language extension.
input: magic: (uint8_t): 0xB4: identifier.
input: flags: (uint32_t): flags of bitwise-or. 0x01 for the no-reply option.
input: nsiz: (uint32_t): the size of the procedure name.
input: rnum: (uint32_t): the number of the records in the request.
input: name: (variable): the data of the procedure name.
input: ksiz: (uint32_t): (iteration): the size of the key.
input: vsiz: (uint32_t): (iteration): the size of the value.
input: key: (variable): (iteration): the data of the key.
input: value: (variable): (iteration): the data of the value.
output: magic: (uint8_t): 0xB4: identifier.
output: rnum: (uint32_t): the number of the result records.
output: ksiz: (uint32_t): (iteration): the size of the key.
output: vsiz: (uint32_t): (iteration): the size of the value.
output: key: (variable): (iteration): the data of the key.
output: value: (variable): (iteration): the data of the value.
set_bulk
Store records at once.
input: magic: (uint8_t): 0xB8: identifier.
input: flags: (uint32_t): flags of bitwise-or. 0x01 for the no-reply option.
input: rnum: (uint32_t): the number of records in the request.
input: dbidx: (uint16_t): (iteration): the index of the target database.
input: ksiz: (uint32_t): (iteration): the size of the key.
input: vsiz: (uint32_t): (iteration): the size of the value.
input: xt: (int64_t): (iteration): the expiration time.
input: key: (variable): (iteration): the data of the key.
input: value: (variable): (iteration): the data of the value.
output: magic: (uint8_t): 0xB8: identifier.
output: hits: (uint32_t): the number of stored records.
remove_bulk
Remove records at once.
input: magic: (uint8_t): 0xB9: identifier.
input: flags: (uint32_t): flags of bitwise-or. 0x01 for the no-reply option.
input: rnum: (uint32_t): the number of records in the request.
input: dbidx: (uint16_t): (iteration): the index of the target database.
input: ksiz: (uint32_t): (iteration): the size of the key.
input: key: (variable): (iteration): the data of the key.
output: magic: (uint8_t): 0xB9: identifier.
output: hits: (uint32_t): the number of removed records.
get_bulk
Retrieve records at once.
input: magic: (uint8_t): 0xBA: identifier.
input: flags: (uint32_t): reserved and not used now. It should be 0.
input: rnum: (uint32_t): the number of records in the request.
input: dbidx: (uint16_t): (iteration): the index of the target database.
input: ksiz: (uint32_t): (iteration): the size of the key.
input: key: (variable): (iteration): the data of the key.
output: magic: (uint8_t): 0xBA: identifier.
output: hits: (uint32_t): the number of retrieved records.
output: dbidx: (uint16_t): (iteration): the index of the target database.
output: ksiz: (uint32_t): (iteration): the size of the key.
output: vsiz: (uint32_t): (iteration): the size of the value.
output: xt: (int64_t): (iteration): the expiration time.
output: key: (variable): (iteration): the data of the key.
output: value: (variable): (iteration): the data of the value.

Simplest Client Implementations

If there is no client library for Kyoto Tycoon in your favorite language, you have to write it by yourself or use the memcached protocol by the pluggable memcached server module. However, it is very easy to implement your own client library for the RESTful interface.

In Python3, the `http.client' module is useful. Use the `httplib' instead in Python2.

import time
import urllib
import http.client

# RESTful interface of Kyoto Tycoon
class KyotoTycoon:
    # connect to the server
    def open(self, host = "127.0.0.1", port = 1978, timeout = 30):
        self.ua = http.client.HTTPConnection(host, port, False, timeout)
    # close the connection
    def close(self):
        self.ua.close()
    # store a record
    def set(self, key, value, xt = None):
        if isinstance(key, str): key = key.encode("UTF-8")
        if isinstance(value, str): value = value.encode("UTF-8")
        key = "/" + urllib.parse.quote(key)
        headers = {}
        if xt != None:
            xt = int(time.time()) + xt
            headers["X-Kt-Xt"] = str(xt)
        self.ua.request("PUT", key, value, headers)
        res = self.ua.getresponse()
        body = res.read()
        return res.status == 201
    # remove a record
    def remove(self, key):
        if isinstance(key, str): key = key.encode("UTF-8")
        key = "/" + urllib.parse.quote(key)
        self.ua.request("DELETE", key)
        res = self.ua.getresponse()
        body = res.read()
        return res.status == 204
    # retrieve the value of a record
    def get(self, key):
        if isinstance(key, str): key = key.encode("UTF-8")
        key = "/" + urllib.parse.quote(key)
        self.ua.request("GET", key)
        res = self.ua.getresponse()
        body = res.read()
        if res.status != 200: return None
        return body

# sample usage
kt = KyotoTycoon()
kt.open("localhost", 1978)
kt.set("japan", "tokyo", 60)
print(kt.get("japan"))
kt.remove("japan")
kt.close()

In Ruby, the `Net::HTTP' module is useful.

require 'uri'
require 'net/http'

# RESTful interface of Kyoto Tycoon
class KyotoTycoon
  # connect to the server
  def open(host = "127.0.0.1", port = 1978, timeout = 30)
    @ua = Net::HTTP::new(host, port)
    @ua.read_timeout = timeout
    @ua.start
  end
  # close the connection
  def close
    @ua.finish
  end
  # store a record
  def set(key, value, xt = nil)
    key = "/" + URI::encode(key)
    req = Net::HTTP::Put::new(key)
    if xt
      xt = Time::now.to_i + xt
      req.add_field("X-Kt-Xt", xt)
    end
    res = @ua.request(req, value)
    res.code.to_i == 201
  end
  # remove a record
  def remove(key)
    key = "/" + URI::encode(key)
    req = Net::HTTP::Delete::new(key)
    res = @ua.request(req)
    res.code.to_i == 204
  end
  # retrieve the value of a record
  def get(key)
    key = "/" + URI::encode(key)
    req = Net::HTTP::Get::new(key)
    res = @ua.request(req)
    return nil if res.code.to_i != 200
    res.body
  end
end

# sample usage
kt = KyotoTycoon::new
kt.open("localhost", 1978)
kt.set("japan", "tokyo", 60)
printf("%s\n", kt.get("japan"))
kt.remove("japan")
kt.close

License

Kyoto Tycoon is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version.

Kyoto Tycoon is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see `http://www.gnu.org/licenses/'.

The FOSS License Exception and the Specific FOSS Library Linking Exception are also provided in order to accommodate products under other free and open source licenses. See the documents of Kyoto Cabinet for details.

Kyoto Tycoon was written and is maintained by FAL Labs. You can contact the author by e-mail to `info@fallabs.com'.


kyototycoon-0.9.56/doc/index.ja.html0000644000175000017500000001322311757471567016376 0ustar mikiomikio Kyoto Tycoon: キャッシュã¨ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã®ä¾¿åˆ©ã‚µãƒ¼ãƒ

Kyoto Tycoon: キャッシュã¨ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¸ã®ä¾¿åˆ©ã‚µãƒ¼ãƒ

Copyright (C) 2009-2012 FAL Labs
Last Update: Fri, 25 May 2012 02:44:22 +0900

概è¦

Kyoto Tycoonã¯æ™‚é™å‰Šé™¤æ©Ÿèƒ½ä»˜ãã®è»½é‡ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚µãƒ¼ãƒã§ã‚りã€å„種アプリケーションã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã‚„永続データをå–り扱ã†ã®ã«ä¾¿åˆ©ã§ã™ã€‚Kyoto Tycoonã¯Kyoto Cabinetã¨ã„ã†DBMã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ェイスã®ãƒ‘ッケージã§ã‚ã‚‹ã¨ã‚‚言ãˆã¾ã™ã€‚DBMã¯é«˜é€Ÿã‹ã¤ä¸¦åˆ—ãªå‹•作ã«ãŠã„ã¦å„ªä½æ€§ãŒã‚りã¾ã™ãŒã€è¤‡æ•°ã®ãƒ—ロセスã§åŒä¸€ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’共有ã§ããªã„ã¨ã„ã†æ¬ ç‚¹ã‚‚ã‚りã¾ã™ã€‚ãã“ã§ã€Kyoto Tycoonã¯Kyoto Cabinetã¸ã®ä¸¦åˆ—ã‹ã¤é éš”ã®æŽ¥ç¶šãŒã§ãるよã†ã«ã™ã‚‹ãŸã‚ã«æä¾›ã•れã¾ã™ã€‚Kyoto Cabinetã¯è¤‡æ•°ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’処ç†ã§ãるサーãƒãƒ—ロセスã¨ã€ãれã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ãŸã‚ã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãƒ©ã‚¤ãƒ–ラリã«ã‚ˆã£ã¦æ§‹æˆã•れã¾ã™ã€‚

サーãƒã¨ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã®é–“ã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ãƒ—ロトコルã¯HTTPã«åŸºã¥ã„ã¦ã„ã‚‹ã®ã§ã€å„種ã®è¨€èªžã§ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã‚¢ãƒ—リケーションやクライアントライブラリã®é–‹ç™ºã‚’ã™ã‚‹ã®ãŒå®¹æ˜“ã§ã™ã€‚GETã€HEADã€PUTã€DELETEã¨ã„ã£ãŸãƒ¡ã‚½ãƒƒãƒ‰ã‚’用ã„ã‚‹RESTful風ã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒ•ェイスã¨ã€å…¨ã¦ã‚’POSTã§æ‰±ã†RPC風インターフェイスã®ä¸¡æ–¹ãŒæä¾›ã•れã¾ã™ã€‚下層ã®OSãŒæä¾›ã™ã‚‹epollã‚„kqueueãªã©ã®ãƒ¢ãƒ€ãƒ³ãªã‚¤ãƒ™ãƒ³ãƒˆé€šçŸ¥æ©Ÿæ§‹ã‚’利用ã™ã‚‹ã“ã¨ã«ã‚ˆã£ã¦ã€ã²ã¨ã¤ã®ã‚µãƒ¼ãƒã¯1万以上ã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã‹ã‚‰ã®æŽ¥ç¶šã‚’åŒæ™‚ã«å—ã‘付ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ホットãƒãƒƒã‚¯ã‚¢ãƒƒãƒ—や更新ログやéžåŒæœŸãƒ¬ãƒ—リケーションãªã©ã®æ©Ÿèƒ½ã«ã‚ˆã£ã¦é«˜å¯ç”¨æ€§ã‚’å‚™ãˆãŸé‹ç”¨ã‚’支æ´ã—ã¾ã™ã€‚軽é‡ã‚¹ã‚¯ãƒªãƒ—ト言語ã§ã‚ã‚‹Luaã®å‡¦ç†ç³»ã‚’埋ã‚込むã“ã¨ã§ã€ã‚µãƒ¼ãƒä¸Šã§ä»»æ„ã®ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹å‡¦ç†ã‚’行ã†ã“ã¨ãŒã§ãã¾ã™ã€‚

Kyoto Tycoonã®ã‚µãƒ¼ãƒã¯C++言語ã§è¨˜è¿°ã•れã¦ã„ã¾ã™ã€‚サーãƒã¯C++03ã¨TR1ãƒ©ã‚¤ãƒ–ãƒ©ãƒªæ‹¡å¼µã«æº–æ‹ ã™ã‚‹APIã‚’å‚™ãˆãŸç’°å¢ƒã«ã¦åˆ©ç”¨ã§ãã¾ã™ã€‚クライアントã¯HTTPã•ãˆä½¿ãˆã‚Œã°ã©ã‚“ãªç’°å¢ƒã§ã‚‚利用ã§ãã¾ã™ã€‚Kyoto Cabinetã¯GNU一般公衆利用許諾ã«åŸºã¥ã„ã¦åˆ©ç”¨è¨±è«¾ã•れãŸãƒ•リーソフトウェアã§ã™ã€‚


文書

以下ã¯Kyoto Tycoonã®æ–‡æ›¸ç¾¤ã§ã™ã€‚ã“れらã¯ã‚½ãƒ¼ã‚¹ãƒ‘ッケージã«ã‚‚å«ã¾ã‚Œã¦ã„ã¾ã™ã€‚


パッケージ

以下ã¯Kyoto Tycoonã®ã‚½ãƒ¼ã‚¹ãƒ‘ッケージ群ã§ã™ã€‚ãƒã‚¤ãƒŠãƒªãƒ‘ッケージã«é–¢ã—ã¦ã¯ã€å„々ã®é…布者ã®ã‚µã‚¤ãƒˆã‚’ã”覧ãã ã•ã„。


情報

Kyoto Cabinetã¯FAL Labsã«ã‚ˆã£ã¦é–‹ç™ºã•れä¿å®ˆã•れã¦ã„ã¾ã™ã€‚開発者ã®é€£çµ¡å…ˆãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã¯ `info@fallabs.com' ã§ã™ã€‚


kyototycoon-0.9.56/myscript.cc0000644000175000017500000031674111757471602015425 0ustar mikiomikio/************************************************************************************************* * The scripting extension * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "myscript.h" #include "myconf.h" #if _KT_LUA extern "C" { #include #include #include } /* precedent type declaration */ struct ScriptProcessorCore; class StringBuilder; struct SoftCursor; struct SoftDB; class SoftVisitor; class SoftFileProcessor; class SoftMapReduce; typedef std::map StringMap; typedef std::vector StringVector; /* function prototypes */ static void reporterror(ScriptProcessorCore* core, const char* name); static void throwinvarg(lua_State* lua, const char* func); static void setfielduint(lua_State* lua, const char* name, uint32_t num); static void setfieldstr(lua_State* lua, const char* name, const char* str); static void setfieldfunc(lua_State* lua, const char* name, lua_CFunction func); static void setfieldvalue(lua_State* lua, const char* name, int32_t index); static void define_module(lua_State* lua); static int kt_atoi(lua_State* lua); static int kt_atoix(lua_State* lua); static int kt_atof(lua_State* lua); static int kt_hash_murmur(lua_State* lua); static int kt_hash_fnv(lua_State* lua); static int kt_levdist(lua_State* lua); static int kt_time(lua_State* lua); static int kt_sleep(lua_State* lua); static int kt_pack(lua_State* lua); static int kt_unpack(lua_State *lua); static int kt_split(lua_State *lua); static int kt_codec(lua_State *lua); static int kt_bit(lua_State *lua); static int kt_strstr(lua_State *lua); static int kt_strfwm(lua_State *lua); static int kt_strbwm(lua_State *lua); static int kt_regex(lua_State *lua); static int kt_arraydump(lua_State *lua); static int kt_arrayload(lua_State *lua); static int kt_mapdump(lua_State *lua); static int kt_mapload(lua_State *lua); static void define_err(lua_State* lua); static int err_new(lua_State* lua); static int err_tostring(lua_State* lua); static int err_set(lua_State* lua); static int err_code(lua_State* lua); static int err_name(lua_State* lua); static int err_message(lua_State* lua); static void define_vis(lua_State* lua); static int vis_new(lua_State* lua); static int vis_visit_full(lua_State* lua); static int vis_visit_empty(lua_State* lua); static void define_fproc(lua_State* lua); static int fproc_new(lua_State* lua); static int fproc_process(lua_State* lua); static void define_cur(lua_State* lua); static int cur_new(lua_State* lua); static int cur_gc(lua_State* lua); static int cur_tostring(lua_State* lua); static int cur_call(lua_State* lua); static int cur_disable(lua_State* lua); static int cur_accept(lua_State* lua); static int cur_set_value(lua_State* lua); static int cur_remove(lua_State* lua); static int cur_get_key(lua_State* lua); static int cur_get_value(lua_State* lua); static int cur_get(lua_State* lua); static int cur_seize(lua_State* lua); static int cur_jump(lua_State* lua); static int cur_jump_back(lua_State* lua); static int cur_step(lua_State* lua); static int cur_step_back(lua_State* lua); static int cur_db(lua_State* lua); static int cur_error(lua_State* lua); static void define_db(lua_State* lua); static int db_new(lua_State* lua); static int db_gc(lua_State* lua); static int db_tostring(lua_State* lua); static int db_index(lua_State* lua); static int db_newindex(lua_State* lua); static int db_new_ptr(lua_State* lua); static int db_delete_ptr(lua_State* lua); static int db_process(lua_State* lua); static int db_error(lua_State* lua); static int db_open(lua_State* lua); static int db_close(lua_State* lua); static int db_accept(lua_State* lua); static int db_accept_bulk(lua_State* lua); static int db_iterate(lua_State* lua); static int db_set(lua_State* lua); static int db_add(lua_State* lua); static int db_replace(lua_State* lua); static int db_append(lua_State* lua); static int db_increment(lua_State* lua); static int db_increment_double(lua_State* lua); static int db_cas(lua_State* lua); static int db_remove(lua_State* lua); static int db_get(lua_State* lua); static int db_check(lua_State* lua); static int db_seize(lua_State* lua); static int db_set_bulk(lua_State* lua); static int db_remove_bulk(lua_State* lua); static int db_get_bulk(lua_State* lua); static int db_clear(lua_State* lua); static int db_synchronize(lua_State* lua); static int db_occupy(lua_State* lua); static int db_copy(lua_State* lua); static int db_begin_transaction(lua_State* lua); static int db_end_transaction(lua_State* lua); static int db_transaction(lua_State* lua); static int db_dump_snapshot(lua_State* lua); static int db_load_snapshot(lua_State* lua); static int db_count(lua_State* lua); static int db_size(lua_State* lua); static int db_path(lua_State* lua); static int db_status(lua_State* lua); static int db_match_prefix(lua_State* lua); static int db_match_regex(lua_State* lua); static int db_match_similar(lua_State* lua); static int db_merge(lua_State* lua); static int db_mapreduce(lua_State* lua); static int db_mapreduce_emit(lua_State* lua); static int db_mapreduce_iter(lua_State* lua); static int db_cursor(lua_State* lua); static int db_cursor_process(lua_State* lua); static int db_pairs(lua_State* lua); static int serv_log(lua_State* lua); /** * ScriptProcessor internal. */ struct ScriptProcessorCore { std::string path; int32_t thid; kt::RPCServer* serv; kt::TimedDB* dbs; int32_t dbnum; const std::map* dbmap; lua_State *lua; }; /** * Wrapper of a string. */ class StringBuilder { public: StringBuilder(lua_State* lua, int32_t index) : str_(), ok_(false) { char nbuf[kc::NUMBUFSIZ]; const char* ptr = NULL; size_t size = 0; switch (lua_type(lua, index)) { case LUA_TNUMBER: { double num = lua_tonumber(lua, index); if (num == std::floor(num)) { std::snprintf(nbuf, sizeof(nbuf) - 1, "%lld", (long long)num); } else { std::snprintf(nbuf, sizeof(nbuf) - 1, "%f", num); } nbuf[sizeof(nbuf)-1] = '\0'; ptr = nbuf; size = std::strlen(ptr); break; } case LUA_TBOOLEAN: { ptr = lua_toboolean(lua, index) ? "true" : "false"; size = std::strlen(ptr); break; } case LUA_TSTRING: { ptr = lua_tolstring(lua, index, &size); break; } } if (ptr) { str_.append(ptr, size); ok_ = true; } } const std::string& str() { return str_; } bool ok() { return ok_; } private: std::string str_; bool ok_; }; /** * Default constructor. */ ScriptProcessor::ScriptProcessor() { _assert_(true); ScriptProcessorCore* core = new ScriptProcessorCore; core->thid = 0; core->serv = NULL; core->dbs = NULL; core->dbnum = 0; core->dbmap = NULL; core->lua = NULL; opq_ = core; } /** * Destructor. */ ScriptProcessor::~ScriptProcessor() { _assert_(true); ScriptProcessorCore* core = (ScriptProcessorCore*)opq_; lua_State* lua = core->lua; if (lua) lua_close(lua); delete core; } /** * Set domain-specific resources. */ bool ScriptProcessor::set_resources(int32_t thid, kt::RPCServer* serv, kt::TimedDB* dbs, int32_t dbnum, const std::map* dbmap) { _assert_(serv && dbs && dbnum >= 0 && dbmap); ScriptProcessorCore* core = (ScriptProcessorCore*)opq_; lua_State *lua = luaL_newstate(); if (!lua) return false; luaL_openlibs(lua); lua_settop(lua, 0); lua_newtable(lua); define_module(lua); define_err(lua); define_vis(lua); define_fproc(lua); define_cur(lua); define_db(lua); lua_setglobal(lua, "__kyototycoon__"); lua_getglobal(lua, "__kyototycoon__"); lua_pushlightuserdata(lua, serv); lua_setfield(lua, -2, "__serv__"); setfieldstr(lua, "VERSION", kt::VERSION); setfielduint(lua, "RVSUCCESS", kt::RPCClient::RVSUCCESS); setfielduint(lua, "RVENOIMPL", kt::RPCClient::RVENOIMPL); setfielduint(lua, "RVEINVALID", kt::RPCClient::RVEINVALID); setfielduint(lua, "RVELOGIC", kt::RPCClient::RVELOGIC); setfielduint(lua, "RVEINTERNAL", kt::RPCClient::RVEINTERNAL); setfielduint(lua, "thid", thid); lua_getfield(lua, -1, "DB"); lua_newtable(lua); for (int32_t i = 0; i < dbnum; i++) { lua_getfield(lua, -2, "new"); lua_pushvalue(lua, -3); lua_pushlightuserdata(lua, dbs + i); if (lua_pcall(lua, 2, 1, 0) != 0) { lua_close(lua); return false; } lua_rawseti(lua, -2, i + 1); } lua_rawgeti(lua, -1, 1); lua_setfield(lua, -4, "db"); std::map::const_iterator it = dbmap->begin(); std::map::const_iterator itend = dbmap->end(); while (it != itend) { lua_rawgeti(lua, -1, it->second + 1); lua_setfield(lua, -2, it->first.c_str()); ++it; } lua_setfield(lua, -3, "dbs"); lua_pop(lua, 1); setfieldfunc(lua, "log", serv_log); lua_settop(lua, 0); core->thid = thid; core->serv = serv; core->dbs = dbs; core->dbnum = dbnum; core->dbmap = dbmap; core->lua = lua; return true; } /** * Load a script file. */ bool ScriptProcessor::load(const std::string& path) { _assert_(true); ScriptProcessorCore* core = (ScriptProcessorCore*)opq_; core->path = path; lua_State* lua = core->lua; int64_t size; char* script = kc::File::read_file(path, &size); if (!script) return false; bool err = false; lua_settop(lua, 0); if (luaL_loadstring(lua, script) != 0 || lua_pcall(lua, 0, 0, 0) != 0) { reporterror(core, "(init)"); err = true; } delete[] script; return !err; } /** * Clear the internal state. */ void ScriptProcessor::clear() { _assert_(true); ScriptProcessorCore* core = (ScriptProcessorCore*)opq_; lua_State* lua = core->lua; if (lua) lua_close(lua); core->thid = 0; core->serv = NULL; core->dbs = NULL; core->dbnum = 0; core->dbmap = NULL; core->lua = NULL; } /** * Call a procedure. */ kt::RPCClient::ReturnValue ScriptProcessor::call(const std::string& name, const std::map& inmap, std::map& outmap) { _assert_(true); ScriptProcessorCore* core = (ScriptProcessorCore*)opq_; lua_State* lua = core->lua; lua_settop(lua, 0); lua_newtable(lua); lua_getglobal(lua, name.c_str()); if (!lua_isfunction(lua, -1)) { lua_settop(lua, 0); return kt::RPCClient::RVENOIMPL; } lua_newtable(lua); std::map::const_iterator it = inmap.begin(); std::map::const_iterator itend = inmap.end(); while (it != itend) { lua_pushlstring(lua, it->first.data(), it->first.size()); lua_pushlstring(lua, it->second.data(), it->second.size()); lua_settable(lua, -3); ++it; } lua_pushvalue(lua, 1); kt::RPCClient::ReturnValue rv; if (lua_pcall(lua, 2, 1, 0) == 0) { lua_pushnil(lua); while (lua_next(lua, 1) != 0) { StringBuilder key(lua, -2); StringBuilder value(lua, -1); if (key.ok() && value.ok()) outmap[key.str()] = value.str(); lua_pop(lua, 1); } rv = (kt::RPCClient::ReturnValue)lua_tointeger(lua, -1); } else { reporterror(core, name.c_str()); rv = kt::RPCClient::RVEINTERNAL; } lua_settop(lua, 0); return rv; } /** * Burrow of cursors no longer in use. */ class CursorBurrow { private: typedef std::vector CursorList; public: explicit CursorBurrow() : lock_(), dcurs_() {} ~CursorBurrow() { sweap(); } void sweap() { kc::ScopedSpinLock lock(&lock_); if (dcurs_.size() > 0) { CursorList::iterator dit = dcurs_.begin(); CursorList::iterator ditend = dcurs_.end(); while (dit != ditend) { kt::TimedDB::Cursor* cur = *dit; delete cur; ++dit; } dcurs_.clear(); } } void deposit(kt::TimedDB::Cursor* cur) { kc::ScopedSpinLock lock(&lock_); dcurs_.push_back(cur); } private: kc::SpinLock lock_; CursorList dcurs_; } g_curbur; /** * Wrapper of a database. */ struct SoftCursor { kt::TimedDB::Cursor* cur; }; /** * Wrapper of a database. */ struct SoftDB { kt::TimedDB* db; bool light; }; /** * Wrapper of a visitor. */ class SoftVisitor : public kt::TimedDB::Visitor { public: explicit SoftVisitor(lua_State* lua, bool writable) : lua_(lua), writable_(writable), top_(0) { top_ = lua_gettop(lua_); } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { lua_settop(lua_, top_); int32_t argc; if (lua_istable(lua_, -1)) { lua_getfield(lua_, -1, "visit_full"); if (!lua_isfunction(lua_, -1)) return NOP; lua_pushvalue(lua_, -2); lua_pushlstring(lua_, kbuf, ksiz); lua_pushlstring(lua_, vbuf, vsiz); lua_pushnumber(lua_, *xtp < kt::TimedDB::XTMAX ? *xtp : kt::TimedDB::XTMAX); argc = 4; } else { if (!lua_isfunction(lua_, -1)) return NOP; lua_pushvalue(lua_, -1); lua_pushlstring(lua_, kbuf, ksiz); lua_pushlstring(lua_, vbuf, vsiz); lua_pushnumber(lua_, *xtp < kt::TimedDB::XTMAX ? *xtp : kt::TimedDB::XTMAX); argc = 3; } const char* rv = NOP; if (lua_pcall(lua_, argc, 2, 0) == 0) { if (lua_islightuserdata(lua_, -2)) { const char* trv = (const char*)lua_touserdata(lua_, -2); if (trv == kt::TimedDB::Visitor::REMOVE) rv = kt::TimedDB::Visitor::REMOVE; } else { size_t rsiz; const char* rbuf = lua_tolstring(lua_, -2, &rsiz); if (rbuf) { rv = rbuf; *sp = rsiz; } *xtp = lua_isnumber(lua_, -1) ? lua_tonumber(lua_, -1) : -*xtp; } } if (!writable_) rv = NULL; return rv; } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { lua_settop(lua_, top_); int32_t argc; if (lua_istable(lua_, -1)) { lua_getfield(lua_, -1, "visit_empty"); if (!lua_isfunction(lua_, -1)) return NOP; lua_pushvalue(lua_, -2); lua_pushlstring(lua_, kbuf, ksiz); argc = 2; } else { if (!lua_isfunction(lua_, -1)) return NOP; lua_pushvalue(lua_, -1); lua_pushlstring(lua_, kbuf, ksiz); lua_pushnil(lua_); argc = 2; } const char* rv = NOP; if (lua_pcall(lua_, argc, 2, 0) == 0) { if (lua_islightuserdata(lua_, -1)) { const char* trv = (const char*)lua_touserdata(lua_, -1); if (trv == kt::TimedDB::Visitor::REMOVE) rv = kt::TimedDB::Visitor::REMOVE; } else { size_t rsiz; const char* rbuf = lua_tolstring(lua_, -2, &rsiz); if (rbuf) { rv = rbuf; *sp = rsiz; } *xtp = lua_isnumber(lua_, -1) ? lua_tonumber(lua_, -1) : kc::INT64MAX; } } if (!writable_) rv = NULL; return rv; } void visit_before() { lua_settop(lua_, top_); if (!lua_istable(lua_, -1)) return; lua_getfield(lua_, -1, "visit_before"); if (!lua_isfunction(lua_, -1)) return; lua_pushvalue(lua_, -2); lua_pcall(lua_, 1, 0, 0); } void visit_after() { lua_settop(lua_, top_); if (!lua_istable(lua_, -1)) return; lua_getfield(lua_, -1, "visit_after"); if (!lua_isfunction(lua_, -1)) return; lua_pushvalue(lua_, -2); lua_pcall(lua_, 1, 0, 0); } lua_State* lua_; bool writable_; int32_t top_; }; /** * Wrapper of a file processor. */ class SoftFileProcessor : public kc::BasicDB::FileProcessor { public: explicit SoftFileProcessor(lua_State* lua) : lua_(lua) {} private: bool process(const std::string& path, int64_t count, int64_t size) { int32_t argc; if (lua_istable(lua_, -1)) { lua_getfield(lua_, -1, "process"); lua_pushvalue(lua_, -2); lua_pushstring(lua_, path.c_str()); lua_pushnumber(lua_, count); lua_pushnumber(lua_, size); argc = 4; } else { lua_pushvalue(lua_, -1); lua_pushstring(lua_, path.c_str()); lua_pushnumber(lua_, count); lua_pushnumber(lua_, size); argc = 3; } bool rv = false; if (lua_pcall(lua_, argc, 1, 0) == 0) rv = lua_toboolean(lua_, -1); return rv; } lua_State* lua_; }; class SoftMapReduce : public kt::MapReduce { public: SoftMapReduce(lua_State* lua, int32_t logidx, int32_t procidx) : lua_(lua), logidx_(logidx), procidx_(procidx) {} bool map(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) { int32_t top = lua_gettop(lua_); lua_pushlightuserdata(lua_, (void*)this); lua_setglobal(lua_, "__mr_self"); lua_pushvalue(lua_, 2); lua_pushlstring(lua_, kbuf, ksiz); lua_pushlstring(lua_, vbuf, vsiz); lua_pushcfunction(lua_, db_mapreduce_emit); bool rv; if (lua_pcall(lua_, 3, 1, 0) == 0) { rv = lua_toboolean(lua_, -1); } else { rv = false; } lua_settop(lua_, top); return rv; } bool reduce(const char* kbuf, size_t ksiz, ValueIterator* iter) { int32_t top = lua_gettop(lua_); lua_pushlightuserdata(lua_, (void*)iter); lua_setglobal(lua_, "__mr_iter"); lua_pushvalue(lua_, 3); lua_pushlstring(lua_, kbuf, ksiz); lua_pushcfunction(lua_, db_mapreduce_iter); bool rv; if (lua_pcall(lua_, 2, 1, 0) == 0) { rv = lua_toboolean(lua_, -1); } else { rv = false; } lua_settop(lua_, top); return rv; } bool log(const char* name, const char* message) { if (logidx_ < 1) return true; int32_t top = lua_gettop(lua_); lua_pushvalue(lua_, logidx_); lua_pushstring(lua_, name); lua_pushstring(lua_, message); bool rv; if (lua_pcall(lua_, 2, 1, 0) == 0) { rv = lua_toboolean(lua_, -1); } else { rv = false; } lua_settop(lua_, top); return rv; } bool preprocess() { if (procidx_ < 1) return true; int32_t top = lua_gettop(lua_); lua_pushlightuserdata(lua_, (void*)this); lua_setglobal(lua_, "__mr_self"); lua_pushvalue(lua_, procidx_); lua_pushcfunction(lua_, db_mapreduce_emit); bool rv; if (lua_pcall(lua_, 1, 1, 0) == 0) { rv = lua_toboolean(lua_, -1); } else { rv = false; } lua_settop(lua_, top); return rv; } bool midprocess() { return preprocess(); } bool postprocess() { if (procidx_ < 1) return true; int32_t top = lua_gettop(lua_); lua_pushlightuserdata(lua_, (void*)this); lua_setglobal(lua_, "__mr_self"); lua_pushvalue(lua_, procidx_); bool rv; if (lua_pcall(lua_, 0, 1, 0) == 0) { rv = lua_toboolean(lua_, -1); } else { rv = false; } lua_settop(lua_, top); return rv; } bool emit_public(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) { return emit(kbuf, ksiz, vbuf, vsiz); } private: lua_State* lua_; int32_t logidx_; int32_t procidx_; }; /** * Report error information. */ static void reporterror(ScriptProcessorCore* core, const char* name) { lua_State* lua = core->lua; int argc = lua_gettop(lua); core->serv->log(kt::RPCServer::Logger::ERROR, "[SCRIPT]: %s: %s", name, argc > 0 ? lua_tostring(lua, argc) : "unknown"); } /** * Throw the invalid argument error. */ static void throwinvarg(lua_State* lua, const char* func) { char msg[256]; size_t len = std::sprintf(msg, "%s: invalid arguments", func); lua_pushlstring(lua, msg, len); lua_error(lua); } /** * Set a field of unsigned integer. */ static void setfielduint(lua_State* lua, const char* name, uint32_t num) { lua_pushinteger(lua, num); lua_setfield(lua, -2, name); } /** * Set a field of string. */ static void setfieldstr(lua_State* lua, const char* name, const char* str) { lua_pushstring(lua, str); lua_setfield(lua, -2, name); } /** * Set a field of function. */ static void setfieldfunc(lua_State* lua, const char* name, lua_CFunction func) { lua_pushcfunction(lua, func); lua_setfield(lua, -2, name); } /** * Set a field of stacked value. */ static void setfieldvalue(lua_State* lua, const char* name, int32_t index) { lua_pushvalue(lua, index); lua_setfield(lua, -2, name); } /** * Define objects of the module. */ static void define_module(lua_State* lua) { setfieldfunc(lua, "atoi", kt_atoi); setfieldfunc(lua, "atoix", kt_atoix); setfieldfunc(lua, "atof", kt_atof); setfieldfunc(lua, "hash_murmur", kt_hash_murmur); setfieldfunc(lua, "hash_fnv", kt_hash_fnv); setfieldfunc(lua, "levdist", kt_levdist); setfieldfunc(lua, "time", kt_time); setfieldfunc(lua, "sleep", kt_sleep); setfieldfunc(lua, "pack", kt_pack); setfieldfunc(lua, "unpack", kt_unpack); setfieldfunc(lua, "split", kt_split); setfieldfunc(lua, "codec", kt_codec); setfieldfunc(lua, "bit", kt_bit); setfieldfunc(lua, "strstr", kt_strstr); setfieldfunc(lua, "strfwm", kt_strfwm); setfieldfunc(lua, "strbwm", kt_strbwm); setfieldfunc(lua, "regex", kt_regex); setfieldfunc(lua, "arraydump", kt_arraydump); setfieldfunc(lua, "arrayload", kt_arrayload); setfieldfunc(lua, "mapdump", kt_mapdump); setfieldfunc(lua, "mapload", kt_mapload); } /** * Implementation of atoi. */ static int kt_atoi(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1) throwinvarg(lua, __KCFUNC__); const char* str = lua_tostring(lua, 1); if (!str) return 0; lua_pushnumber(lua, kc::atoi(str)); return 1; } /** * Implementation of atoix. */ static int kt_atoix(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1) throwinvarg(lua, __KCFUNC__); const char* str = lua_tostring(lua, 1); if (!str) return 0; lua_pushnumber(lua, kc::atoix(str)); return 1; } /** * Implementation of atof. */ static int kt_atof(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1) throwinvarg(lua, __KCFUNC__); const char* str = lua_tostring(lua, 1); if (!str) return 0; lua_pushnumber(lua, kc::atof(str)); return 1; } /** * Implementation of hash_murmur. */ static int kt_hash_murmur(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1) throwinvarg(lua, __KCFUNC__); size_t len; const char* str = lua_tolstring(lua, 1, &len); if (!str) return 0; lua_pushinteger(lua, kc::hashmurmur(str, len) & ((1ULL << 48) - 1)); return 1; } /** * Implementation of hash_fnv. */ static int kt_hash_fnv(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1) throwinvarg(lua, __KCFUNC__); size_t len; const char* str = lua_tolstring(lua, 1, &len); if (!str) return 0; lua_pushinteger(lua, kc::hashfnv(str, len) & ((1ULL << 48) - 1)); return 1; } /** * Implementation of levdist. */ static int kt_levdist(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2) throwinvarg(lua, __KCFUNC__); size_t asiz; const char* abuf = lua_tolstring(lua, 1, &asiz); size_t bsiz; const char* bbuf = lua_tolstring(lua, 2, &bsiz); if (!abuf || !bbuf) throwinvarg(lua, __KCFUNC__); bool utf = argc > 2 ? lua_toboolean(lua, 3) : false; size_t dist; if (utf) { uint32_t astack[128]; uint32_t* aary = asiz > sizeof(astack) / sizeof(*astack) ? new uint32_t[asiz] : astack; size_t anum; kc::strutftoucs(abuf, asiz, aary, &anum); uint32_t bstack[128]; uint32_t* bary = bsiz > sizeof(bstack) / sizeof(*bstack) ? new uint32_t[bsiz] : bstack; size_t bnum; kc::strutftoucs(bbuf, bsiz, bary, &bnum); dist = kc::strucsdist(aary, anum, bary, bnum); if (bary != bstack) delete[] bary; if (aary != astack) delete[] aary; } else { dist = kc::memdist(abuf, asiz, bbuf, bsiz); } lua_pushinteger(lua, dist); return 1; } /** * Implementation of hash_fnv. */ static int kt_time(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 0) throwinvarg(lua, __KCFUNC__); lua_pushnumber(lua, kc::time()); return 1; } /** * Implementation of sleep. */ static int kt_sleep(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc > 1) throwinvarg(lua, __KCFUNC__); double sec = argc > 0 ? lua_tonumber(lua, 1) : 0; if (sec > 0) { kc::Thread::sleep(sec); } else { kc::Thread::yield(); } return 0; } /** * Implementation of pack. */ static int kt_pack(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1) throwinvarg(lua, __KCFUNC__); const char* format = lua_tostring(lua, 1); if (!format) throwinvarg(lua, __KCFUNC__); lua_newtable(lua); int32_t aidx = argc + 1; int32_t eidx = 1; for (int32_t i = 2; i <= argc; i++) { size_t len; switch (lua_type(lua, i)) { case LUA_TNUMBER: case LUA_TSTRING: { lua_pushvalue(lua, i); lua_rawseti(lua, aidx, eidx++); break; } case LUA_TTABLE: { len = lua_objlen(lua, i); for (size_t j = 1; j <= len; j++) { lua_rawgeti(lua, i, j); lua_rawseti(lua, aidx, eidx++); } break; } default: { lua_pushnumber(lua, 0); lua_rawseti(lua, aidx, eidx++); break; } } } lua_replace(lua, 2); lua_settop(lua, 2); std::string xstr; int32_t emax = eidx - 1; eidx = 1; while (*format != '\0') { int32_t c = *format; int32_t loop = 1; if (format[1] == '*') { loop = kc::INT32MAX; format++; } else if (format[1] >= '0' && format[1] <= '9') { char* suffix; loop = std::strtol(format + 1, &suffix, 10); format = suffix - 1; } loop = loop < emax ? loop : emax; int32_t end = eidx + loop - 1; if (end > emax) end = emax; while (eidx <= end) { lua_rawgeti(lua, 2, eidx); double num = lua_tonumber(lua, 3); lua_pop(lua, 1); uint8_t cnum; uint16_t snum; uint32_t inum; uint64_t lnum; double dnum; float fnum; uint64_t wnum; char wbuf[kc::NUMBUFSIZ], *wp; switch (c) { case 'c': case 'C': { cnum = num; xstr.append((char*)&cnum, sizeof(cnum)); break; } case 's': case 'S': { snum = num; xstr.append((char*)&snum, sizeof(snum)); break; } case 'i': case 'I': { inum = num; xstr.append((char*)&inum, sizeof(inum)); break; } case 'l': case 'L': { lnum = num; xstr.append((char*)&lnum, sizeof(lnum)); break; } case 'f': case 'F': { fnum = num; xstr.append((char*)&fnum, sizeof(fnum)); break; } case 'd': case 'D': { dnum = num; xstr.append((char*)&dnum, sizeof(dnum)); break; } case 'n': { snum = num; snum = kc::hton16(snum); xstr.append((char*)&snum, sizeof(snum)); break; } case 'N': { inum = num; inum = kc::hton32(inum); xstr.append((char*)&inum, sizeof(inum)); break; } case 'M': { lnum = num; lnum = kc::hton64(lnum); xstr.append((char*)&lnum, sizeof(lnum)); break; } case 'w': case 'W': { wnum = num; wp = wbuf; if (wnum < (1ULL << 7)) { *(wp++) = wnum; } else if (wnum < (1ULL << 14)) { *(wp++) = (wnum >> 7) | 0x80; *(wp++) = wnum & 0x7f; } else if (wnum < (1ULL << 21)) { *(wp++) = (wnum >> 14) | 0x80; *(wp++) = ((wnum >> 7) & 0x7f) | 0x80; *(wp++) = wnum & 0x7f; } else if (wnum < (1ULL << 28)) { *(wp++) = (wnum >> 21) | 0x80; *(wp++) = ((wnum >> 14) & 0x7f) | 0x80; *(wp++) = ((wnum >> 7) & 0x7f) | 0x80; *(wp++) = wnum & 0x7f; } else if (wnum < (1ULL << 35)) { *(wp++) = (wnum >> 28) | 0x80; *(wp++) = ((wnum >> 21) & 0x7f) | 0x80; *(wp++) = ((wnum >> 14) & 0x7f) | 0x80; *(wp++) = ((wnum >> 7) & 0x7f) | 0x80; *(wp++) = wnum & 0x7f; } else if (wnum < (1ULL << 42)) { *(wp++) = (wnum >> 35) | 0x80; *(wp++) = ((wnum >> 28) & 0x7f) | 0x80; *(wp++) = ((wnum >> 21) & 0x7f) | 0x80; *(wp++) = ((wnum >> 14) & 0x7f) | 0x80; *(wp++) = ((wnum >> 7) & 0x7f) | 0x80; *(wp++) = wnum & 0x7f; } else if (wnum < (1ULL << 49)) { *(wp++) = (wnum >> 42) | 0x80; *(wp++) = ((wnum >> 35) & 0x7f) | 0x80; *(wp++) = ((wnum >> 28) & 0x7f) | 0x80; *(wp++) = ((wnum >> 21) & 0x7f) | 0x80; *(wp++) = ((wnum >> 14) & 0x7f) | 0x80; *(wp++) = ((wnum >> 7) & 0x7f) | 0x80; *(wp++) = wnum & 0x7f; } else if (wnum < (1ULL << 56)) { *(wp++) = (wnum >> 49) | 0x80; *(wp++) = ((wnum >> 42) & 0x7f) | 0x80; *(wp++) = ((wnum >> 35) & 0x7f) | 0x80; *(wp++) = ((wnum >> 28) & 0x7f) | 0x80; *(wp++) = ((wnum >> 21) & 0x7f) | 0x80; *(wp++) = ((wnum >> 14) & 0x7f) | 0x80; *(wp++) = ((wnum >> 7) & 0x7f) | 0x80; *(wp++) = wnum & 0x7f; } else { *(wp++) = (wnum >> 63) | 0x80; *(wp++) = ((wnum >> 49) & 0x7f) | 0x80; *(wp++) = ((wnum >> 42) & 0x7f) | 0x80; *(wp++) = ((wnum >> 35) & 0x7f) | 0x80; *(wp++) = ((wnum >> 28) & 0x7f) | 0x80; *(wp++) = ((wnum >> 21) & 0x7f) | 0x80; *(wp++) = ((wnum >> 14) & 0x7f) | 0x80; *(wp++) = ((wnum >> 7) & 0x7f) | 0x80; *(wp++) = wnum & 0x7f; } xstr.append(wbuf, wp - wbuf); break; } } eidx++; } format++; if (eidx > emax) break; } lua_pushlstring(lua, xstr.data(), xstr.size()); return 1; } /** * Implementation of unpack. */ static int kt_unpack(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc != 2) throwinvarg(lua, __KCFUNC__); const char* format = lua_tostring(lua, 1); size_t size; const char* buf = lua_tolstring(lua, 2, &size); if (!format) throwinvarg(lua, __KCFUNC__); if (!buf) { buf = ""; size = 0; } lua_newtable(lua); const char* rp = buf; int32_t eidx = 1; while (*format != '\0') { int32_t c = *format; int32_t loop = 1; if (format[1] == '*') { loop = kc::INT32MAX; format++; } else if (format[1] >= '0' && format[1] <= '9') { char* suffix; loop = strtol(format + 1, &suffix, 10); format = suffix - 1; } loop = loop < (int32_t)size ? loop : size; for (int32_t i = 0; i < loop && size > 0; i++) { uint8_t cnum; uint16_t snum; uint32_t inum; uint64_t lnum; float fnum; double dnum; uint64_t wnum; switch (c) { case 'c': { if (size >= sizeof(cnum)) { std::memcpy(&cnum, rp, sizeof(cnum)); lua_pushnumber(lua, (int8_t)cnum); lua_rawseti(lua, 3, eidx++); rp += sizeof(cnum); size -= sizeof(cnum); } else { size = 0; } break; } case 'C': { if (size >= sizeof(cnum)) { std::memcpy(&cnum, rp, sizeof(cnum)); lua_pushnumber(lua, (uint8_t)cnum); lua_rawseti(lua, 3, eidx++); rp += sizeof(cnum); size -= sizeof(cnum); } else { size = 0; } break; } case 's': { if (size >= sizeof(snum)) { std::memcpy(&snum, rp, sizeof(snum)); lua_pushnumber(lua, (int16_t)snum); lua_rawseti(lua, 3, eidx++); rp += sizeof(snum); size -= sizeof(snum); } else { size = 0; } break; } case 'S': { if (size >= sizeof(snum)) { std::memcpy(&snum, rp, sizeof(snum)); lua_pushnumber(lua, (uint16_t)snum); lua_rawseti(lua, 3, eidx++); rp += sizeof(snum); size -= sizeof(snum); } else { size = 0; } break; } case 'i': { if (size >= sizeof(inum)) { std::memcpy(&inum, rp, sizeof(inum)); lua_pushnumber(lua, (int32_t)inum); lua_rawseti(lua, 3, eidx++); rp += sizeof(inum); size -= sizeof(inum); } else { size = 0; } break; } case 'I': { if (size >= sizeof(inum)) { std::memcpy(&inum, rp, sizeof(inum)); lua_pushnumber(lua, (uint32_t)inum); lua_rawseti(lua, 3, eidx++); rp += sizeof(inum); size -= sizeof(inum); } else { size = 0; } break; } case 'l': { if (size >= sizeof(lnum)) { std::memcpy(&lnum, rp, sizeof(lnum)); lua_pushnumber(lua, (int64_t)lnum); lua_rawseti(lua, 3, eidx++); rp += sizeof(lnum); size -= sizeof(lnum); } else { size = 0; } break; } case 'L': { if (size >= sizeof(lnum)) { std::memcpy(&lnum, rp, sizeof(lnum)); lua_pushnumber(lua, (uint64_t)lnum); lua_rawseti(lua, 3, eidx++); rp += sizeof(lnum); size -= sizeof(lnum); } else { size = 0; } break; } case 'f': case 'F': { if (size >= sizeof(fnum)) { std::memcpy(&fnum, rp, sizeof(fnum)); lua_pushnumber(lua, (float)fnum); lua_rawseti(lua, 3, eidx++); rp += sizeof(fnum); size -= sizeof(fnum); } else { size = 0; } break; } case 'd': case 'D': { if (size >= sizeof(dnum)) { std::memcpy(&dnum, rp, sizeof(dnum)); lua_pushnumber(lua, (double)dnum); lua_rawseti(lua, 3, eidx++); rp += sizeof(dnum); size -= sizeof(dnum); } else { size = 0; } break; } case 'n': { if (size >= sizeof(snum)) { std::memcpy(&snum, rp, sizeof(snum)); snum = kc::ntoh16(snum); lua_pushnumber(lua, (uint16_t)snum); lua_rawseti(lua, 3, eidx++); rp += sizeof(snum); size -= sizeof(snum); } else { size = 0; } break; } case 'N': { if (size >= sizeof(inum)) { std::memcpy(&inum, rp, sizeof(inum)); inum = kc::ntoh32(inum); lua_pushnumber(lua, (uint32_t)inum); lua_rawseti(lua, 3, eidx++); rp += sizeof(inum); size -= sizeof(inum); } else { size = 0; } break; } case 'M': { if (size >= sizeof(lnum)) { std::memcpy(&lnum, rp, sizeof(lnum)); lnum = kc::ntoh64(lnum); lua_pushnumber(lua, (uint64_t)lnum); lua_rawseti(lua, 3, eidx++); rp += sizeof(lnum); size -= sizeof(lnum); } else { size = 0; } break; } case 'w': case 'W': { wnum = 0; do { inum = *(unsigned char*)rp; wnum = wnum * 0x80 + (inum & 0x7f); rp++; size--; } while (inum >= 0x80 && size > 0); lua_pushnumber(lua, (uint64_t)wnum); lua_rawseti(lua, 3, eidx++); break; } } } format++; if (size < 1) break; } return 1; } /** * Implementation of split. */ static int kt_split(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc < 1) throwinvarg(lua, __KCFUNC__); size_t isiz; const char* ibuf = lua_tolstring(lua, 1, &isiz); if (!ibuf) throwinvarg(lua, __KCFUNC__); const char* delims = argc > 1 ? lua_tostring(lua, 2) : NULL; lua_newtable(lua); int32_t lnum = 1; if (delims) { const char* str = ibuf; while (true) { const char* sp = str; while (*str != '\0' && !std::strchr(delims, *str)) { str++; } lua_pushlstring(lua, sp, str - sp); lua_rawseti(lua, -2, lnum++); if (*str == '\0') break; str++; } } else { const char* ptr = ibuf; int32_t size = isiz; while (size >= 0) { const char* rp = ptr; const char* ep = ptr + size; while (rp < ep) { if (*rp == '\0') break; rp++; } lua_pushlstring(lua, ptr, rp - ptr); lua_rawseti(lua, -2, lnum++); rp++; size -= rp - ptr; ptr = rp; } } return 1; } /** * Implementation of codec. */ static int kt_codec(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc != 2) throwinvarg(lua, __KCFUNC__); const char* mode = lua_tostring(lua, 1); size_t isiz; const char* ibuf = lua_tolstring(lua, 2, &isiz); if (!mode || !ibuf) throwinvarg(lua, __KCFUNC__); char* obuf = NULL; size_t osiz = 0; if (*mode == '~') { mode++; if (!kc::stricmp(mode, "url")) { obuf = kc::urldecode(ibuf, &osiz); } else if (!kc::stricmp(mode, "base")) { obuf = kc::basedecode(ibuf, &osiz); } else if (!kc::stricmp(mode, "quote")) { obuf = kc::quotedecode(ibuf, &osiz); } else if (!kc::stricmp(mode, "hex")) { obuf = kc::hexdecode(ibuf, &osiz); } else if (!kc::stricmp(mode, "zlib")) { obuf = kc::ZLIB::decompress(ibuf, isiz, &osiz, kc::ZLIB::RAW); } else if (!kc::stricmp(mode, "deflate")) { obuf = kc::ZLIB::decompress(ibuf, isiz, &osiz, kc::ZLIB::DEFLATE); } else if (!kc::stricmp(mode, "gzip")) { obuf = kc::ZLIB::decompress(ibuf, isiz, &osiz, kc::ZLIB::GZIP); } } else { if (!kc::stricmp(mode, "url")) { obuf = kc::urlencode(ibuf, isiz); osiz = obuf ? std::strlen(obuf) : 0; } else if (!kc::stricmp(mode, "base")) { obuf = kc::baseencode(ibuf, isiz); osiz = obuf ? std::strlen(obuf) : 0; } else if (!kc::stricmp(mode, "quote")) { obuf = kc::quoteencode(ibuf, isiz); osiz = obuf ? std::strlen(obuf) : 0; } else if (!kc::stricmp(mode, "hex")) { obuf = kc::hexencode(ibuf, isiz); osiz = obuf ? std::strlen(obuf) : 0; } else if (!kc::stricmp(mode, "zlib")) { obuf = kc::ZLIB::compress(ibuf, isiz, &osiz, kc::ZLIB::RAW); } else if (!kc::stricmp(mode, "deflate")) { obuf = kc::ZLIB::compress(ibuf, isiz, &osiz, kc::ZLIB::DEFLATE); } else if (!kc::stricmp(mode, "gzip")) { obuf = kc::ZLIB::compress(ibuf, isiz, &osiz, kc::ZLIB::GZIP); } } if (obuf) { lua_pushlstring(lua, obuf, osiz); delete[] obuf; } else { lua_pushnil(lua); } return 1; } /** * Implementation of bit. */ static int kt_bit(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc < 2) throwinvarg(lua, __KCFUNC__); const char* mode = lua_tostring(lua, 1); uint32_t num = lua_tonumber(lua, 2); uint32_t aux = argc > 2 ? lua_tonumber(lua, 3) : 0; if (!mode) throwinvarg(lua, __KCFUNC__); if (!kc::stricmp(mode, "and")) { num &= aux; } else if (!kc::stricmp(mode, "or")) { num |= aux; } else if (!kc::stricmp(mode, "xor")) { num ^= aux; } else if (!kc::stricmp(mode, "not")) { num = ~num; } else if (!kc::stricmp(mode, "left")) { num <<= aux; } else if (!kc::stricmp(mode, "right")) { num >>= aux; } lua_pushnumber(lua, num); return 1; } /** * Implementation of strstr. */ static int kt_strstr(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc < 2) throwinvarg(lua, __KCFUNC__); const char* str = lua_tostring(lua, 1); const char* pat = lua_tostring(lua, 2); if (!str || !pat) throwinvarg(lua, __KCFUNC__); const char* alt = argc > 2 ? lua_tostring(lua, 3) : NULL; if (alt) { std::string xstr; size_t plen = std::strlen(pat); size_t alen = std::strlen(alt); if (plen > 0) { const char* pv; while ((pv = std::strstr(str, pat)) != NULL) { xstr.append(str, pv - str); xstr.append(alt, alen); str = pv + plen; } } xstr.append(str); lua_pushlstring(lua, xstr.data(), xstr.size()); } else { const char* pv = std::strstr(str, pat); if (pv) { int32_t idx = pv - str + 1; lua_pushinteger(lua, idx); } else { lua_pushinteger(lua, 0); } } return 1; } /** * Implementation of strfwm. */ static int kt_strfwm(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc < 2) throwinvarg(lua, __KCFUNC__); const char* str = lua_tostring(lua, 1); const char* pat = lua_tostring(lua, 2); if (!str || !pat) throwinvarg(lua, __KCFUNC__); lua_pushboolean(lua, kc::strfwm(str, pat)); return 1; } /** * Implementation of strbwm. */ static int kt_strbwm(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc < 2) throwinvarg(lua, __KCFUNC__); const char* str = lua_tostring(lua, 1); const char* pat = lua_tostring(lua, 2); if (!str || !pat) throwinvarg(lua, __KCFUNC__); lua_pushboolean(lua, kc::strbwm(str, pat)); return 1; } /** * Implementation of regex. */ static int kt_regex(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc < 2) throwinvarg(lua, __KCFUNC__); const char* str = lua_tostring(lua, 1); const char* pat = lua_tostring(lua, 2); if (!str || !pat) throwinvarg(lua, __KCFUNC__); const char* alt = argc > 2 ? lua_tostring(lua, 3) : NULL; if (alt) { std::string xstr = kc::Regex::replace(str, pat, alt); lua_pushlstring(lua, xstr.data(), xstr.size()); } else { bool rv = kc::Regex::match(str, pat); lua_pushboolean(lua, rv); } return 1; } /** * Implementation of arraydump. */ static int kt_arraydump(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); size_t rnum = lua_objlen(lua, 1); std::string rstr; rstr.reserve(rnum * 16 + 256); for (size_t i = 1; i <= rnum; i++) { lua_rawgeti(lua, 1, i); char vnbuf[kc::NUMBUFSIZ]; const char* vbuf = NULL; size_t vsiz = 0; switch (lua_type(lua, -1)) { case LUA_TNUMBER: { double num = lua_tonumber(lua, -1); if (num == std::floor(num)) { vsiz = std::sprintf(vnbuf, "%lld", (long long)num); } else { vsiz = std::snprintf(vnbuf, sizeof(vnbuf), "%.6f", num); vnbuf[sizeof(vnbuf)-1] = '\0'; } vbuf = vnbuf; break; } case LUA_TSTRING: { vbuf = lua_tolstring(lua, -1, &vsiz); break; } } if (vbuf) { char nbuf[kc::NUMBUFSIZ]; size_t nsiz = kc::writevarnum(nbuf, vsiz); rstr.append(nbuf, nsiz); rstr.append(vbuf, vsiz); } lua_pop(lua, 1); } lua_pushlstring(lua, rstr.data(), rstr.size()); return 1; } /** * Implementation of arrayload. */ static int kt_arrayload(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc != 1) throwinvarg(lua, __KCFUNC__); size_t size; const char* rp = lua_tolstring(lua, 1, &size); if (!rp) throwinvarg(lua, __KCFUNC__); lua_newtable(lua); int32_t idx = 1; while (size > 0) { uint64_t vsiz; size_t step = kc::readvarnum(rp, size, &vsiz); rp += step; size -= step; if (vsiz > size) break; lua_pushlstring(lua, rp, vsiz); lua_rawseti(lua, -2, idx++); rp += vsiz; size -= vsiz; } return 1; } /** * Implementation of mapdump. */ static int kt_mapdump(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); std::string rstr; rstr.reserve(512); lua_pushnil(lua); while (lua_next(lua, 1) != 0) { char knbuf[kc::NUMBUFSIZ]; const char* kbuf = NULL; size_t ksiz = 0; switch (lua_type(lua, -2)) { case LUA_TNUMBER: { double num = lua_tonumber(lua, -2); if (num == std::floor(num)) { ksiz = std::sprintf(knbuf, "%lld", (long long)num); } else { ksiz = std::snprintf(knbuf, sizeof(knbuf), "%.6f", num); knbuf[sizeof(knbuf)-1] = '\0'; } kbuf = knbuf; break; } case LUA_TSTRING: { kbuf = lua_tolstring(lua, -2, &ksiz); break; } } char vnbuf[kc::NUMBUFSIZ]; const char* vbuf = NULL; size_t vsiz = 0; switch (lua_type(lua, -1)) { case LUA_TNUMBER: { double num = lua_tonumber(lua, -1); if (num == std::floor(num)) { vsiz = std::sprintf(vnbuf, "%lld", (long long)num); } else { vsiz = std::snprintf(vnbuf, sizeof(vnbuf), "%.6f", num); vnbuf[sizeof(vnbuf)-1] = '\0'; } vbuf = vnbuf; break; } case LUA_TSTRING: { vbuf = lua_tolstring(lua, -1, &vsiz); break; } } if (kbuf && vbuf) { char nbuf[kc::NUMBUFSIZ*2]; size_t nsiz = kc::writevarnum(nbuf, ksiz); nsiz += kc::writevarnum(nbuf + nsiz, vsiz); rstr.append(nbuf, nsiz); rstr.append(kbuf, ksiz); rstr.append(vbuf, vsiz); } lua_pop(lua, 1); } lua_pushlstring(lua, rstr.data(), rstr.size()); return 1; } /** * Implementation of mapload. */ static int kt_mapload(lua_State *lua) { int32_t argc = lua_gettop(lua); if (argc != 1) throwinvarg(lua, __KCFUNC__); size_t size; const char* rp = lua_tolstring(lua, 1, &size); if (!rp) throwinvarg(lua, __KCFUNC__); lua_newtable(lua); while (size > 1) { uint64_t ksiz; size_t step = kc::readvarnum(rp, size, &ksiz); rp += step; size -= step; if (size < 1) break; uint64_t vsiz; step = kc::readvarnum(rp, size, &vsiz); rp += step; size -= step; size_t rsiz = ksiz + vsiz; if (rsiz > size) break; lua_pushlstring(lua, rp, ksiz); lua_pushlstring(lua, rp + ksiz, vsiz); lua_settable(lua, -3); rp += rsiz; size -= rsiz; } return 1; } /** * Define objects of the Error class. */ static void define_err(lua_State* lua) { lua_newtable(lua); setfielduint(lua, "SUCCESS", kc::BasicDB::Error::SUCCESS); setfielduint(lua, "NOIMPL", kc::BasicDB::Error::NOIMPL); setfielduint(lua, "INVALID", kc::BasicDB::Error::INVALID); setfielduint(lua, "NOREPOS", kc::BasicDB::Error::NOREPOS); setfielduint(lua, "NOPERM", kc::BasicDB::Error::NOPERM); setfielduint(lua, "BROKEN", kc::BasicDB::Error::BROKEN); setfielduint(lua, "DUPREC", kc::BasicDB::Error::DUPREC); setfielduint(lua, "NOREC", kc::BasicDB::Error::NOREC); setfielduint(lua, "LOGIC", kc::BasicDB::Error::LOGIC); setfielduint(lua, "SYSTEM", kc::BasicDB::Error::SYSTEM); setfielduint(lua, "MISC", kc::BasicDB::Error::MISC); setfieldfunc(lua, "new", err_new); lua_newtable(lua); setfieldfunc(lua, "__tostring", err_tostring); lua_setfield(lua, -2, "meta_"); lua_setfield(lua, 1, "Error"); } /** * Implementation of new. */ static int err_new(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 3) throwinvarg(lua, __KCFUNC__); lua_newtable(lua); if (argc > 2 && lua_isnumber(lua, 2) && lua_isstring(lua, 3)) { setfieldvalue(lua, "code_", 2); setfieldvalue(lua, "message_", 3); } else { setfielduint(lua, "code_", 0); setfieldstr(lua, "message_", "error"); } setfieldfunc(lua, "set", err_set); setfieldfunc(lua, "code", err_code); setfieldfunc(lua, "name", err_name); setfieldfunc(lua, "message", err_message); lua_getfield(lua, 1, "meta_"); lua_setmetatable(lua, -2); return 1; } /** * Implementation of __tostring. */ static int err_tostring(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "code_"); uint32_t code = lua_tonumber(lua, -1); lua_getfield(lua, 1, "message_"); const char* message = lua_tostring(lua, -1); const char* name = kc::BasicDB::Error::codename((kc::BasicDB::Error::Code)code); lua_pushfstring(lua, "%s: %s", name, message); return 1; } /** * Implementation of set. */ static int err_set(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 2 && lua_isnumber(lua, 2) && lua_isstring(lua, 3)) { lua_pushvalue(lua, 2); lua_setfield(lua, 1, "code_"); lua_pushvalue(lua, 3); lua_setfield(lua, 1, "message_"); } lua_pushnil(lua); return 1; } /** * Implementation of code. */ static int err_code(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "code_"); return 1; } /** * Implementation of name. */ static int err_name(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "code_"); uint32_t code = lua_tonumber(lua, -1); const char* name = kc::BasicDB::Error::codename((kc::BasicDB::Error::Code)code); lua_pushstring(lua, name); return 1; } /** * Implementation of message. */ static int err_message(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "message_"); return 1; } /** * Define objects of the Visitor class. */ static void define_vis(lua_State* lua) { lua_newtable(lua); lua_pushlightuserdata(lua, (void*)kt::TimedDB::Visitor::NOP); lua_setfield(lua, -2, "NOP"); lua_pushlightuserdata(lua, (void*)kt::TimedDB::Visitor::REMOVE); lua_setfield(lua, -2, "REMOVE"); setfieldfunc(lua, "new", vis_new); lua_newtable(lua); lua_setfield(lua, -2, "meta_"); lua_setfield(lua, 1, "Visitor"); } /** * Implementation of new. */ static int vis_new(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_newtable(lua); setfieldfunc(lua, "visit_full", vis_visit_full); setfieldfunc(lua, "visit_empty", vis_visit_empty); lua_getfield(lua, 1, "meta_"); lua_setmetatable(lua, -2); return 1; } /** * Implementation of visit_full. */ static int vis_visit_full(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_pushnil(lua); return 1; } /** * Implementation of visit_empty. */ static int vis_visit_empty(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_pushnil(lua); return 1; } /** * Define objects of the FileProcessor class. */ static void define_fproc(lua_State* lua) { lua_newtable(lua); setfieldfunc(lua, "new", fproc_new); lua_newtable(lua); lua_setfield(lua, -2, "meta_"); lua_setfield(lua, 1, "FileProcessor"); } /** * Implementation of new. */ static int fproc_new(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_newtable(lua); setfieldfunc(lua, "process", fproc_process); lua_getfield(lua, 1, "meta_"); lua_setmetatable(lua, -2); return 1; } /** * Implementation of process. */ static int fproc_process(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 4 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_pushboolean(lua, true); return 1; } /** * Define objects of the Cursor class. */ static void define_cur(lua_State* lua) { lua_newtable(lua); setfieldfunc(lua, "new", cur_new); lua_newtable(lua); setfieldfunc(lua, "__tostring", cur_tostring); setfieldfunc(lua, "__call", cur_call); lua_setfield(lua, -2, "meta_"); lua_setfield(lua, 1, "Cursor"); } /** * Implementation of new. */ static int cur_new(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1) || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 2, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); lua_newtable(lua); g_curbur.sweap(); SoftCursor* cur = (SoftCursor*)lua_newuserdata(lua, sizeof(*cur)); cur->cur = db->db->cursor(); lua_newtable(lua); setfieldfunc(lua, "__gc", cur_gc); lua_setmetatable(lua, -2); lua_setfield(lua, -2, "cur_ptr_"); lua_pushvalue(lua, 2); lua_setfield(lua, -2, "db_"); setfieldfunc(lua, "disable", cur_disable); setfieldfunc(lua, "accept", cur_accept); setfieldfunc(lua, "set_value", cur_set_value); setfieldfunc(lua, "remove", cur_remove); setfieldfunc(lua, "get_key", cur_get_key); setfieldfunc(lua, "get_value", cur_get_value); setfieldfunc(lua, "get", cur_get); setfieldfunc(lua, "seize", cur_seize); setfieldfunc(lua, "jump", cur_jump); setfieldfunc(lua, "jump_back", cur_jump_back); setfieldfunc(lua, "step", cur_step); setfieldfunc(lua, "step_back", cur_step_back); setfieldfunc(lua, "db", cur_db); setfieldfunc(lua, "error", cur_error); lua_getfield(lua, 1, "meta_"); lua_setmetatable(lua, -2); return 1; } /** * Implementation of __gc. */ static int cur_gc(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_isuserdata(lua, 1)) return 0; SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, 1); if (!cur) return 0; if (cur->cur) g_curbur.deposit(cur->cur); return 0; } /** * Implementation of __tostring. */ static int cur_tostring(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) { lua_pushstring(lua, "(disabled)"); return 1; } kt::TimedDB* db = cur->cur->db(); std::string path = db->path(); if (path.size() < 1) path = "(nil)"; std::string str = kc::strprintf("%s: ", path.c_str()); size_t ksiz; char* kbuf = cur->cur->get_key(&ksiz); if (kbuf) { str.append(kbuf, ksiz); delete[] kbuf; } else { str.append("(nil)"); } lua_pushstring(lua, str.c_str()); return 1; } /** * Implementation of __call. */ static int cur_call(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); const char* vbuf; size_t ksiz, vsiz; int64_t xt; char* kbuf = cur->cur->get(&ksiz, &vbuf, &vsiz, &xt, true); if (kbuf) { lua_pushlstring(lua, kbuf, ksiz); lua_pushlstring(lua, vbuf, vsiz); delete[] kbuf; return 2; } lua_pushnil(lua); return 1; } /** * Implementation of disable. */ static int cur_disable(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); delete cur->cur; cur->cur = NULL; lua_pushnil(lua); lua_setfield(lua, 1, "cur_ptr_"); lua_pushnil(lua); return 1; } /** * Implementation of accept. */ static int cur_accept(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); bool writable = argc > 2 ? lua_toboolean(lua, 3) : true; bool step = argc > 3 ? lua_toboolean(lua, 4) : false; bool rv; if (lua_istable(lua, 2) || lua_isfunction(lua, 2)) { lua_pushvalue(lua, 2); SoftVisitor visitor(lua, writable); rv = cur->cur->accept(&visitor, writable, step); } else { throwinvarg(lua, __KCFUNC__); rv = false; } lua_pushboolean(lua, rv); return 1; } /** * Implementation of set_value. */ static int cur_set_value(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); size_t vsiz; const char* vbuf = lua_tolstring(lua, 2, &vsiz); if (!cur || !vsiz) throwinvarg(lua, __KCFUNC__); int64_t xt = argc > 2 && !lua_isnil(lua, 3) ? lua_tonumber(lua, 3) : kc::INT64MAX; bool step = argc > 3 ? lua_toboolean(lua, 4) : false; bool rv = cur->cur->set_value(vbuf, vsiz, step, xt); lua_pushboolean(lua, rv); return 1; } /** * Implementation of remove. */ static int cur_remove(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); bool rv = cur->cur->remove(); lua_pushboolean(lua, rv); return 1; } /** * Implementation of get_key. */ static int cur_get_key(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 2) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); bool step = argc > 1 ? lua_toboolean(lua, 2) : false; size_t ksiz; char* kbuf = cur->cur->get_key(&ksiz, step); if (kbuf) { lua_pushlstring(lua, kbuf, ksiz); delete[] kbuf; } else { lua_pushnil(lua); } return 1; } /** * Implementation of get_value. */ static int cur_get_value(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 2) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); bool step = argc > 1 ? lua_toboolean(lua, 2) : false; size_t vsiz; char* vbuf = cur->cur->get_value(&vsiz, step); if (vbuf) { lua_pushlstring(lua, vbuf, vsiz); delete[] vbuf; } else { lua_pushnil(lua); } return 1; } /** * Implementation of get. */ static int cur_get(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 2) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); bool step = argc > 1 ? lua_toboolean(lua, 2) : false; const char* vbuf; size_t ksiz, vsiz; int64_t xt; char* kbuf = cur->cur->get(&ksiz, &vbuf, &vsiz, &xt, step); if (kbuf) { lua_pushlstring(lua, kbuf, ksiz); lua_pushlstring(lua, vbuf, vsiz); lua_pushnumber(lua, xt < kt::TimedDB::XTMAX ? xt : kt::TimedDB::XTMAX); delete[] kbuf; return 3; } lua_pushnil(lua); return 1; } /** * Implementation of seize. */ static int cur_seize(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); const char* vbuf; size_t ksiz, vsiz; int64_t xt; char* kbuf = cur->cur->seize(&ksiz, &vbuf, &vsiz, &xt); if (kbuf) { lua_pushlstring(lua, kbuf, ksiz); lua_pushlstring(lua, vbuf, vsiz); lua_pushnumber(lua, xt < kt::TimedDB::XTMAX ? xt : kt::TimedDB::XTMAX); delete[] kbuf; return 3; } lua_pushnil(lua); return 1; } /** * Implementation of jump. */ static int cur_jump(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 2) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); bool rv; if (argc > 1) { size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!kbuf) throwinvarg(lua, __KCFUNC__); rv = cur->cur->jump(kbuf, ksiz); } else { rv = cur->cur->jump(); } lua_pushboolean(lua, rv); return 1; } /** * Implementation of jump_back. */ static int cur_jump_back(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 2) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); bool rv; if (argc > 1) { size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!kbuf) throwinvarg(lua, __KCFUNC__); rv = cur->cur->jump_back(kbuf, ksiz); } else { rv = cur->cur->jump_back(); } lua_pushboolean(lua, rv); return 1; } /** * Implementation of step. */ static int cur_step(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); bool rv = cur->cur->step(); lua_pushboolean(lua, rv); return 1; } /** * Implementation of step_back. */ static int cur_step_back(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); bool rv = cur->cur->step_back(); lua_pushboolean(lua, rv); return 1; } /** * Implementation of db. */ static int cur_db(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_"); return 1; } /** * Implementation of error. */ static int cur_error(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_ptr_"); SoftCursor* cur = (SoftCursor*)lua_touserdata(lua, -1); if (!cur) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_"); lua_getfield(lua, -1, "error"); lua_pushvalue(lua, -2); lua_call(lua, 1, 1); return 1; } /** * Define objects of the DB class. */ static void define_db(lua_State* lua) { lua_newtable(lua); setfielduint(lua, "OREADER", kc::BasicDB::OREADER); setfielduint(lua, "OWRITER", kc::BasicDB::OWRITER); setfielduint(lua, "OCREATE", kc::BasicDB::OCREATE); setfielduint(lua, "OTRUNCATE", kc::BasicDB::OTRUNCATE); setfielduint(lua, "OAUTOTRAN", kc::BasicDB::OAUTOTRAN); setfielduint(lua, "OAUTOSYNC", kc::BasicDB::OAUTOSYNC); setfielduint(lua, "ONOLOCK", kc::BasicDB::ONOLOCK); setfielduint(lua, "OTRYLOCK", kc::BasicDB::OTRYLOCK); setfielduint(lua, "ONOREPAIR", kc::BasicDB::ONOREPAIR); setfielduint(lua, "MSET", kc::PolyDB::MSET); setfielduint(lua, "MADD", kc::PolyDB::MADD); setfielduint(lua, "MREPLACE", kc::PolyDB::MREPLACE); setfielduint(lua, "MAPPEND", kc::PolyDB::MAPPEND); setfielduint(lua, "XNOLOCK", kc::MapReduce::XNOLOCK); setfielduint(lua, "XNOCOMP", kc::MapReduce::XNOCOMP); setfieldfunc(lua, "new", db_new); setfieldfunc(lua, "new_ptr", db_new_ptr); setfieldfunc(lua, "delete_ptr", db_delete_ptr); setfieldfunc(lua, "process", db_process); lua_newtable(lua); setfieldfunc(lua, "__tostring", db_tostring); setfieldfunc(lua, "__index", db_index); setfieldfunc(lua, "__newindex", db_newindex); lua_setfield(lua, -2, "meta_"); lua_setfield(lua, 1, "DB"); } /** * Implementation of new. */ static int db_new(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 2) throwinvarg(lua, __KCFUNC__); lua_newtable(lua); SoftDB* db = (SoftDB*)lua_newuserdata(lua, sizeof(*db)); if (argc > 1 && lua_islightuserdata(lua, 2)) { db->db = (kt::TimedDB*)lua_touserdata(lua, 2); db->light = true; } else { db->db = new kt::TimedDB; db->light = false; } lua_newtable(lua); setfieldfunc(lua, "__gc", db_gc); lua_setmetatable(lua, -2); lua_setfield(lua, -2, "db_ptr_"); lua_getglobal(lua, "__kyototycoon__"); lua_getfield(lua, -1, "Error"); lua_setfield(lua, -3, "err_"); lua_getfield(lua, -1, "Cursor"); lua_setfield(lua, -3, "cur_"); lua_pop(lua, 1); setfieldfunc(lua, "error", db_error); setfieldfunc(lua, "open", db_open); setfieldfunc(lua, "close", db_close); setfieldfunc(lua, "accept", db_accept); setfieldfunc(lua, "accept_bulk", db_accept_bulk); setfieldfunc(lua, "iterate", db_iterate); setfieldfunc(lua, "set", db_set); setfieldfunc(lua, "add", db_add); setfieldfunc(lua, "replace", db_replace); setfieldfunc(lua, "append", db_append); setfieldfunc(lua, "increment", db_increment); setfieldfunc(lua, "increment_double", db_increment_double); setfieldfunc(lua, "cas", db_cas); setfieldfunc(lua, "remove", db_remove); setfieldfunc(lua, "get", db_get); setfieldfunc(lua, "check", db_check); setfieldfunc(lua, "seize", db_seize); setfieldfunc(lua, "set_bulk", db_set_bulk); setfieldfunc(lua, "remove_bulk", db_remove_bulk); setfieldfunc(lua, "get_bulk", db_get_bulk); setfieldfunc(lua, "clear", db_clear); setfieldfunc(lua, "synchronize", db_synchronize); setfieldfunc(lua, "occupy", db_occupy); setfieldfunc(lua, "copy", db_copy); setfieldfunc(lua, "begin_transaction", db_begin_transaction); setfieldfunc(lua, "end_transaction", db_end_transaction); setfieldfunc(lua, "transaction", db_transaction); setfieldfunc(lua, "dump_snapshot", db_dump_snapshot); setfieldfunc(lua, "load_snapshot", db_load_snapshot); setfieldfunc(lua, "count", db_count); setfieldfunc(lua, "size", db_size); setfieldfunc(lua, "path", db_path); setfieldfunc(lua, "status", db_status); setfieldfunc(lua, "match_prefix", db_match_prefix); setfieldfunc(lua, "match_regex", db_match_regex); setfieldfunc(lua, "match_similar", db_match_similar); setfieldfunc(lua, "merge", db_merge); setfieldfunc(lua, "mapreduce", db_mapreduce); setfieldfunc(lua, "cursor", db_cursor); setfieldfunc(lua, "cursor_process", db_cursor_process); setfieldfunc(lua, "pairs", db_pairs); lua_getfield(lua, 1, "meta_"); lua_setmetatable(lua, -2); return 1; } /** * Implementation of __gc. */ static int db_gc(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_isuserdata(lua, 1)) return 0; SoftDB* db = (SoftDB*)lua_touserdata(lua, 1); if (!db) return 0; if (!db->light) delete db->db; return 0; } /** * Implementation of __tostring. */ static int db_tostring(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); std::string path = db->db->path(); if (path.size() < 1) path = "(nil)"; std::string str = kc::strprintf("%s: %lld: %lld", path.c_str(), (long long)db->db->count(), (long long)db->db->size()); lua_pushstring(lua, str.c_str()); return 1; } /** * Implementation of __index. */ static int db_index(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); size_t vsiz; char* vbuf = db->db->get(kbuf, ksiz, &vsiz); if (vbuf) { lua_pushlstring(lua, vbuf, vsiz); delete[] vbuf; } else { lua_pushnil(lua); } return 1; } /** * Implementation of __newindex. */ static int db_newindex(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); size_t vsiz; const char* vbuf = lua_tolstring(lua, 3, &vsiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); bool rv; if (vbuf) { rv = db->db->set(kbuf, ksiz, vbuf, vsiz); } else { rv = db->db->remove(kbuf, ksiz); } lua_pushboolean(lua, rv); return 1; } /** * Implementation of new_ptr. */ static int db_new_ptr(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); kt::TimedDB* db = new kt::TimedDB; lua_pushlightuserdata(lua, (void*)db); return 1; } /** * Implementation of delete_ptr. */ static int db_delete_ptr(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (lua_islightuserdata(lua, 2)) { kt::TimedDB* db = (kt::TimedDB*)lua_touserdata(lua, 2); delete db; } lua_pushnil(lua); return 1; } /** * Implementation of process. */ static int db_process(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); if (!lua_isfunction(lua, 2)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "new"); lua_pushvalue(lua, 1); lua_call(lua, 1, 1); int32_t objidx = lua_gettop(lua); lua_getfield(lua, objidx, "open"); lua_pushvalue(lua, objidx); if (argc > 2) lua_pushvalue(lua, 3); if (argc > 3) lua_pushvalue(lua, 4); lua_call(lua, argc - 1, 1); if (!lua_toboolean(lua, -1)) { lua_getfield(lua, objidx, "error"); lua_pushvalue(lua, objidx); lua_call(lua, 1, 1); return 1; } lua_pushvalue(lua, 2); lua_pushvalue(lua, objidx); int32_t erridx = 0; if (lua_pcall(lua, 1, 0, 0) != 0) erridx = lua_gettop(lua); lua_getfield(lua, objidx, "close"); lua_pushvalue(lua, objidx); lua_call(lua, 1, 1); if (erridx > 0) { lua_pushvalue(lua, erridx); lua_error(lua); } if (!lua_toboolean(lua, -1)) { lua_getfield(lua, objidx, "error"); lua_pushvalue(lua, objidx); lua_call(lua, 1, 1); return 1; } lua_pushnil(lua); return 1; } /** * Implementation of error. */ static int db_error(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); kc::BasicDB::Error err = db->db->error(); lua_getfield(lua, 1, "err_"); lua_getfield(lua, -1, "new"); lua_pushvalue(lua, -2); lua_pushinteger(lua, err.code()); lua_pushstring(lua, err.message()); lua_call(lua, 3, 1); return 1; } /** * Implementation of open. */ static int db_open(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 3) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); const char* path = ":"; if (argc > 1 && lua_isstring(lua, 2)) path = lua_tostring(lua, 2); uint32_t mode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE; if (argc > 2 && lua_isnumber(lua, 3)) mode = lua_tonumber(lua, 3); bool rv = db->db->open(path, mode); lua_pushboolean(lua, rv); return 1; } /** * Implementation of close. */ static int db_close(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); g_curbur.sweap(); bool rv = db->db->close(); lua_pushboolean(lua, rv); return 1; } /** * Implementation of accept. */ static int db_accept(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); bool writable = argc > 3 ? lua_toboolean(lua, 4) : true; bool rv; if (lua_istable(lua, 3) || lua_isfunction(lua, 3)) { lua_pushvalue(lua, 3); SoftVisitor visitor(lua, writable); rv = db->db->accept(kbuf, ksiz, &visitor, writable); } else { throwinvarg(lua, __KCFUNC__); rv = false; } lua_pushboolean(lua, rv); return 1; } /** * Implementation of accept_bulk. */ static int db_accept_bulk(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__); size_t knum = lua_objlen(lua, 2); StringVector keys; keys.reserve(knum); for (size_t i = 1; i <= knum; i++) { lua_rawgeti(lua, 2, i); size_t ksiz; const char* kbuf = lua_tolstring(lua, -1, &ksiz); if (kbuf) keys.push_back(std::string(kbuf, ksiz)); lua_pop(lua, 1); } bool writable = argc > 3 ? lua_toboolean(lua, 4) : true; bool rv; if (lua_istable(lua, 3) || lua_isfunction(lua, 3)) { lua_pushvalue(lua, 3); SoftVisitor visitor(lua, writable); rv = db->db->accept_bulk(keys, &visitor, writable); } else { throwinvarg(lua, __KCFUNC__); rv = false; } lua_pushboolean(lua, rv); return 1; } /** * Implementation of iterate. */ static int db_iterate(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 3) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); bool writable = argc > 2 ? lua_toboolean(lua, 3) : true; bool rv; if (lua_istable(lua, 2) || lua_isfunction(lua, 2)) { lua_pushvalue(lua, 2); SoftVisitor visitor(lua, writable); rv = db->db->iterate(&visitor, writable); } else { throwinvarg(lua, __KCFUNC__); rv = false; } lua_pushboolean(lua, rv); return 1; } /** * Implementation of set. */ static int db_set(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); size_t vsiz; const char* vbuf = lua_tolstring(lua, 3, &vsiz); if (!db || !kbuf || !vbuf) throwinvarg(lua, __KCFUNC__); int64_t xt = argc > 3 && !lua_isnil(lua, 4) ? lua_tonumber(lua, 4) : kc::INT64MAX; bool rv = db->db->set(kbuf, ksiz, vbuf, vsiz, xt); lua_pushboolean(lua, rv); return 1; } /** * Implementation of add. */ static int db_add(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); size_t vsiz; const char* vbuf = lua_tolstring(lua, 3, &vsiz); if (!db || !kbuf || !vbuf) throwinvarg(lua, __KCFUNC__); int64_t xt = argc > 3 && !lua_isnil(lua, 4) ? lua_tonumber(lua, 4) : kc::INT64MAX; bool rv = db->db->add(kbuf, ksiz, vbuf, vsiz, xt); lua_pushboolean(lua, rv); return 1; } /** * Implementation of replace. */ static int db_replace(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); size_t vsiz; const char* vbuf = lua_tolstring(lua, 3, &vsiz); if (!db || !kbuf || !vbuf) throwinvarg(lua, __KCFUNC__); int64_t xt = argc > 3 && !lua_isnil(lua, 4) ? lua_tonumber(lua, 4) : kc::INT64MAX; bool rv = db->db->replace(kbuf, ksiz, vbuf, vsiz, xt); lua_pushboolean(lua, rv); return 1; } /** * Implementation of append. */ static int db_append(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); size_t vsiz; const char* vbuf = lua_tolstring(lua, 3, &vsiz); if (!db || !kbuf || !vbuf) throwinvarg(lua, __KCFUNC__); int64_t xt = argc > 3 && !lua_isnil(lua, 4) ? lua_tonumber(lua, 4) : kc::INT64MAX; bool rv = db->db->append(kbuf, ksiz, vbuf, vsiz, xt); lua_pushboolean(lua, rv); return 1; } /** * Implementation of increment. */ static int db_increment(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 5) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); int64_t num = argc > 2 ? lua_tonumber(lua, 3) : 0; double orig = argc > 3 ? lua_tonumber(lua, 4) : 0; int64_t orint; if (kc::chkinf(orig)) { orint = orig >= 0 ? kc::INT64MAX : kc::INT64MIN; } else { orint = orig; } int64_t xt = argc > 4 && !lua_isnil(lua, 5) ? lua_tonumber(lua, 5) : kc::INT64MAX; num = db->db->increment(kbuf, ksiz, num, orint, xt); if (num == kc::INT64MIN) { lua_pushnil(lua); } else { lua_pushnumber(lua, num); } return 1; } /** * Implementation of increment_double. */ static int db_increment_double(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 5) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); double num = argc > 2 ? lua_tonumber(lua, 3) : 0; double orig = argc > 3 ? lua_tonumber(lua, 4) : 0; int64_t xt = argc > 4 && !lua_isnil(lua, 5) ? lua_tonumber(lua, 5) : kc::INT64MAX; num = db->db->increment_double(kbuf, ksiz, num, orig, xt); if (kc::chknan(num)) { lua_pushnil(lua); } else { lua_pushnumber(lua, num); } return 1; } /** * Implementation of cas. */ static int db_cas(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 4 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 5) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); size_t ovsiz; const char* ovbuf = lua_tolstring(lua, 3, &ovsiz); size_t nvsiz; const char* nvbuf = lua_tolstring(lua, 4, &nvsiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); int64_t xt = argc > 4 && !lua_isnil(lua, 5) ? lua_tonumber(lua, 5) : kc::INT64MAX; bool rv = db->db->cas(kbuf, ksiz, ovbuf, ovsiz, nvbuf, nvsiz, xt); lua_pushboolean(lua, rv); return 1; } /** * Implementation of remove. */ static int db_remove(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); bool rv = db->db->remove(kbuf, ksiz); lua_pushboolean(lua, rv); return 1; } /** * Implementation of get. */ static int db_get(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); size_t vsiz; int64_t xt; char* vbuf = db->db->get(kbuf, ksiz, &vsiz, &xt); if (vbuf) { lua_pushlstring(lua, vbuf, vsiz); lua_pushnumber(lua, xt < kt::TimedDB::XTMAX ? xt : kt::TimedDB::XTMAX); delete[] vbuf; return 2; } lua_pushnil(lua); return 1; } /** * Implementation of check. */ static int db_check(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); int32_t vsiz = db->db->check(kbuf, ksiz); lua_pushnumber(lua, vsiz); return 1; } /** * Implementation of seize. */ static int db_seize(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t ksiz; const char* kbuf = lua_tolstring(lua, 2, &ksiz); if (!db || !kbuf) throwinvarg(lua, __KCFUNC__); size_t vsiz; int64_t xt; char* vbuf = db->db->seize(kbuf, ksiz, &vsiz, &xt); if (vbuf) { lua_pushlstring(lua, vbuf, vsiz); lua_pushnumber(lua, xt < kt::TimedDB::XTMAX ? xt : kt::TimedDB::XTMAX); delete[] vbuf; return 2; } lua_pushnil(lua); return 1; } /** * Implementation of set_bulk. */ static int db_set_bulk(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 4) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__); StringMap recs; lua_pushnil(lua); while (lua_next(lua, 2) != 0) { char knbuf[kc::NUMBUFSIZ]; const char* kbuf = NULL; size_t ksiz = 0; switch (lua_type(lua, -2)) { case LUA_TNUMBER: { double num = lua_tonumber(lua, -2); if (num == std::floor(num)) { ksiz = std::sprintf(knbuf, "%lld", (long long)num); } else { ksiz = std::snprintf(knbuf, sizeof(knbuf), "%.6f", num); knbuf[sizeof(knbuf)-1] = '\0'; } kbuf = knbuf; break; } case LUA_TSTRING: { kbuf = lua_tolstring(lua, -2, &ksiz); break; } } char vnbuf[kc::NUMBUFSIZ]; const char* vbuf = NULL; size_t vsiz = 0; switch (lua_type(lua, -1)) { case LUA_TNUMBER: { double num = lua_tonumber(lua, -1); if (num == std::floor(num)) { vsiz = std::sprintf(vnbuf, "%lld", (long long)num); } else { vsiz = std::snprintf(vnbuf, sizeof(vnbuf), "%.6f", num); vnbuf[sizeof(vnbuf)-1] = '\0'; } vbuf = vnbuf; break; } case LUA_TSTRING: { vbuf = lua_tolstring(lua, -1, &vsiz); break; } } if (kbuf && vbuf) recs[std::string(kbuf, ksiz)] = std::string(vbuf, vsiz); lua_pop(lua, 1); } int64_t xt = argc > 2 && !lua_isnil(lua, 3) ? lua_tonumber(lua, 3) : kc::INT64MAX; bool atomic = argc > 3 ? lua_toboolean(lua, 4) : true; int64_t rv = db->db->set_bulk(recs, xt, atomic); lua_pushnumber(lua, rv); return 1; } /** * Implementation of remove_bulk. */ static int db_remove_bulk(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 3) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__); size_t knum = lua_objlen(lua, 2); StringVector keys; keys.reserve(knum); for (size_t i = 1; i <= knum; i++) { lua_rawgeti(lua, 2, i); size_t ksiz; const char* kbuf = lua_tolstring(lua, -1, &ksiz); if (kbuf) keys.push_back(std::string(kbuf, ksiz)); lua_pop(lua, 1); } bool atomic = argc > 2 ? lua_toboolean(lua, 3) : true; int64_t rv = db->db->remove_bulk(keys, atomic); lua_pushnumber(lua, rv); return 1; } /** * Implementation of get_bulk. */ static int db_get_bulk(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 3) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__); size_t knum = lua_objlen(lua, 2); StringVector keys; keys.reserve(knum); for (size_t i = 1; i <= knum; i++) { lua_rawgeti(lua, 2, i); size_t ksiz; const char* kbuf = lua_tolstring(lua, -1, &ksiz); if (kbuf) keys.push_back(std::string(kbuf, ksiz)); lua_pop(lua, 1); } bool atomic = argc > 2 ? lua_toboolean(lua, 3) : true; StringMap recs; int64_t rv = db->db->get_bulk(keys, &recs, atomic); if (rv < 0) { lua_pushnil(lua); } else { lua_newtable(lua); StringMap::const_iterator it = recs.begin(); StringMap::const_iterator itend = recs.end(); while (it != itend) { lua_pushlstring(lua, it->first.data(), it->first.size()); lua_pushlstring(lua, it->second.data(), it->second.size()); lua_settable(lua, -3); ++it; } } return 1; } /** * Implementation of clear. */ static int db_clear(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); bool rv = db->db->clear(); lua_pushboolean(lua, rv); return 1; } /** * Implementation of synchronize. */ static int db_synchronize(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 3) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); bool hard = argc > 1 ? lua_toboolean(lua, 2) : false; bool rv; if (argc > 2 && (lua_istable(lua, 3) || lua_isfunction(lua, 3))) { lua_pushvalue(lua, 3); SoftFileProcessor proc(lua); rv = db->db->synchronize(hard, &proc); } else { rv = db->db->synchronize(hard, NULL); } lua_pushboolean(lua, rv); return 1; } /** * Implementation of occupy. */ static int db_occupy(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 3) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); bool writable = argc > 1 ? lua_toboolean(lua, 2) : false; bool rv; if (argc > 2 && (lua_istable(lua, 3) || lua_isfunction(lua, 3))) { lua_pushvalue(lua, 3); SoftFileProcessor proc(lua); rv = db->db->occupy(writable, &proc); } else { rv = db->db->occupy(writable, NULL); } lua_pushboolean(lua, rv); return 1; } /** * Implementation of copy. */ static int db_copy(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); const char* dest = lua_tostring(lua, 2); if (!db || !dest) throwinvarg(lua, __KCFUNC__); bool rv = db->db->copy(dest); lua_pushboolean(lua, rv); return 1; } /** * Implementation of begin_transaction. */ static int db_begin_transaction(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 2) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); bool hard = argc > 1 ? lua_toboolean(lua, 2) : false; bool rv = db->db->begin_transaction(hard); lua_pushboolean(lua, rv); return 1; } /** * Implementation of end_transaction. */ static int db_end_transaction(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 2) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); bool commit = argc > 1 ? lua_toboolean(lua, 2) : true; bool rv = db->db->end_transaction(commit); lua_pushboolean(lua, rv); return 1; } /** * Implementation of transaction. */ static int db_transaction(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 3) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); bool hard = argc > 2 ? lua_toboolean(lua, 3) : false; lua_getfield(lua, 1, "begin_transaction"); lua_pushvalue(lua, 1); lua_pushboolean(lua, hard); lua_call(lua, 2, 1); if (!lua_toboolean(lua, -1)) return 1; lua_pushvalue(lua, 2); int32_t erridx = 0; if (lua_pcall(lua, 0, 1, 0) != 0) erridx = lua_gettop(lua); bool commit = erridx == 0 && lua_toboolean(lua, -1); lua_getfield(lua, 1, "end_transaction"); lua_pushvalue(lua, 1); lua_pushboolean(lua, commit); lua_call(lua, 2, 1); if (erridx > 0) { lua_pushvalue(lua, erridx); lua_error(lua); } return 1; } /** * Implementation of dump_snapshot. */ static int db_dump_snapshot(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); const char* dest = lua_tostring(lua, 2); if (!db || !dest) throwinvarg(lua, __KCFUNC__); bool rv = db->db->dump_snapshot(dest); lua_pushboolean(lua, rv); return 1; } /** * Implementation of load_snapshot. */ static int db_load_snapshot(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); const char* src = lua_tostring(lua, 2); if (!db || !src) throwinvarg(lua, __KCFUNC__); bool rv = db->db->load_snapshot(src); lua_pushboolean(lua, rv); return 1; } /** * Implementation of count. */ static int db_count(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); int64_t count = db->db->count(); lua_pushnumber(lua, count); return 1; } /** * Implementation of size. */ static int db_size(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); int64_t size = db->db->size(); lua_pushnumber(lua, size); return 1; } /** * Implementation of path. */ static int db_path(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); const std::string& path = db->db->path(); if (path.size() > 0) { lua_pushstring(lua, path.c_str()); } else { lua_pushnil(lua); } return 1; } /** * Implementation of status. */ static int db_status(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); StringMap status; bool rv = db->db->status(&status); if (rv) { lua_newtable(lua); StringMap::const_iterator it = status.begin(); StringMap::const_iterator itend = status.end(); while (it != itend) { lua_pushlstring(lua, it->first.data(), it->first.size()); lua_pushlstring(lua, it->second.data(), it->second.size()); lua_settable(lua, -3); ++it; } } else { lua_pushnil(lua); } return 1; } /** * Implementation of match_prefix. */ static int db_match_prefix(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t psiz; const char* pbuf = lua_tolstring(lua, 2, &psiz); if (!db || !pbuf) throwinvarg(lua, __KCFUNC__); int64_t max = argc > 2 ? lua_tonumber(lua, 3) : -1; StringVector keys; int64_t num = db->db->match_prefix(std::string(pbuf, psiz), &keys, max); if (num >= 0) { lua_newtable(lua); StringVector::const_iterator it = keys.begin(); StringVector::const_iterator itend = keys.end(); int32_t idx = 1; while (it != itend) { lua_pushlstring(lua, it->data(), it->size()); lua_rawseti(lua, -2, idx++); ++it; } } else { lua_pushnil(lua); } return 1; } /** * Implementation of match_regex. */ static int db_match_regex(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t rsiz; const char* rbuf = lua_tolstring(lua, 2, &rsiz); if (!db || !rbuf) throwinvarg(lua, __KCFUNC__); int64_t max = argc > 2 ? lua_tonumber(lua, 3) : -1; StringVector keys; int64_t num = db->db->match_regex(std::string(rbuf, rsiz), &keys, max); if (num >= 0) { lua_newtable(lua); StringVector::const_iterator it = keys.begin(); StringVector::const_iterator itend = keys.end(); int32_t idx = 1; while (it != itend) { lua_pushlstring(lua, it->data(), it->size()); lua_rawseti(lua, -2, idx++); ++it; } } else { lua_pushnil(lua); } return 1; } /** * Implementation of match_similar. */ static int db_match_similar(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); size_t osiz; const char* obuf = lua_tolstring(lua, 2, &osiz); if (!db || !obuf) throwinvarg(lua, __KCFUNC__); int64_t range = argc > 2 ? lua_tonumber(lua, 3) : -1; bool utf = argc > 3 ? lua_toboolean(lua, 4) : false; int64_t max = argc > 4 ? lua_tonumber(lua, 5) : -1; StringVector keys; int64_t num = db->db->match_similar(std::string(obuf, osiz), range, utf, &keys, max); if (num >= 0) { lua_newtable(lua); StringVector::const_iterator it = keys.begin(); StringVector::const_iterator itend = keys.end(); int32_t idx = 1; while (it != itend) { lua_pushlstring(lua, it->data(), it->size()); lua_rawseti(lua, -2, idx++); ++it; } } else { lua_pushnil(lua); } return 1; } /** * Implementation of merge. */ static int db_merge(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 2 || !lua_istable(lua, 1) || !lua_istable(lua, 2)) throwinvarg(lua, __KCFUNC__); if (argc > 3) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); uint32_t mode = kt::TimedDB::MSET; if (argc > 2 && lua_isnumber(lua, 3)) mode = lua_tonumber(lua, 3); size_t num = lua_objlen(lua, 2); if (num < 1) { lua_pushboolean(lua, true); return 1; } kt::TimedDB** srcary = new kt::TimedDB*[num]; size_t srcnum = 0; for (size_t i = 1; i <= num; i++) { lua_rawgeti(lua, 2, i); if (lua_istable(lua, -1)) { lua_getfield(lua, -1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); srcary[srcnum++] = db->db; lua_pop(lua, 1); } lua_pop(lua, 1); } bool rv = db->db->merge(srcary, srcnum, (kt::TimedDB::MergeMode)mode); delete[] srcary; lua_pushboolean(lua, rv); return 1; } /** * Implementation of mapreduce. */ static int db_mapreduce(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc < 3 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (argc > 10) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); if (!db || !lua_isfunction(lua, 2) || !lua_isfunction(lua, 3)) throwinvarg(lua, __KCFUNC__); const char* tmppath = argc > 3 ? lua_tostring(lua, 4) : NULL; if (!tmppath) tmppath = ""; uint32_t opts = argc > 4 ? lua_tonumber(lua, 5) : 0; int32_t dbnum = argc > 5 ? lua_tonumber(lua, 6) : -1; int64_t clim = argc > 6 ? lua_tonumber(lua, 7) : -1; int64_t cbnum = argc > 7 ? lua_tonumber(lua, 8) : -1; int32_t logidx = -1; if (argc > 8 && lua_isfunction(lua, 9)) logidx = 9; int32_t procidx = -1; if (argc > 9 && lua_isfunction(lua, 10)) procidx = 10; SoftMapReduce mr(lua, logidx, procidx); mr.tune_storage(dbnum, clim, cbnum); bool rv = mr.execute(db->db, tmppath, opts); lua_pushnil(lua); lua_setglobal(lua, "__mr_iter"); lua_pushnil(lua); lua_setglobal(lua, "__mr_self"); lua_pushboolean(lua, rv); return 1; } /** * Implementation of mapreduce_emit. */ static int db_mapreduce_emit(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2) throwinvarg(lua, __KCFUNC__); size_t ksiz; const char* kbuf = lua_tolstring(lua, 1, &ksiz); size_t vsiz; const char* vbuf = lua_tolstring(lua, 2, &vsiz); if (!kbuf || !vbuf) throwinvarg(lua, __KCFUNC__); lua_getglobal(lua, "__mr_self"); SoftMapReduce* mr = (SoftMapReduce*)lua_touserdata(lua, -1); bool rv; if (mr) { rv = mr->emit_public(kbuf, ksiz, vbuf, vsiz); } else { rv = false; } lua_pushboolean(lua, rv); return 1; } /** * Implementation of mapreduce_iter. */ static int db_mapreduce_iter(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 0) throwinvarg(lua, __KCFUNC__); lua_getglobal(lua, "__mr_iter"); kc::MapReduce::ValueIterator* iter = (kc::MapReduce::ValueIterator*)lua_touserdata(lua, -1); if (iter) { size_t vsiz; const char* vbuf = iter->next(&vsiz); if (vbuf) { lua_pushlstring(lua, vbuf, vsiz); } else { lua_pushnil(lua); } } else { lua_pushnil(lua); } return 1; } /** * Implementation of cursor. */ static int db_cursor(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_"); lua_getfield(lua, -1, "new"); lua_getfield(lua, 1, "cur_"); lua_pushvalue(lua, 1); lua_call(lua, 2, 1); return 1; } /** * Implementation of cursor_process. */ static int db_cursor_process(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); if (!lua_isfunction(lua, 2)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_"); lua_getfield(lua, -1, "new"); lua_getfield(lua, 1, "cur_"); lua_pushvalue(lua, 1); lua_call(lua, 2, 1); int32_t objidx = lua_gettop(lua); lua_pushvalue(lua, 2); lua_pushvalue(lua, objidx); int32_t erridx = 0; if (lua_pcall(lua, 1, 0, 0) != 0) erridx = lua_gettop(lua); lua_getfield(lua, objidx, "disable"); lua_pushvalue(lua, objidx); lua_call(lua, 1, 0); if (erridx > 0) { lua_pushvalue(lua, erridx); lua_error(lua); } return 0; } /** * Implementation of pairs. */ static int db_pairs(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 1 || !lua_istable(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "db_ptr_"); SoftDB* db = (SoftDB*)lua_touserdata(lua, -1); if (!db) throwinvarg(lua, __KCFUNC__); lua_getfield(lua, 1, "cur_"); lua_getfield(lua, -1, "new"); lua_getfield(lua, 1, "cur_"); lua_pushvalue(lua, 1); lua_call(lua, 2, 1); lua_getfield(lua, -1, "jump"); lua_pushvalue(lua, -2); lua_call(lua, 1, 0); lua_pushvalue(lua, 1); lua_pushnil(lua); return 3; } /** * Implementation of log. */ static int serv_log(lua_State* lua) { int32_t argc = lua_gettop(lua); if (argc != 2 || !lua_isstring(lua, 1)) throwinvarg(lua, __KCFUNC__); lua_getglobal(lua, "__kyototycoon__"); lua_getfield(lua, -1, "__serv__"); kt::RPCServer* serv = (kt::RPCServer*)lua_touserdata(lua, -1); const char* kstr = lua_tostring(lua, 1); const char* message = lua_tostring(lua, 2); if (kstr && message) { kt::RPCServer::Logger::Kind kind = kt::RPCServer::Logger::DEBUG; if (!kc::stricmp(kstr, "info")) { kind = kt::RPCServer::Logger::INFO; } else if (!kc::stricmp(kstr, "system")) { kind = kt::RPCServer::Logger::SYSTEM; } else if (!kc::stricmp(kstr, "error")) { kind = kt::RPCServer::Logger::ERROR; } serv->log(kind, "[SCRIPT]: %s", message); } return 0; } #else /** * ScriptProcessor internal. */ struct ScriptProcessorCore { std::string path; int32_t thid; kt::RPCServer* serv; kt::TimedDB* dbs; int32_t dbnum; const std::map* dbmap; }; /** * Default constructor. */ ScriptProcessor::ScriptProcessor() { _assert_(true); ScriptProcessorCore* core = new ScriptProcessorCore; core->thid = 0; core->serv = NULL; core->dbs = NULL; core->dbnum = 0; core->dbmap = NULL; opq_ = core; } /** * Destructor. */ ScriptProcessor::~ScriptProcessor() { _assert_(true); ScriptProcessorCore* core = (ScriptProcessorCore*)opq_; delete core; } /** * Set domain-specific resources. */ bool ScriptProcessor::set_resources(int32_t thid, kt::RPCServer* serv, kt::TimedDB* dbs, int32_t dbnum, const std::map* dbmap) { _assert_(serv && dbs && dbnum >= 0 && dbmap); ScriptProcessorCore* core = (ScriptProcessorCore*)opq_; core->thid = thid; core->serv = serv; core->dbs = dbs; core->dbnum = dbnum; core->dbmap = dbmap; return true; } /** * Load a script file. */ bool ScriptProcessor::load(const std::string& path) { _assert_(true); ScriptProcessorCore* core = (ScriptProcessorCore*)opq_; core->path = path; return true; } /** * Clear the internal state. */ void ScriptProcessor::clear() { _assert_(true); ScriptProcessorCore* core = new ScriptProcessorCore; core->thid = 0; core->serv = NULL; core->dbs = NULL; core->dbnum = 0; core->dbmap = NULL; } /** * Call a procedure. */ kt::RPCClient::ReturnValue ScriptProcessor::call(const std::string& name, const std::map& inmap, std::map& outmap) { _assert_(true); ScriptProcessorCore* core = (ScriptProcessorCore*)opq_; kt::RPCClient::ReturnValue rv; if (name == "echo") { std::string keys; std::map::const_iterator it = inmap.begin(); std::map::const_iterator itend = inmap.end(); while (it != itend) { if (!keys.empty()) keys.append(","); keys.append(it->first); ++it; } core->serv->log(kt::RPCServer::Logger::DEBUG, "[SCRIPT]: %s: thid=%d inmap=%s", name.c_str(), core->thid, keys.c_str()); outmap.insert(inmap.begin(), inmap.end()); rv = kt::RPCClient::RVSUCCESS; } else { rv = kt::RPCClient::RVENOIMPL; } return rv; } #endif // END OF FILE kyototycoon-0.9.56/kthttp.h0000644000175000017500000012447311757471602014732 0ustar mikiomikio/************************************************************************************************* * HTTP utilities * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTHTTP_H // duplication check #define _KTHTTP_H #include #include #include #include namespace kyototycoon { // common namespace /** * URL accessor. */ class URL { public: /** * Default constructor. */ explicit URL() : scheme_(""), host_(""), port_(0), authority_(""), path_(""), query_(""), fragment_("") { _assert_(true); } /** * Constructor. * @param expr the string expression of the URL. */ explicit URL(const std::string& expr) : scheme_(""), host_(""), port_(0), authority_(""), path_(""), query_(""), fragment_("") { _assert_(true); parse_expression(expr); } /** * Copy constructor. * @param src the source object. */ explicit URL(const URL& src) : scheme_(src.scheme_), host_(src.host_), port_(src.port_), authority_(src.authority_), path_(src.path_), query_(src.query_), fragment_(src.fragment_) { _assert_(true); } /** * Destructor */ ~URL() { _assert_(true); } /** * Set the string expression of the URL. */ void set_expression(const std::string& expr) { _assert_(true); parse_expression(expr); } /** * Set the scheme. */ void set_scheme(const std::string& scheme) { _assert_(true); scheme_ = scheme; } /** * Set the host name. */ void set_host(const std::string& host) { _assert_(true); host_ = host; } /** * Set the port number. */ void set_port(int32_t port) { _assert_(true); port_ = port; } /** * Set the authority information. */ void set_authority(const std::string& authority) { _assert_(true); authority_ = authority; } /** * Set the path. */ void set_path(const std::string& path) { _assert_(true); path_ = path; } /** * Set the query string. */ void set_query(const std::string& query) { _assert_(true); query_ = query; } /** * Set the fragment string. */ void set_fragment(const std::string& fragment) { _assert_(true); fragment_ = fragment; } /** * Get the string expression of the URL. * @return the string expression of the URL. */ std::string expression() { _assert_(true); std::string expr; if (!scheme_.empty()) { kc::strprintf(&expr, "%s://", scheme_.c_str()); if (!authority_.empty()) kc::strprintf(&expr, "%s@", authority_.c_str()); if (!host_.empty()) { kc::strprintf(&expr, "%s", host_.c_str()); if (port_ > 0 && port_ != default_port(scheme_)) kc::strprintf(&expr, ":%d", port_); } } kc::strprintf(&expr, "%s", path_.c_str()); if (!query_.empty()) kc::strprintf(&expr, "?%s", query_.c_str()); if (!fragment_.empty()) kc::strprintf(&expr, "#%s", fragment_.c_str()); return expr; } /** * Get the path and the query string for HTTP request. * @return the path and the query string for HTTP request. */ std::string path_query() { _assert_(true); return path_ + (query_.empty() ? "" : "?") + query_; } /** * Get the scheme. * @return the scheme. */ std::string scheme() { _assert_(true); return scheme_; } /** * Get the host name. * @return the host name. */ std::string host() { _assert_(true); return host_; } /** * Get the port number. * @return the port number. */ int32_t port() { _assert_(true); return port_; } /** * Get the authority information. * @return the authority information. */ std::string authority() { _assert_(true); return authority_; } /** * Get the path. * @return the path. */ std::string path() { _assert_(true); return path_; } /** * Get the query string. * @return the query string. */ std::string query() { _assert_(true); return query_; } /** * Get the fragment string. * @return the fragment string. */ std::string fragment() { _assert_(true); return fragment_; } /** * Assignment operator from the self type. * @param right the right operand. * @return the reference to itself. */ URL& operator =(const URL& right) { _assert_(true); if (&right == this) return *this; scheme_ = right.scheme_; host_ = right.host_; port_ = right.port_; authority_ = right.authority_; path_ = right.path_; query_ = right.query_; fragment_ = right.fragment_; return *this; } private: /** * Parse a string expression. * @param expr the string expression. */ void parse_expression(const std::string& expr) { scheme_ = ""; host_ = ""; port_ = 0; authority_ = ""; path_ = ""; query_ = ""; fragment_ = ""; char* trim = kc::strdup(expr.c_str()); kc::strtrim(trim); char* rp = trim; char* norm = new char[std::strlen(trim)*3+1]; char* wp = norm; while (*rp != '\0') { if (*rp > 0x20 && *rp < 0x7f) { *(wp++) = *rp; } else { *(wp++) = '%'; int32_t num = *(unsigned char*)rp >> 4; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } num = *rp & 0x0f; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } } rp++; } *wp = '\0'; rp = norm; if (kc::strifwm(rp, "http://")) { scheme_ = "http"; rp += 7; } else if (kc::strifwm(rp, "https://")) { scheme_ = "https"; rp += 8; } else if (kc::strifwm(rp, "ftp://")) { scheme_ = "ftp"; rp += 6; } else if (kc::strifwm(rp, "sftp://")) { scheme_ = "sftp"; rp += 7; } else if (kc::strifwm(rp, "ftps://")) { scheme_ = "ftps"; rp += 7; } else if (kc::strifwm(rp, "tftp://")) { scheme_ = "tftp"; rp += 7; } else if (kc::strifwm(rp, "ldap://")) { scheme_ = "ldap"; rp += 7; } else if (kc::strifwm(rp, "ldaps://")) { scheme_ = "ldaps"; rp += 8; } else if (kc::strifwm(rp, "file://")) { scheme_ = "file"; rp += 7; } char* ep; if ((ep = std::strchr(rp, '#')) != NULL) { fragment_ = ep + 1; *ep = '\0'; } if ((ep = std::strchr(rp, '?')) != NULL) { query_ = ep + 1; *ep = '\0'; } if (!scheme_.empty()) { if ((ep = std::strchr(rp, '/')) != NULL) { path_ = ep; *ep = '\0'; } else { path_ = "/"; } if ((ep = std::strchr(rp, '@')) != NULL) { *ep = '\0'; if (rp[0] != '\0') authority_ = rp; rp = ep + 1; } if ((ep = std::strchr(rp, ':')) != NULL) { if (ep[1] != '\0') port_ = kc::atoi(ep + 1); *ep = '\0'; } if (rp[0] != '\0') host_ = rp; if (port_ < 1) port_ = default_port(scheme_); } else { path_ = rp; } delete[] norm; delete[] trim; } /** * Get the default port of a scheme. * @param scheme the scheme. */ int32_t default_port(const std::string& scheme) { if (scheme == "http") return 80; if (scheme == "https") return 443; if (scheme == "ftp") return 21; if (scheme == "sftp") return 22; if (scheme == "ftps") return 990; if (scheme == "tftp") return 69; if (scheme == "ldap") return 389; if (scheme == "ldaps") return 636; return 0; } /** The scheme. */ std::string scheme_; /** The host name. */ std::string host_; /** The port number. */ int32_t port_; /** The autority information. */ std::string authority_; /** The path. */ std::string path_; /** The query string. */ std::string query_; /** The fragment string. */ std::string fragment_; }; /** * HTTP client. * @note Although all methods of this class are thread-safe, its instance does not have mutual * exclusion mechanism. So, multiple threads must not share the same instance and they must use * their own respective instances. */ class HTTPClient { public: /** The size for a line buffer. */ static const int32_t LINEBUFSIZ = 8192; /** The maximum size of received data. */ static const int32_t RECVMAXSIZ = 1 << 28; /** * Kinds of HTTP request methods. */ enum Method { MGET, ///< GET MHEAD, ///< HEAD MPOST, ///< POST MPUT, ///< PUT MDELETE, ///< DELETE MUNKNOWN ///< unknown }; /** * Default constructor. */ explicit HTTPClient() : sock_(), host_(""), port_(0) { _assert_(true); } /** * Destructor. */ ~HTTPClient() { _assert_(true); } /** * Open the connection. * @param host the name or the address of the server. If it is an empty string, the local host * is specified. * @param port the port numger of the server. * @param timeout the timeout of each operation in seconds. If it is not more than 0, no * timeout is specified. * @return true on success, or false on failure. */ bool open(const std::string& host = "", int32_t port = 80, double timeout = -1) { _assert_(true); const std::string& thost = host.empty() ? Socket::get_local_host_name() : host; const std::string& addr = Socket::get_host_address(thost); if (addr.empty() || port < 1) return false; std::string expr; kc::strprintf(&expr, "%s:%d", addr.c_str(), port); if (timeout > 0) sock_.set_timeout(timeout); if (!sock_.open(expr)) return false; host_ = host; port_ = port; return true; } /** * Close the connection. * @param grace true for graceful shutdown, or false for immediate disconnection. * @return true on success, or false on failure. */ bool close(bool grace = true) { _assert_(true); return sock_.close(grace); } /** * Fetch a resource. * @param pathquery the path and the query string of the resource. * @param method the kind of the request methods. * @param resbody a string to contain the entity body of the response. If it is NULL, it is * ignored. * @param resheads a string map to contain the headers of the response. If it is NULL, it is * ignored. Header names are converted into lower cases. The empty key means the * request-line. * @param reqbody a string which contains the entity body of the request. If it is NULL, it * is ignored. * @param reqheads a string map which contains the headers of the request. If it is NULL, it * is ignored. * @return the status code of the response, or -1 on failure. */ int32_t fetch(const std::string& pathquery, Method method = MGET, std::string* resbody = NULL, std::map* resheads = NULL, const std::string* reqbody = NULL, const std::map* reqheads = NULL) { _assert_(true); if (resbody) resbody->clear(); if (resheads) resheads->clear(); if (pathquery.empty() || pathquery[0] != '/') { if (resbody) resbody->append("[invalid URL expression]"); return -1; } std::string request; const char* mstr; switch (method) { default: mstr = "GET"; break; case MHEAD: mstr = "HEAD"; break; case MPOST: mstr = "POST"; break; case MPUT: mstr = "PUT"; break; case MDELETE: mstr = "DELETE"; break; } kc::strprintf(&request, "%s %s HTTP/1.1\r\n", mstr, pathquery.c_str()); kc::strprintf(&request, "Host: %s", host_.c_str()); if (port_ != 80) kc::strprintf(&request, ":%d", port_); kc::strprintf(&request, "\r\n"); if (reqbody) kc::strprintf(&request, "Content-Length: %lld\r\n", (long long)reqbody->size()); if (reqheads) { std::map::const_iterator it = reqheads->begin(); std::map::const_iterator itend = reqheads->end(); while (it != itend) { char* name = kc::strdup(it->first.c_str()); char* value = kc::strdup(it->second.c_str()); kc::strnrmspc(name); kc::strtolower(name); kc::strnrmspc(value); if (*name != '\0' && !std::strchr(name, ':') && !std::strchr(name, ' ')) { strcapitalize(name); kc::strprintf(&request, "%s: %s\r\n", name, value); } delete[] value; delete[] name; ++it; } } kc::strprintf(&request, "\r\n"); if (reqbody) request.append(*reqbody); if (!sock_.send(request)) { if (resbody) resbody->append("[sending data failed]"); return -1; } char line[LINEBUFSIZ]; if (!sock_.receive_line(line, sizeof(line))) { if (resbody) resbody->append("[receiving data failed]"); return -1; } if (!kc::strfwm(line, "HTTP/1.1 ") && !kc::strfwm(line, "HTTP/1.0 ")) { if (resbody) resbody->append("[received data was invalid]"); return -1; } const char* rp = line + 9; int32_t code = kc::atoi(rp); if (code < 1) { if (resbody) resbody->append("[invalid status code]"); return -1; } if (resheads) (*resheads)[""] = line; int64_t clen = -1; bool chunked = false; while (true) { if (!sock_.receive_line(line, sizeof(line))) { resbody->append("[receiving data failed]"); return -1; } if (*line == '\0') break; char* pv = std::strchr(line, ':'); if (pv) { *(pv++) = '\0'; kc::strnrmspc(line); kc::strtolower(line); if (*line != '\0') { while (*pv == ' ') { pv++; } if (!std::strcmp(line, "content-length")) { clen = kc::atoi(pv); } else if (!std::strcmp(line, "transfer-encoding")) { if (!kc::stricmp(pv, "chunked")) chunked = true; } if (resheads) (*resheads)[line] = pv; } } } if (method != MHEAD && code != 304) { if (clen >= 0) { if (clen > RECVMAXSIZ) { if (resbody) resbody->append("[too large response]"); return -1; } char* body = new char[clen]; if (!sock_.receive(body, clen)) { if (resbody) resbody->append("[receiving data failed]"); delete[] body; return -1; } if (resbody) resbody->append(body, clen); delete[] body; } else if (chunked) { int64_t asiz = LINEBUFSIZ; char* body = (char*)kc::xmalloc(asiz); int64_t bsiz = 0; while (true) { if (!sock_.receive_line(line, sizeof(line))) { if (resbody) resbody->append("[receiving data failed]"); kc::xfree(body); return -1; } if (*line == '\0') break; int64_t csiz = kc::atoih(line); if (bsiz + csiz > RECVMAXSIZ) { if (resbody) resbody->append("[too large response]"); kc::xfree(body); return -1; } if (bsiz + csiz > asiz) { asiz = bsiz * 2 + csiz; body = (char*)kc::xrealloc(body, asiz); } if (csiz > 0 && !sock_.receive(body + bsiz, csiz)) { if (resbody) resbody->append("[receiving data failed]"); kc::xfree(body); return -1; } if (sock_.receive_byte() != '\r' || sock_.receive_byte() != '\n') { if (resbody) resbody->append("[invalid chunk]"); kc::xfree(body); return -1; } if (csiz < 1) break; bsiz += csiz; } if (resbody) resbody->append(body, bsiz); kc::xfree(body); } else { int64_t asiz = LINEBUFSIZ; char* body = (char*)kc::xmalloc(asiz); int64_t bsiz = 0; while (true) { int32_t c = sock_.receive_byte(); if (c < 0) break; if (bsiz > RECVMAXSIZ - 1) { if (resbody) resbody->append("[too large response]"); kc::xfree(body); return -1; } if (bsiz + 1 > asiz) { asiz = bsiz * 2; body = (char*)kc::xrealloc(body, asiz); } body[bsiz++] = c; } if (resbody) resbody->append(body, bsiz); kc::xfree(body); } } return code; } /** * Reveal the internal TCP socket. * @return the internal TCP socket. */ Socket* reveal_core() { _assert_(true); return &sock_; } /** * Fetch a resource at once * @param url the URL of the resource. * @param method the kind of the request methods. * @param resbody a string to contain the entity body of the response. If it is NULL, it is * ignored. * @param resheads a string map to contain the headers of the response. If it is NULL, it is * ignored. Header names are converted into lower cases. The empty key means the * request-line. * @param reqbody a string which contains the entity body of the request. If it is NULL, it * is ignored. * @param reqheads a string map which contains the headers of the request. If it is NULL, it * is ignored. * @param timeout the timeout of each operation in seconds. If it is not more than 0, no * timeout is specified. * @return the status code of the response, or -1 on failure. */ static int32_t fetch_once(const std::string& url, Method method = MGET, std::string* resbody = NULL, std::map* resheads = NULL, const std::string* reqbody = NULL, const std::map* reqheads = NULL, double timeout = -1) { _assert_(true); URL uo(url); const std::string& scheme = uo.scheme(); const std::string& host = uo.host(); uint32_t port = uo.port(); if (scheme != "http" || host.empty() || port < 1) { if (resbody) resbody->append("[invalid URL expression]"); return -1; } HTTPClient ua; if (!ua.open(host, port, timeout)) { if (resbody) resbody->append("[connection refused]"); return -1; } std::map rhtmp; if (reqheads) rhtmp.insert(reqheads->begin(), reqheads->end()); rhtmp["connection"] = "close"; int32_t code = ua.fetch(uo.path_query(), method, resbody, resheads, reqbody, &rhtmp); if (!ua.close()) { if (resbody) { resbody->clear(); resbody->append("[close failed]"); } return -1; } return code; } private: /** Dummy constructor to forbid the use. */ HTTPClient(const HTTPClient&); /** Dummy Operator to forbid the use. */ HTTPClient& operator =(const HTTPClient&); /** The socket of connection. */ Socket sock_; /** The host name of the server. */ std::string host_; /** The port number of the server. */ int32_t port_; }; /** * HTTP server. */ class HTTPServer { public: class Logger; class Worker; class Session; private: class WorkerAdapter; public: /** * Interface to log internal information and errors. */ class Logger : public ThreadedServer::Logger { public: /** * Destructor. */ virtual ~Logger() { _assert_(true); } }; /** * Interface to process each request. */ class Worker { public: /** * Destructor. */ virtual ~Worker() { _assert_(true); } /** * Process each request. * @param serv the server. * @param sess the session with the client. * @param path the path of the requested resource. * @param method the kind of the request methods. * @param reqheads a string map which contains the headers of the request. Header names are * converted into lower cases. The empty key means the request-line. * @param reqbody a string which contains the entity body of the request. * @param resheads a string map to contain the headers of the response. * @param resbody a string to contain the entity body of the response. * @param misc a string map which contains miscellaneous information. "url" means the * absolute URL. "query" means the query string of the URL. * @return the status code of the response. If it is less than 1, internal server error is * sent to the client and the connection is closed. */ virtual int32_t process(HTTPServer* serv, Session* sess, const std::string& path, HTTPClient::Method method, const std::map& reqheads, const std::string& reqbody, std::map& resheads, std::string& resbody, const std::map& misc) = 0; /** * Process each binary request. * @param serv the server. * @param sess the session with the client. * @return true to reuse the session, or false to close the session. */ virtual bool process_binary(ThreadedServer* serv, ThreadedServer::Session* sess) { _assert_(serv && sess); return false; } /** * Process each idle event. * @param serv the server. */ virtual void process_idle(HTTPServer* serv) { _assert_(serv); } /** * Process each timer event. * @param serv the server. */ virtual void process_timer(HTTPServer* serv) { _assert_(serv); } /** * Process the starting event. * @param serv the server. */ virtual void process_start(HTTPServer* serv) { _assert_(serv); } /** * Process the finishing event. * @param serv the server. */ virtual void process_finish(HTTPServer* serv) { _assert_(serv); } }; /** * Interface to access each session data. */ class Session { friend class HTTPServer; public: /** * Interface of session local data. */ class Data : public ThreadedServer::Session::Data { public: /** * Destructor. */ virtual ~Data() { _assert_(true); } }; /** * Get the ID number of the session. * @return the ID number of the session. */ uint64_t id() { _assert_(true); return sess_->id(); } /** * Get the ID number of the worker thread. * @return the ID number of the worker thread. It is from 0 to less than the number of * worker threads. */ uint32_t thread_id() { _assert_(true); return sess_->thread_id(); } /** * Set the session local data. * @param data the session local data. If it is NULL, no data is registered. * @note The registered data is destroyed implicitly when the session object is destroyed or * this method is called again. */ void set_data(Data* data) { _assert_(true); sess_->set_data(data); } /** * Get the session local data. * @return the session local data, or NULL if no data is registered. */ Data* data() { _assert_(true); return (Data*)sess_->data(); } /** * Get the expression of the socket. * @return the expression of the socket or an empty string on failure. */ const std::string expression() { _assert_(true); return sess_->expression(); } private: /** * Constructor. */ explicit Session(ThreadedServer::Session* sess) : sess_(sess) { _assert_(true); } /** * Destructor. */ virtual ~Session() { _assert_(true); } private: ThreadedServer::Session* sess_; }; /** * Default constructor. */ explicit HTTPServer() : serv_(), name_(), worker_() { _assert_(true); } /** * Destructor. */ ~HTTPServer() { _assert_(true); } /** * Set the network configurations. * @param expr an expression of the address and the port of the server. * @param timeout the timeout of each network operation in seconds. If it is not more than 0, * no timeout is specified. * @param name the name of the server. If it is an empty string, the host name is specified. */ void set_network(const std::string& expr, double timeout = -1, const std::string& name = "") { _assert_(true); if (timeout > 0) serv_.set_network(expr, timeout); if (name.empty()) { name_ = Socket::get_local_host_name(); if (name.empty()) name_ = "localhost"; const char* rp = std::strrchr(expr.c_str(), ':'); if (rp) { rp++; int32_t port = kc::atoi(rp); if (port > 0 && port != 80 && !std::strchr(rp, '[') && !std::strchr(rp, ']') && !std::strchr(rp, '/')) kc::strprintf(&name_, ":%d", port); } } else { name_ = name; } } /** * Set the logger to process each log message. * @param logger the logger object. * @param kinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, * Logger::INFO for normal information, Logger::SYSTEM for system information, and * Logger::ERROR for fatal error. */ void set_logger(Logger* logger, uint32_t kinds = Logger::SYSTEM | Logger::ERROR) { _assert_(true); serv_.set_logger(logger, kinds); } /** * Set the worker to process each request. * @param worker the worker object. * @param thnum the number of worker threads. */ void set_worker(Worker* worker, size_t thnum = 1) { _assert_(true); worker_.serv_ = this; worker_.worker_ = worker; serv_.set_worker(&worker_, thnum); } /** * Start the service. * @return true on success, or false on failure. * @note This function blocks until the server stops by the HTTPServer::stop method. */ bool start() { _assert_(true); return serv_.start(); } /** * Stop the service. * @return true on success, or false on failure. */ bool stop() { _assert_(true); return serv_.stop(); } /** * Finish the service. * @return true on success, or false on failure. */ bool finish() { _assert_(true); return serv_.finish(); } /** * Log a message. * @param kind the kind of the event. Logger::DEBUG for debugging, Logger::INFO for normal * information, Logger::SYSTEM for system information, and Logger::ERROR for fatal error. * @param format the printf-like format string. The conversion character `%' can be used with * such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `%'. * @param ... used according to the format string. */ void log(Logger::Kind kind, const char* format, ...) { _assert_(format); va_list ap; va_start(ap, format); serv_.log_v(kind, format, ap); va_end(ap); } /** * Log a message. * @note Equal to the original Cursor::set_value method except that the last parameters is * va_list. */ void log_v(Logger::Kind kind, const char* format, va_list ap) { _assert_(format); serv_.log_v(kind, format, ap); } /** * Reveal the internal TCP server. * @return the internal TCP server. */ ThreadedServer* reveal_core() { _assert_(true); return &serv_; } /** * Get the name of a status code. * @return the name of a status code. */ static const char* status_name(int32_t code) { _assert_(true); switch (code) { case 100: return "Continue"; case 101: return "Switching Protocols"; case 102: return "Processing"; case 200: return "OK"; case 201: return "Created"; case 202: return "Accepted"; case 203: return "Non-Authoritative Information"; case 204: return "No Content"; case 205: return "Reset Content"; case 206: return "Partial Content"; case 207: return "Multi-Status"; case 300: return "Multiple Choices"; case 301: return "Moved Permanently"; case 302: return "Found"; case 303: return "See Other"; case 304: return "Not Modified"; case 305: return "Use Proxy"; case 307: return "Temporary Redirect"; case 400: return "Bad Request"; case 401: return "Unauthorized"; case 402: return "Payment Required"; case 403: return "Forbidden"; case 404: return "Not Found"; case 405: return "Method Not Allowed"; case 406: return "Not Acceptable"; case 407: return "Proxy Authentication Required"; case 408: return "Request Timeout"; case 409: return "Conflict"; case 410: return "Gone"; case 411: return "Length Required"; case 412: return "Precondition Failed"; case 413: return "Request Entity Too Large"; case 414: return "Request-URI Too Long"; case 415: return "Unsupported Media Type"; case 416: return "Requested Range Not Satisfiable"; case 417: return "Expectation Failed"; case 422: return "Unprocessable Entity"; case 423: return "Locked"; case 424: return "Failed Dependency"; case 426: return "Upgrade Required"; case 450: return "Logical Inconsistency"; case 500: return "Internal Server Error"; case 501: return "Not Implemented"; case 502: return "Bad Gateway"; case 503: return "Service Unavailable"; case 504: return "Gateway Timeout"; case 505: return "HTTP Version Not Supported"; case 506: return "Variant Also Negotiates"; case 507: return "Insufficient Storage"; case 509: return "Bandwidth Limit Exceeded"; case 510: return "Not Extended"; } if (code < 100) return "Unknown Status"; if (code < 200) return "Unknown Informational Status"; if (code < 300) return "Unknown Success Status"; if (code < 400) return "Unknown Redirection Status"; if (code < 500) return "Unknown Client Error Status"; if (code < 600) return "Unknown Server Error Status"; return "Unknown Status"; } /** * Guess the media type of a URL. * @param url the URL. * @return the media type string, or NULL on failure. */ static const char* media_type(const std::string& url) { static const char* types[] = { "txt", "text/plain", "text", "text/plain", "asc", "text/plain", "c", "text/plain", "h", "text/plain", "s", "text/plain", "cc", "text/plain", "cxx", "text/plain", "cpp", "text/plain", "html", "text/html", "htm", "text/html", "xml", "application/xml", "xhtml", "application/xml+xhtml", "tar", "application/x-tar", "gz", "application/x-gzip", "bz2", "application/x-bzip2", "zip", "application/zip", "xz", "application/octet-stream", "lzma", "application/octet-stream", "lzo", "application/octet-stream", "lzh", "application/octet-stream", "o", "application/octet-stream", "so", "application/octet-stream", "a", "application/octet-stream", "exe", "application/octet-stream", "pdf", "application/pdf", "ps", "application/postscript", "doc", "application/msword", "xls", "application/vnd.ms-excel", "ppt", "application/ms-powerpoint", "swf", "application/x-shockwave-flash", "png", "image/png", "jpg", "image/jpeg", "jpeg", "image/jpeg", "gif", "image/gif", "bmp", "image/bmp", "tif", "image/tiff", "tiff", "image/tiff", "svg", "image/xml+svg", "au", "audio/basic", "snd", "audio/basic", "mid", "audio/midi", "midi", "audio/midi", "mp3", "audio/mpeg", "mp2", "audio/mpeg", "wav", "audio/x-wav", "mpg", "video/mpeg", "mpeg", "video/mpeg", "mp4", "video/mp4", "mpg4", "video/mp4", "mov", "video/quicktime", "qt", "video/quicktime", NULL }; const char* rp = url.c_str(); const char* pv = std::strrchr(rp, '/'); if (pv) rp = pv + 1; pv = std::strrchr(rp, '.'); if (pv) { rp = pv + 1; for (int32_t i = 0; types[i]; i += 2) { if (!kc::stricmp(rp, types[i])) return types[i+1]; } } return NULL; } /** * Convert the path element of a URL into the local path. * @param path the path element of a URL. * @return the local path. */ static std::string localize_path(const std::string& path) { _assert_(true); const std::string& npath = path; std::vector elems, nelems; kc::strsplit(npath, '/', &elems); std::vector::iterator it = elems.begin(); std::vector::iterator itend = elems.end(); while (it != itend) { if (*it == "..") { if (!nelems.empty()) nelems.pop_back(); } else if (!it->empty() && *it != ".") { size_t zsiz; char* zbuf = kc::urldecode(it->c_str(), &zsiz); if (zsiz > 0 && zbuf[0] != '\0' && !std::strchr(zbuf, kc::File::PATHCHR) && std::strcmp(zbuf, kc::File::CDIRSTR) && std::strcmp(zbuf, kc::File::PDIRSTR)) nelems.push_back(zbuf); delete[] zbuf; } ++it; } std::string rpath; it = nelems.begin(); itend = nelems.end(); while (it != itend) { if (!rpath.empty()) rpath.append(kc::File::PATHSTR); rpath.append(*it); ++it; } return rpath; } private: /** * Adapter for the worker. */ class WorkerAdapter : public ThreadedServer::Worker { friend class HTTPServer; public: WorkerAdapter() : serv_(NULL), worker_(NULL) { _assert_(true); } private: bool process(ThreadedServer* serv, ThreadedServer::Session* sess) { _assert_(true); int32_t magic = sess->receive_byte(); if (magic < 0) return false; sess->undo_receive_byte(magic); if (magic == 0 || magic >= 0x80) return worker_->process_binary(serv, sess); char line[HTTPClient::LINEBUFSIZ]; if (!sess->receive_line(&line, sizeof(line))) return false; std::map misc; std::map reqheads; reqheads[""] = line; char* pv = std::strchr(line, ' '); if (!pv) return false; *(pv++) = '\0'; char* tpath = pv; pv = std::strchr(tpath, ' '); if (!pv) return false; *(pv++) = '\0'; std::string url; kc::strprintf(&url, "http://%s%s", serv_->name_.c_str(), tpath); misc["url"] = url; char* query = std::strchr(tpath, '?'); if (query) { *(query++) = '\0'; misc["query"] = query; } if (*tpath == '\0') return false; std::string path = tpath; int32_t htver; if (!std::strcmp(pv, "HTTP/1.0")) { htver = 0; } else if (!std::strcmp(pv, "HTTP/1.1")) { htver = 1; } else { return false; } HTTPClient::Method method; if (!std::strcmp(line, "GET")) { method = HTTPClient::MGET; } else if (!std::strcmp(line, "HEAD")) { method = HTTPClient::MHEAD; } else if (!std::strcmp(line, "POST")) { method = HTTPClient::MPOST; } else if (!std::strcmp(line, "PUT")) { method = HTTPClient::MPUT; } else if (!std::strcmp(line, "DELETE")) { method = HTTPClient::MDELETE; } else { method = HTTPClient::MUNKNOWN; } bool keep = htver >= 1; int64_t clen = -1; bool chunked = false; while (true) { if (!sess->receive_line(&line, sizeof(line))) return false; if (*line == '\0') break; pv = std::strchr(line, ':'); if (pv) { *(pv++) = '\0'; kc::strnrmspc(line); kc::strtolower(line); if (*line != '\0') { while (*pv == ' ') { pv++; } if (!std::strcmp(line, "connection")) { if (!kc::stricmp(pv, "close")) { keep = false; } else if (!kc::stricmp(pv, "keep-alive")) { keep = true; } } else if (!std::strcmp(line, "content-length")) { clen = kc::atoi(pv); } else if (!std::strcmp(line, "transfer-encoding")) { if (!kc::stricmp(pv, "chunked")) chunked = true; } reqheads[line] = pv; } } } std::string reqbody; if (method == HTTPClient::MPOST || method == HTTPClient::MPUT || method == HTTPClient::MUNKNOWN) { if (clen >= 0) { if (clen > HTTPClient::RECVMAXSIZ) { send_error(sess, 413, "request entity too large"); return false; } char* body = new char[clen]; if (!sess->receive(body, clen)) { send_error(sess, 400, "receiving data failed"); delete[] body; return false; } reqbody.append(body, clen); delete[] body; } else if (chunked) { int64_t asiz = HTTPClient::LINEBUFSIZ; char* body = (char*)kc::xmalloc(asiz); int64_t bsiz = 0; while (true) { if (!sess->receive_line(line, sizeof(line))) { send_error(sess, 400, "receiving data failed"); kc::xfree(body); return false; } if (*line == '\0') break; int64_t csiz = kc::atoih(line); if (bsiz + csiz > HTTPClient::RECVMAXSIZ) { send_error(sess, 413, "request entity too large"); kc::xfree(body); return false; } if (bsiz + csiz > asiz) { asiz = bsiz * 2 + csiz; body = (char*)kc::xrealloc(body, asiz); } if (csiz > 0 && !sess->receive(body + bsiz, csiz)) { send_error(sess, 400, "receiving data failed"); kc::xfree(body); return false; } if (sess->receive_byte() != '\r' || sess->receive_byte() != '\n') { send_error(sess, 400, "invalid chunk"); kc::xfree(body); return false; } if (csiz < 1) break; bsiz += csiz; } reqbody.append(body, bsiz); kc::xfree(body); } } Session mysess(sess); std::string resbody; std::map resheads; int32_t code = worker_->process(serv_, &mysess, path, method, reqheads, reqbody, resheads, resbody, misc); serv->log(Logger::INFO, "(%s): %s: %d", sess->expression().c_str(), reqheads[""].c_str(), code); if (code > 0) { if (!send_result(sess, code, keep, path, method, reqheads, reqbody, resheads, resbody, misc)) keep = false; } else { send_error(sess, 500, "logic error"); keep = false; } return keep; } void process_idle(ThreadedServer* serv) { worker_->process_idle(serv_); } void process_timer(ThreadedServer* serv) { worker_->process_timer(serv_); } void process_start(ThreadedServer* serv) { worker_->process_start(serv_); } void process_finish(ThreadedServer* serv) { worker_->process_finish(serv_); } void send_error(ThreadedServer::Session* sess, int32_t code, const char* msg) { _assert_(sess && code > 0); const char* name = status_name(code); std::string str; kc::strprintf(&str, "%d %s (%s)\n", code, name, msg); std::string data; kc::strprintf(&data, "HTTP/1.1 %d %s\r\n", code, name); append_server_headers(&data); kc::strprintf(&data, "Connection: close\r\n"); kc::strprintf(&data, "Content-Length: %d\r\n", (int)str.size()); kc::strprintf(&data, "Content-Type: text/plain\r\n"); kc::strprintf(&data, "\r\n"); data.append(str); sess->send(data.data(), data.size()); } bool send_result(ThreadedServer::Session* sess, int32_t code, bool keep, const std::string& path, HTTPClient::Method method, const std::map& reqheads, const std::string& reqbody, const std::map& resheads, const std::string& resbody, const std::map& misc) { const char* name = status_name(code); bool body = true; if (method == HTTPClient::MHEAD || code == 304) body = false; std::string data; kc::strprintf(&data, "HTTP/1.1 %d %s\r\n", code, name); append_server_headers(&data); if (!keep) kc::strprintf(&data, "Connection: close\r\n"); if (body) kc::strprintf(&data, "Content-Length: %lld\r\n", (long long)resbody.size()); std::map::const_iterator it = resheads.begin(); std::map::const_iterator itend = resheads.end(); while (it != itend) { char* name = kc::strdup(it->first.c_str()); char* value = kc::strdup(it->second.c_str()); kc::strnrmspc(name); kc::strtolower(name); kc::strnrmspc(value); if (*name != '\0' && !std::strchr(name, ':') && !std::strchr(name, ' ')) { strcapitalize(name); kc::strprintf(&data, "%s: %s\r\n", name, value); } delete[] value; delete[] name; ++it; } kc::strprintf(&data, "\r\n"); if (body) data.append(resbody); return sess->send(data.data(), data.size()); } void append_server_headers(std::string* str) { _assert_(str); kc::strprintf(str, "Server: KyotoTycoon/%s\r\n", VERSION); char buf[48]; datestrhttp(kc::INT64MAX, 0, buf); kc::strprintf(str, "Date: %s\r\n", buf); } HTTPServer* serv_; HTTPServer::Worker* worker_; }; /** Dummy constructor to forbid the use. */ HTTPServer(const HTTPServer&); /** Dummy Operator to forbid the use. */ HTTPServer& operator =(const HTTPServer&); /** The internal server. */ ThreadedServer serv_; /** The server name. */ std::string name_; /** The adapter for worker. */ WorkerAdapter worker_; }; } // common namespace #endif // duplication check // END OF FILE kyototycoon-0.9.56/ktdbext.cc0000644000175000017500000000225111757471602015204 0ustar mikiomikio/************************************************************************************************* * Database extension * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "ktdbext.h" #include "myconf.h" namespace kyototycoon { // common namespace // There is no implementation now. } // common namespace // END OF FILE kyototycoon-0.9.56/kyototycoon.pc.in0000644000175000017500000000051611526473017016560 0ustar mikiomikioprefix=@prefix@ exec_prefix=@exec_prefix@ datarootdir = @datarootdir@ bindir=@bindir@ libdir=@libdir@ libexecdir=@libexecdir@ includedir=@includedir@ datadir=@datadir@ Name: Kyoto Tyrant Description: a handy cache/storage server Version: @PACKAGE_VERSION@ Libs: -L${libdir} -lkyototycoon Libs.private: @LIBS@ Cflags: -I${includedir} kyototycoon-0.9.56/ktplugserv.h0000644000175000017500000000607711757471602015621 0ustar mikiomikio/************************************************************************************************* * Interface of pluggable server abstraction * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTPLUGSERV_H // duplication check #define _KTPLUGSERV_H #include #include #include #include #include #include #include #include #include #include #include namespace kyototycoon { // common namespace /** * Interface of pluggable server abstraction. */ class PluggableServer { public: /** * Destructor. */ virtual ~PluggableServer() { _assert_(true); } /** * Configure server settings. * @param dbary an array of the database objects. * @param dbnum the number of the database objects. * @param logger the logger object. * @param logkinds kinds of logged messages by bitwise-or: Logger::DEBUG for debugging, * Logger::INFO for normal information, Logger::SYSTEM for system information, and * Logger::ERROR for fatal error. * @param expr an expression given in the command line. */ virtual void configure(TimedDB* dbary, size_t dbnum, ThreadedServer::Logger* logger, uint32_t logkinds, const char* expr) = 0; /** * Start the service. * @return true on success, or false on failure. */ virtual bool start() = 0; /** * Stop the service. * @return true on success, or false on failure. */ virtual bool stop() = 0; /** * Finish the service. * @return true on success, or false on failure. */ virtual bool finish() = 0; }; /** * The name of the initializer function. */ const char* const KTSERVINITNAME = "ktservinit"; extern "C" { /** * Initializer of a server implementation. * @note Each shared library of a pluggable server module must implement a function whose name is * "ktservinit" and return a new instance of a derived class of the PluggableServer class. The * instance will be deleted implicitly by the caller. */ typedef PluggableServer* (*KTSERVINIT)(); } } // common namespace #endif // duplication check // END OF FILE kyototycoon-0.9.56/ktutilserv.cc0000644000175000017500000005601511757471602015762 0ustar mikiomikio/************************************************************************************************* * The testing implementations using the server tool kit * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "cmdcommon.h" // global variables const char* g_progname; // program name kt::ServerSocket *g_servsock; // running server socket kt::Poller *g_poller; // running poller kt::ThreadedServer* g_thserv; // running threaded server kt::HTTPServer* g_httpserv; // running HTTP server kt::RPCServer* g_rpcserv; // running RPC server // function prototypes int main(int argc, char** argv); static void usage(); static void killserver(int signum); static int32_t runecho(int argc, char** argv); static int32_t runmtecho(int argc, char** argv); static int32_t runhttp(int argc, char** argv); static int32_t runrpc(int argc, char** argv); static int32_t procecho(const char* host, int32_t port, double tout); static int32_t procmtecho(const char* host, int32_t port, double tout, int32_t thnum, uint32_t logkinds); static int32_t prochttp(const char* base, const char* host, int32_t port, double tout, int32_t thnum, uint32_t logkinds); static int32_t procrpc(const char* host, int32_t port, double tout, int32_t thnum, uint32_t logkinds); // main routine int main(int argc, char** argv) { g_progname = argv[0]; kc::setstdiobin(); kt::setkillsignalhandler(killserver); if (argc < 2) usage(); int32_t rv = 0; if (!std::strcmp(argv[1], "echo")) { rv = runecho(argc, argv); } else if (!std::strcmp(argv[1], "mtecho")) { rv = runmtecho(argc, argv); } else if (!std::strcmp(argv[1], "http")) { rv = runhttp(argc, argv); } else if (!std::strcmp(argv[1], "rpc")) { rv = runrpc(argc, argv); } else if (!std::strcmp(argv[1], "version") || !std::strcmp(argv[1], "--version")) { printversion(); rv = 0; } else { usage(); } return rv; } // print the usage and exit static void usage() { eprintf("%s: testing implementations using the server tool kit\n", g_progname); eprintf("\n"); eprintf("usage:\n"); eprintf(" %s echo [-host str] [-port num] [-tout num]\n", g_progname); eprintf(" %s mtecho [-host str] [-port num] [-tout num] [-th num] [-li|-ls|-le|-lz]\n", g_progname); eprintf(" %s http [-host str] [-port num] [-tout num] [-th num] [-li|-ls|-le|-lz]" " [basedir]\n", g_progname); eprintf(" %s rpc [-host str] [-port num] [-tout num] [-th num] [-li|-ls|-le|-lz]\n", g_progname); eprintf("\n"); std::exit(1); } // kill the running server static void killserver(int signum) { oprintf("%s: catched the signal %d\n", g_progname, signum); if (g_servsock) { g_servsock->abort(); g_servsock = NULL; } if (g_poller) { g_poller->abort(); g_poller = NULL; } if (g_thserv) { g_thserv->stop(); g_thserv = NULL; } if (g_httpserv) { g_httpserv->stop(); g_httpserv = NULL; } if (g_rpcserv) { g_rpcserv->stop(); g_rpcserv = NULL; } } // parse arguments of echo command static int32_t runecho(int argc, char** argv) { bool argbrk = false; const char* host = NULL; int32_t port = kt::DEFPORT; double tout = DEFTOUT; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else { usage(); } } else { argbrk = true; usage(); } } if (port < 1) usage(); int32_t rv = procecho(host, port, tout); return rv; } // parse arguments of mtecho command static int32_t runmtecho(int argc, char** argv) { bool argbrk = false; const char* host = NULL; int32_t port = kt::DEFPORT; double tout = DEFTOUT; int32_t thnum = DEFTHNUM; uint32_t logkinds = kc::UINT32MAX; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-li")) { logkinds = kt::ThreadedServer::Logger::INFO | kt::ThreadedServer::Logger::SYSTEM | kt::ThreadedServer::Logger::ERROR; } else if (!std::strcmp(argv[i], "-ls")) { logkinds = kt::ThreadedServer::Logger::SYSTEM | kt::ThreadedServer::Logger::ERROR; } else if (!std::strcmp(argv[i], "-le")) { logkinds = kt::ThreadedServer::Logger::ERROR; } else if (!std::strcmp(argv[i], "-lz")) { logkinds = 0; } else { usage(); } } else { argbrk = true; usage(); } } if (port < 1 || thnum < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = procmtecho(host, port, tout, thnum, logkinds); return rv; } // parse arguments of http command static int32_t runhttp(int argc, char** argv) { bool argbrk = false; const char* host = NULL; const char* base = NULL; int32_t port = kt::DEFPORT; double tout = DEFTOUT; int32_t thnum = DEFTHNUM; uint32_t logkinds = kc::UINT32MAX; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-li")) { logkinds = kt::HTTPServer::Logger::INFO | kt::HTTPServer::Logger::SYSTEM | kt::HTTPServer::Logger::ERROR; } else if (!std::strcmp(argv[i], "-ls")) { logkinds = kt::HTTPServer::Logger::SYSTEM | kt::HTTPServer::Logger::ERROR; } else if (!std::strcmp(argv[i], "-le")) { logkinds = kt::HTTPServer::Logger::ERROR; } else if (!std::strcmp(argv[i], "-lz")) { logkinds = 0; } else { usage(); } } else if (!base) { argbrk = true; base = argv[i]; } else { usage(); } } if (port < 1 || thnum < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = prochttp(base, host, port, tout, thnum, logkinds); return rv; } // parse arguments of rpc command static int32_t runrpc(int argc, char** argv) { bool argbrk = false; const char* host = NULL; int32_t port = kt::DEFPORT; double tout = DEFTOUT; int32_t thnum = DEFTHNUM; uint32_t logkinds = kc::UINT32MAX; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-li")) { logkinds = kt::RPCServer::Logger::INFO | kt::RPCServer::Logger::SYSTEM | kt::RPCServer::Logger::ERROR; } else if (!std::strcmp(argv[i], "-ls")) { logkinds = kt::RPCServer::Logger::SYSTEM | kt::RPCServer::Logger::ERROR; } else if (!std::strcmp(argv[i], "-le")) { logkinds = kt::RPCServer::Logger::ERROR; } else if (!std::strcmp(argv[i], "-lz")) { logkinds = 0; } else { usage(); } } else { argbrk = true; usage(); } } if (port < 1 || thnum < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = procrpc(host, port, tout, thnum, logkinds); return rv; } // perform echo command static int32_t procecho(const char* host, int32_t port, double tout) { std::string addr = ""; if (host) { addr = kt::Socket::get_host_address(host); if (addr.empty()) { eprintf("%s: %s: unknown host\n", g_progname, host); return 1; } } std::string expr = kc::strprintf("%s:%d", addr.c_str(), port); kt::ServerSocket serv; if (!serv.open(expr)) { eprintf("%s: server: open error: %s\n", g_progname, serv.error()); return 1; } bool err = false; kt::Poller poll; if (!poll.open()) { eprintf("%s: poller: open error: %s\n", g_progname, poll.error()); err = true; } g_servsock = &serv; g_poller = &poll; oprintf("%s: started: %s\n", g_progname, serv.expression().c_str()); serv.set_event_flags(kt::Pollable::EVINPUT); if (!poll.deposit(&serv)) { eprintf("%s: poller: deposit error: %s\n", g_progname, poll.error()); err = true; } while (g_servsock) { if (poll.wait()) { kt::Pollable* event; while ((event = poll.next()) != NULL) { if (event == &serv) { kt::Socket* sock = new kt::Socket; sock->set_timeout(tout); if (serv.accept(sock)) { oprintf("%s: connected: %s\n", g_progname, sock->expression().c_str()); sock->set_event_flags(kt::Pollable::EVINPUT); if (!poll.deposit(sock)) { eprintf("%s: poller: deposit error: %s\n", g_progname, poll.error()); err = true; } } else { eprintf("%s: server: accept error: %s\n", g_progname, serv.error()); err = true; delete[] sock; } serv.set_event_flags(kt::Pollable::EVINPUT); if (!poll.undo(&serv)) { eprintf("%s: poller: undo error: %s\n", g_progname, poll.error()); err = true; } } else { kt::Socket* sock = (kt::Socket*)event; char line[LINEBUFSIZ]; if (sock->receive_line(line, sizeof(line))) { oprintf("%s: (%s): %s\n", g_progname, sock->expression().c_str(), line); if (!kc::stricmp(line, "/quit")) { if (!sock->printf("> Bye!\n")) { eprintf("%s: socket: printf error: %s\n", g_progname, sock->error()); err = true; } oprintf("%s: closing: %s\n", g_progname, sock->expression().c_str()); if (!poll.withdraw(sock)) { eprintf("%s: poller: withdraw error: %s\n", g_progname, poll.error()); err = true; } if (!sock->close()) { eprintf("%s: socket: close error: %s\n", g_progname, poll.error()); err = true; } delete sock; } else { if (!sock->printf("> %s\n", line)) { eprintf("%s: socket: printf error: %s\n", g_progname, sock->error()); err = true; } serv.set_event_flags(kt::Pollable::EVINPUT); if (!poll.undo(sock)) { eprintf("%s: poller: undo error: %s\n", g_progname, poll.error()); err = true; } } } else { oprintf("%s: closed: %s\n", g_progname, sock->expression().c_str()); if (!poll.withdraw(sock)) { eprintf("%s: poller: withdraw error: %s\n", g_progname, poll.error()); err = true; } if (!sock->close()) { eprintf("%s: socket: close error: %s\n", g_progname, poll.error()); err = true; } delete sock; } } } } else { eprintf("%s: poller: wait error: %s\n", g_progname, poll.error()); err = true; } } g_poller = NULL; if (poll.flush()) { kt::Pollable* event; while ((event = poll.next()) != NULL) { if (event != &serv) { kt::Socket* sock = (kt::Socket*)event; oprintf("%s: discarded: %s\n", g_progname, sock->expression().c_str()); if (!poll.withdraw(sock)) { eprintf("%s: poller: withdraw error: %s\n", g_progname, poll.error()); err = true; } if (!sock->close()) { eprintf("%s: socket: close error: %s\n", g_progname, poll.error()); err = true; } delete sock; } } } else { eprintf("%s: poller: flush error: %s\n", g_progname, poll.error()); err = true; } oprintf("%s: finished: %s\n", g_progname, serv.expression().c_str()); if (!poll.close()) { eprintf("%s: poller: close error: %s\n", g_progname, poll.error()); err = true; } if (!serv.close()) { eprintf("%s: server: close error: %s\n", g_progname, serv.error()); err = true; } return err ? 1 : 0; } // perform mtecho command static int32_t procmtecho(const char* host, int32_t port, double tout, int32_t thnum, uint32_t logkinds) { std::string addr = ""; if (host) { addr = kt::Socket::get_host_address(host); if (addr.empty()) { eprintf("%s: %s: unknown host\n", g_progname, host); return 1; } } std::string expr = kc::strprintf("%s:%d", addr.c_str(), port); kt::ThreadedServer serv; kt::ThreadedServer::Logger* logger = stdlogger(g_progname, &std::cout); class Worker : public kt::ThreadedServer::Worker { private: bool process(kt::ThreadedServer* serv, kt::ThreadedServer::Session* sess) { bool keep = false; char line[LINEBUFSIZ]; if (sess->receive_line(line, sizeof(line))) { if (!kc::stricmp(line, "/quit")) { sess->printf("> Bye!\n"); } else { class Data : public kt::ThreadedServer::Session::Data { public: time_t t; }; Data* data = (Data*)sess->data(); if (!data) { data = new Data; sess->set_data(data); data->t = kc::time(); } sess->printf("> %s\n", line); serv->log(kt::ThreadedServer::Logger::INFO, "(%s): id=%llu thid=%u time=%lld msg=%s", sess->expression().c_str(), (unsigned long long)sess->id(), (unsigned)sess->thread_id(), (long long)(kc::time() - data->t), line); keep = true; } } return keep; } }; Worker worker; bool err = false; serv.set_network(expr, tout); serv.set_logger(logger, logkinds); serv.set_worker(&worker, thnum); g_thserv = &serv; serv.log(kt::ThreadedServer::Logger::SYSTEM, "================ [START]"); if (serv.start()) { if (serv.finish()) err = true; } else { err = true; } serv.log(kt::ThreadedServer::Logger::SYSTEM, "================ [FINISH]"); return err ? 1 : 0; } // perform http command static int32_t prochttp(const char* base, const char* host, int32_t port, double tout, int32_t thnum, uint32_t logkinds) { if (!base) base = kc::File::CDIRSTR; std::string baseabs = kc::File::absolute_path(base); if (baseabs.empty()) { eprintf("%s: %s: unknown directory\n", g_progname, base); return 1; } std::string addr = ""; if (host) { addr = kt::Socket::get_host_address(host); if (addr.empty()) { eprintf("%s: %s: unknown host\n", g_progname, host); return 1; } } std::string expr = kc::strprintf("%s:%d", addr.c_str(), port); kt::HTTPServer serv; kt::HTTPServer::Logger* logger = stdlogger(g_progname, &std::cout); class Worker : public kt::HTTPServer::Worker { public: explicit Worker(const std::string& base) : base_(base) {} private: int32_t process(kt::HTTPServer* serv, kt::HTTPServer::Session* sess, const std::string& path, kt::HTTPClient::Method method, const std::map& reqheads, const std::string& reqbody, std::map& resheads, std::string& resbody, const std::map& misc) { const char* url = kt::strmapget(misc, "url"); int32_t code = -1; const std::string& lpath = kt::HTTPServer::localize_path(path); std::string apath = base_ + (lpath.empty() ? "" : kc::File::PATHSTR) + lpath; bool dir = kc::strbwm(path.c_str(), "/"); if (method == kt::HTTPClient::MGET) { kc::File::Status sbuf; if (kc::File::status(apath, &sbuf)) { if (dir && sbuf.isdir) { const std::string& ipath = apath + kc::File::PATHSTR + "index.html"; if (kc::File::status(ipath)) { apath = ipath; sbuf.isdir = false; } } if (sbuf.isdir) { if (dir) { std::vector files; if (kc::File::read_directory(apath, &files)) { code = 200; resheads["content-type"] = "text/html"; kc::strprintf(&resbody, "\n"); kc::strprintf(&resbody, "\n"); kc::strprintf(&resbody, "
    \n"); kc::strprintf(&resbody, "
  • ./
  • \n"); kc::strprintf(&resbody, "
  • ../
  • \n"); kc::strprintf(&resbody, "
\n"); kc::strprintf(&resbody, "
    \n"); std::sort(files.begin(), files.end()); std::vector::iterator it = files.begin(); std::vector::iterator itend = files.end(); while (it != itend) { if (*it != kc::File::CDIRSTR && *it != kc::File::PDIRSTR) { std::string cpath = apath + kc::File::PATHSTR + *it; if (kc::File::status(cpath, &sbuf)) { char* ubuf = kc::urlencode(it->data(), it->size()); char* xstr = kt::xmlescape(it->c_str()); const char* dsuf = sbuf.isdir ? "/" : ""; kc::strprintf(&resbody, "
  • %s%s
  • \n", ubuf, dsuf, xstr, dsuf); delete[] xstr; delete[] ubuf; } } ++it; } kc::strprintf(&resbody, "
\n"); kc::strprintf(&resbody, "\n"); kc::strprintf(&resbody, "\n"); } else { code = 403; resheads["content-type"] = "text/plain"; kc::strprintf(&resbody, "%s\n", kt::HTTPServer::status_name(code)); } } else { code = 301; resheads["content-type"] = "text/plain"; resheads["location"] = (url ? url : path) + '/'; kc::strprintf(&resbody, "%s\n", kt::HTTPServer::status_name(code)); } } else { int64_t size; char* buf = kc::File::read_file(apath, &size, 256LL << 20); if (buf) { code = 200; const char* type = kt::HTTPServer::media_type(path); if (type) resheads["content-type"] = type; resbody.append(buf, size); delete[] buf; } else { code = 403; resheads["content-type"] = "text/plain"; kc::strprintf(&resbody, "%s\n", kt::HTTPServer::status_name(code)); } } } else { code = 404; resheads["content-type"] = "text/plain"; kc::strprintf(&resbody, "%s\n", kt::HTTPServer::status_name(code)); } } else { code = 403; resheads["content-type"] = "text/plain"; kc::strprintf(&resbody, "%s\n", kt::HTTPServer::status_name(code)); } return code; } std::string base_; }; Worker worker(baseabs); bool err = false; serv.set_network(expr, tout); serv.set_logger(logger, logkinds); serv.set_worker(&worker, thnum); g_httpserv = &serv; serv.log(kt::HTTPServer::Logger::SYSTEM, "================ [START]"); if (serv.start()) { if (serv.finish()) err = true; } else { err = true; } serv.log(kt::HTTPServer::Logger::SYSTEM, "================ [FINISH]"); return err ? 1 : 0; } // perform rpc command static int32_t procrpc(const char* host, int32_t port, double tout, int32_t thnum, uint32_t logkinds) { std::string addr = ""; if (host) { addr = kt::Socket::get_host_address(host); if (addr.empty()) { eprintf("%s: %s: unknown host\n", g_progname, host); return 1; } } std::string expr = kc::strprintf("%s:%d", addr.c_str(), port); kt::RPCServer serv; kt::RPCServer::Logger* logger = stdlogger(g_progname, &std::cout); class Worker : public kt::RPCServer::Worker { private: kt::RPCClient::ReturnValue process(kt::RPCServer* serv, kt::RPCServer::Session* sess, const std::string& name, const std::map& inmap, std::map& outmap) { outmap.insert(inmap.begin(), inmap.end()); return kt::RPCClient::RVSUCCESS; } }; Worker worker; bool err = false; serv.set_network(expr, tout); serv.set_logger(logger, logkinds); serv.set_worker(&worker, thnum); g_rpcserv = &serv; serv.log(kt::RPCServer::Logger::SYSTEM, "================ [START]"); if (serv.start()) { if (serv.finish()) err = true; } else { err = true; } serv.log(kt::RPCServer::Logger::SYSTEM, "================ [FINISH]"); return err ? 1 : 0; } // END OF FILE kyototycoon-0.9.56/ktulog.cc0000644000175000017500000000224311757471602015045 0ustar mikiomikio/************************************************************************************************* * Update logger * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "ktulog.h" #include "myconf.h" namespace kyototycoon { // common namespace // There is no implementation now. } // common namespace // END OF FILE kyototycoon-0.9.56/ktutiltest.cc0000644000175000017500000004765711757471602015776 0ustar mikiomikio/************************************************************************************************* * The test cases of the utility functions * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "cmdcommon.h" // global variables const char* g_progname; // program name uint32_t g_randseed; // random seed int64_t g_memusage; // memory usage // function prototypes int main(int argc, char** argv); static void usage(); static void errprint(int32_t line, const char* format, ...); static int32_t runhttp(int32_t argc, char** argv); static int32_t runrpc(int32_t argc, char** argv); static int32_t runulog(int32_t argc, char** argv); static int32_t prochttp(const char* url, int64_t rnum, int32_t thnum, kt::HTTPClient::Method meth, const char* body, std::map* reqheads, std::map* queries, double tout, bool ka); static int32_t procrpc(const char* proc, int64_t rnum, std::map* params, int32_t thnum, const char* host, int32_t port, double tout); static int32_t proculog(const char* path, int64_t rnum, int32_t thnum, int64_t ulim); // main routine int main(int argc, char** argv) { g_progname = argv[0]; const char* ebuf = kc::getenv("KTRNDSEED"); g_randseed = ebuf ? (uint32_t)kc::atoi(ebuf) : (uint32_t)(kc::time() * 1000); mysrand(g_randseed); g_memusage = memusage(); kc::setstdiobin(); if (argc < 2) usage(); int32_t rv = 0; if (!std::strcmp(argv[1], "http")) { rv = runhttp(argc, argv); } else if (!std::strcmp(argv[1], "rpc")) { rv = runrpc(argc, argv); } else if (!std::strcmp(argv[1], "ulog")) { rv = runulog(argc, argv); } else { usage(); } if (rv != 0) { oprintf("FAILED: KTRNDSEED=%u PID=%ld", g_randseed, (long)kc::getpid()); for (int32_t i = 0; i < argc; i++) { oprintf(" %s", argv[i]); } oprintf("\n\n"); } return rv; } // print the usage and exit static void usage() { eprintf("%s: test cases of the utility functions of Kyoto Tycoon\n", g_progname); eprintf("\n"); eprintf("usage:\n"); eprintf(" %s http [-th num] [-get|-head|-post|-put|-delete] [-body file] [-ah name value]" " [-qs name value] [-tout num] [-ka] url rnum\n", g_progname); eprintf(" %s rpc [-th num] [-host str] [-port num] [-tout num] proc rnum [name value ...]\n", g_progname); eprintf(" %s ulog [-th num] [-ulim num] path rnum\n", g_progname); eprintf("\n"); std::exit(1); } // print formatted error information string and flush the buffer static void errprint(int32_t line, const char* format, ...) { std::string msg; kc::strprintf(&msg, "%s: %d: ", g_progname, line); va_list ap; va_start(ap, format); kc::vstrprintf(&msg, format, ap); va_end(ap); kc::strprintf(&msg, "\n"); std::cout << msg; std::cout.flush(); } // parse arguments of http command static int32_t runhttp(int32_t argc, char** argv) { bool argbrk = false; const char* url = NULL; const char* rstr = NULL; int32_t thnum = 1; kt::HTTPClient::Method meth = kt::HTTPClient::MUNKNOWN; const char* body = NULL; std::map reqheads; std::map queries; double tout = 0; bool ka = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-get")) { meth = kt::HTTPClient::MGET; } else if (!std::strcmp(argv[i], "-head")) { meth = kt::HTTPClient::MHEAD; } else if (!std::strcmp(argv[i], "-post")) { meth = kt::HTTPClient::MPOST; } else if (!std::strcmp(argv[i], "-put")) { meth = kt::HTTPClient::MPUT; } else if (!std::strcmp(argv[i], "-delete")) { meth = kt::HTTPClient::MDELETE; } else if (!std::strcmp(argv[i], "-body")) { if (++i >= argc) usage(); body = argv[i]; } else if (!std::strcmp(argv[i], "-ah")) { if ((i += 2) >= argc) usage(); char* name = kc::strdup(argv[i-1]); kc::strnrmspc(name); kc::strtolower(name); reqheads[name] = argv[i]; delete[] name; } else if (!std::strcmp(argv[i], "-qs")) { if ((i += 2) >= argc) usage(); queries[argv[i-1]] = argv[i]; } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ka")) { ka = true; } else { usage(); } } else if (!url) { argbrk = false; url = argv[i]; } else if (!rstr) { rstr = argv[i]; } else { usage(); } } if (!url || !rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = prochttp(url, rnum, thnum, meth, body, &reqheads, &queries, tout, ka); return rv; } // parse arguments of rpc command static int32_t runrpc(int32_t argc, char** argv) { bool argbrk = false; const char* proc = NULL; const char* rstr = NULL; std::map params; int32_t thnum = 1; const char* host = NULL; int32_t port = kt::DEFPORT; double tout = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else { usage(); } } else if (!proc) { argbrk = false; proc = argv[i]; } else if (!rstr) { rstr = argv[i]; } else { if (++i >= argc) usage(); params[argv[i-1]] = argv[i]; } } if (!proc || !rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1 || port < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = procrpc(proc, rnum, ¶ms, thnum, host, port, tout); return rv; } // parse arguments of ulog command static int32_t runulog(int32_t argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* rstr = NULL; int32_t thnum = 1; int64_t ulim = -1; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else { usage(); } } else if (!path) { argbrk = false; path = argv[i]; } else if (!rstr) { rstr = argv[i]; } else { usage(); } } if (!path || !rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = proculog(path, rnum, thnum, ulim); return rv; } // perform http command static int32_t prochttp(const char* url, int64_t rnum, int32_t thnum, kt::HTTPClient::Method meth, const char* body, std::map* reqheads, std::map* queries, double tout, bool ka) { oprintf("\n seed=%u url=%s rnum=%lld thnum=%d meth=%d tout=%.3f ka=%d\n\n", g_randseed, url, (long long)rnum, thnum, (int)meth, tout, ka); const char* istr = body && *body == '@' ? body + 1 : NULL; std::istream *is; std::ifstream ifs; std::istringstream iss(istr ? istr : ""); if (body) { if (istr) { is = &iss; } else { ifs.open(body, std::ios_base::in | std::ios_base::binary); if (!ifs) { errprint(__LINE__, "%s: open error", body); return 1; } is = &ifs; } } else { is = &std::cin; } std::string urlstr = url; std::ostringstream oss; bool isbody = body || meth == kt::HTTPClient::MPOST || meth == kt::HTTPClient::MPUT; if (isbody) { if (queries->empty()) { char c; while (is->get(c)) { oss.put(c); } } else { std::map::const_iterator it = queries->begin(); std::map::const_iterator itend = queries->end(); bool first = true; while (it != itend) { char* name = kc::urlencode(it->first.data(), it->first.size()); char* value = kc::urlencode(it->second.data(), it->second.size()); if (first) { first = false; } else { oss << "&"; } oss << name << "=" << value; delete[] value; delete[] name; ++it; } (*reqheads)["content-type"] = "application/x-www-form-urlencoded"; } } else if (!queries->empty()) { std::map::const_iterator it = queries->begin(); std::map::const_iterator itend = queries->end(); bool first = !std::strchr(url, '?'); while (it != itend) { char* name = kc::urlencode(it->first.data(), it->first.size()); char* value = kc::urlencode(it->second.data(), it->second.size()); if (first) { first = false; urlstr.append("?"); } else { urlstr.append("&"); } urlstr.append(name); urlstr.append("="); urlstr.append(value); delete[] value; delete[] name; ++it; } } if (!kt::strmapget(*reqheads, "user-agent")) { std::string uastr; kc::strprintf(&uastr, "KyotoTycoon/%s", kt::VERSION); (*reqheads)["user-agent"] = uastr; } if (!kt::strmapget(*reqheads, "accept")) (*reqheads)["accept"] = "*/*"; const std::string& ostr = oss.str(); const std::string* reqbody = isbody ? &ostr : NULL; if (meth == kt::HTTPClient::MUNKNOWN) meth = isbody ? kt::HTTPClient::MPOST : kt::HTTPClient::MGET; bool err = false; class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), url_(NULL), meth_(), reqheads_(NULL), reqbody_(NULL), tout_(0), err_(false), okcnt_(0) {} void setparams(int32_t id, int64_t rnum, const char* url, kt::HTTPClient::Method meth, const std::map* reqheads, const std::string* reqbody, double tout, bool ka) { id_ = id; rnum_ = rnum; url_ = url; meth_ = meth; reqheads_ = reqheads; reqbody_ = reqbody; tout_ = tout; ka_ = ka; } bool error() { return err_; } int64_t okcnt() { return okcnt_; } private: void run() { kt::URL u(url_); kt::HTTPClient ua; bool open = false; std::map resheads; for (int64_t i = 1; i <= rnum_; i++) { if (!open) { if (!ua.open(u.host(), u.port(), tout_)) { err_ = true; break; } open = true; } int32_t code = ua.fetch(u.path_query(), meth_, NULL, &resheads, reqbody_, reqheads_); if (code >= 200 && code < 300) okcnt_++; const char* conn = kt::strmapget(resheads, "connection"); if (!ka_ || code < 0 || (conn && !kc::stricmp(conn, "close"))) { if (!ua.close(false)) err_ = true; open = false; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } if (open && !ua.close()) err_ = true; } int32_t id_; int64_t rnum_; const char* url_; kt::HTTPClient::Method meth_; const std::map* reqheads_; const std::string* reqbody_; double tout_; bool ka_; bool err_; int64_t okcnt_; }; Worker* workers = new Worker[thnum]; double stime = kc::time(); for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, url, meth, reqheads, reqbody, tout, ka); workers[i].start(); } int64_t okcnt = 0; for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; okcnt += workers[i].okcnt(); } double etime = kc::time(); oprintf("OK count: %lld\n", (long long)okcnt); oprintf("NG count: %lld\n", (long long)(rnum * thnum - okcnt)); oprintf("time: %.3f\n", etime - stime); oprintf("throughput: %.3f req/s\n", okcnt / (etime - stime)); delete[] workers; oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform rpc command static int32_t procrpc(const char* proc, int64_t rnum, std::map* params, int32_t thnum, const char* host, int32_t port, double tout) { oprintf("\n seed=%u proc=%s rnum=%lld thnum=%d host=%s port=%d tout=%.3f\n\n", g_randseed, proc, (long long)rnum, thnum, host ? host : "-", port, tout); std::string lhost = kt::Socket::get_local_host_name(); if (!host) { if (lhost.empty()) { errprint(__LINE__, "getting the local host name failed"); return 1; } host = lhost.c_str(); } bool err = false; class Worker : public kc::Thread { public: Worker() : id_(0), rnum_(0), proc_(NULL), host_(NULL), port_(0), tout_(0), params_(NULL), err_(false), okcnt_(0) {} void setparams(int32_t id, int64_t rnum, const char* proc, const char* host, int32_t port, double tout, const std::map* params) { id_ = id; rnum_ = rnum; proc_ = proc; host_ = host; port_ = port; tout_ = tout; params_ = params; } bool error() { return err_; } int64_t okcnt() { return okcnt_; } private: void run() { kt::RPCClient rpc; if (!rpc.open(host_, port_, tout_)) { err_ = true; return; } std::map outmap; for (int64_t i = 1; i <= rnum_; i++) { kt::RPCClient::ReturnValue rv = rpc.call(proc_, params_, &outmap); if (rv == kt::RPCClient::RVSUCCESS) { okcnt_++; } else { err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } if (!rpc.close()) err_ = true; } int32_t id_; int64_t rnum_; const char* proc_; const char* host_; int32_t port_; double tout_; const std::map* params_; bool err_; int64_t okcnt_; }; Worker* workers = new Worker[thnum]; double stime = kc::time(); for (int32_t i = 0; i < thnum; i++) { workers[i].setparams(i, rnum, proc, host, port, tout, params); workers[i].start(); } int64_t okcnt = 0; for (int32_t i = 0; i < thnum; i++) { workers[i].join(); if (workers[i].error()) err = true; okcnt += workers[i].okcnt(); } double etime = kc::time(); oprintf("OK count: %lld\n", (long long)okcnt); oprintf("NG count: %lld\n", (long long)(rnum * thnum - okcnt)); oprintf("time: %.3f\n", etime - stime); oprintf("throughput: %.3f req/s\n", okcnt / (etime - stime)); delete[] workers; oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform ulog command static int32_t proculog(const char* path, int64_t rnum, int32_t thnum, int64_t ulim) { oprintf("\n seed=%u path=%s rnum=%lld thnum=%d ulim=%lld\n\n", g_randseed, path, (long long)rnum, thnum, (long long)ulim); bool err = false; bool init = !kc::File::status(path); kt::UpdateLogger ulog; if (!ulog.open(path, ulim)) { errprint(__LINE__, "opening the logger failed"); return false; } class Writer : public kc::Thread { public: Writer() : ulog_(NULL), rnum_(0), err_(false) {} void setparams(int32_t id, kt::UpdateLogger* ulog, int64_t rnum) { id_ = id; ulog_ = ulog; rnum_ = rnum; } bool error() { return err_; } private: void run() { for (int64_t i = 1; i <= rnum_; i++) { char rbuf[RECBUFSIZ]; size_t rsiz = std::sprintf(rbuf, "%lld", (long long)i); if (!ulog_->write(rbuf, rsiz)) { errprint(__LINE__, "writing a log failed"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } int32_t id_; kt::UpdateLogger* ulog_; int64_t rnum_; bool err_; }; class Reader : public kc::Thread { public: Reader() : ulog_(NULL), rnum_(0), alive_(true), cnt_(0), err_(false) {} void setparams(int32_t id, kt::UpdateLogger* ulog, int64_t rnum) { id_ = id; ulog_ = ulog; rnum_ = rnum; } void stop() { alive_ = false; } int64_t count() { return cnt_; } bool error() { return err_; } private: void run() { kt::UpdateLogger::Reader ulrd; if (!ulrd.open(ulog_, 0)) { errprint(__LINE__, "opening a reader failed"); err_ = true; } while (alive_) { const char* mbuf; size_t msiz; uint64_t mts; while ((mbuf = ulrd.read(&msiz, &mts)) != NULL) { cnt_ += 1; delete[] mbuf; } kc::Thread::sleep(0.1); } if (!ulrd.close()) { errprint(__LINE__, "opening a reader failed"); err_ = true; } } int32_t id_; kt::UpdateLogger* ulog_; int64_t rnum_; bool alive_; kc::AtomicInt64 cnt_; bool err_; }; double stime = kc::time(); Reader readers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { readers[i].setparams(i, &ulog, rnum); readers[i].start(); } Writer writers[THREADMAX]; for (int32_t i = 0; i < thnum; i++) { writers[i].setparams(i, &ulog, rnum); writers[i].start(); } for (int32_t i = 0; i < thnum; i++) { writers[i].join(); if (writers[i].error()) { errprint(__LINE__, "writing logs failed"); err = true; } } for (int32_t i = 0; i < thnum; i++) { for (int32_t j = 0; j < 100; j++) { if (readers[i].count() >= rnum * thnum) break; kc::Thread::sleep(0.1); } readers[i].stop(); readers[i].join(); if (readers[i].error()) { errprint(__LINE__, "reading logs failed"); err = true; } if (init && readers[i].count() != rnum * thnum) { errprint(__LINE__, "reading logs failed"); err = true; } } if (!ulog.close()) { errprint(__LINE__, "closing the logger failed"); err = true; } double etime = kc::time(); oprintf("time: %.3f\n", etime - stime); oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // END OF FILE kyototycoon-0.9.56/ktsocket.h0000644000175000017500000002551211757471602015235 0ustar mikiomikio/************************************************************************************************* * Network functions * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTSOCKET_H // duplication check #define _KTSOCKET_H #include #include namespace kyototycoon { // common namespace /** * Interface of poolable I/O event. */ class Pollable { friend class Poller; public: /** * Event flags. */ enum EventFlag { EVINPUT = 1 << 0, ///< input EVOUTPUT = 1 << 1, ///< output EVEXCEPT = 1 << 2 ///< exception }; /** * Default constructor. */ explicit Pollable() : opq_(NULL) {} /** * Destructor. */ virtual ~Pollable() {} /** * Get the descriptor integer. * @return the descriptor integer, or -1 on failure. */ virtual int32_t descriptor() = 0; /** * Set event flags. * @param flags specifies the event mode. The following may be added by bitwise-or: * Pollable::EVINPUT for input events, Pollable::EVOUTPUT for output events, Pollable::EVEXCEPT * for exception events. */ virtual void set_event_flags(uint32_t flags) = 0; /** * Get the current event flags. * @return the current event flags. */ virtual uint32_t event_flags() = 0; private: /** Dummy constructor to forbid the use. */ Pollable(const Pollable&); /** Dummy Operator to forbid the use. */ Pollable& operator =(const Pollable&); /** Opaque pointer. */ void* opq_; }; /** * Network stream abstraction based on TCP/IP. */ class Socket : public Pollable { friend class ServerSocket; public: /** * Default constructor. */ explicit Socket(); /** * Destructor. */ ~Socket(); /** * Get the last happened error information. * @return the last happened error information. */ const char* error(); /** * Open a client socket. * @param expr an expression of the address and the port of the server. * @return true on success, or false on failure. */ bool open(const std::string& expr); /** * Close the socket. * @param grace true for graceful shutdown, or false for immediate disconnection. * @return true on success, or false on failure. */ bool close(bool grace = true); /** * Send data. * @param buf the pointer to a data region to send. * @param size the size of the data region. * @return true on success, or false on failure. */ bool send(const void* buf, size_t size); /** * Send data. * @param str a string to send. * @return true on success, or false on failure. */ bool send(const std::string& str); /** * Send formatted data. * @param format the printf-like format string. The conversion character `%' can be used with * such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `%'. * @param ... used according to the format string. * @return true on success, or false on failure. */ bool printf(const char* format, ...); /** * Send formatted data. * @param format the printf-like format string. The conversion character `%' can be used with * such flag characters as `s', `d', `o', `u', `x', `X', `c', `e', `E', `f', `g', `G', and `%'. * @param ap used according to the format string. * @return true on success, or false on failure. */ bool vprintf(const char* format, va_list ap); /** * Receive data. * @param buf the pointer to the buffer into which the received data is written. * @param size the size of the data to receive. * @return true on success, or false on failure. */ bool receive(void* buf, size_t size); /** * Receive one byte. * @return the received byte or -1 on failure. */ int32_t receive_byte(); /** * Push one byte back. * @param c specifies the byte. * @return true on success, or false on failure. * @note The character is available for subsequent receive operations. Only one pushback is * guaranteed. */ bool undo_receive_byte(int32_t c); /** * Receive one line of characters. * @param buf the pointer to the buffer into which the received data is written. * @param max the maximum size of the data to receive. It must be more than 0. * @return true on success, or false on failure. */ bool receive_line(void* buf, size_t max); /** * Get the size of left data in the receiving buffer. * @return the size of left data in the receiving buffer. */ size_t left_size(); /** * Abort the current operation. * @return true on success, or false on failure. */ bool abort(); /** * Set the timeout of each operation. * @param timeout the timeout of each operation in seconds. * @return true on success, or false on failure. */ bool set_timeout(double timeout); /** * Get the expression of the socket. * @return the expression of the socket or an empty string on failure. */ const std::string expression(); /** * Get the descriptor integer. * @return the descriptor integer, or -1 on failure. */ int32_t descriptor(); /** * Set event flags. * @param flags specifies the event mode. The following may be added by bitwise-or: * Socket::EVINPUT for input events, Socket::EVOUTPUT for output events, Socket::EVEXCEPT for * exception events. */ void set_event_flags(uint32_t flags); /** * Get the current event flags. * @return the current event flags. */ uint32_t event_flags(); /** * Get the primary name of the local host. * @return the host name, or an empty string on failure. */ static std::string get_local_host_name(); /** * Get the address of a host. * @return the host address, or an empty string on failure. */ static std::string get_host_address(const std::string& name); private: /** Dummy constructor to forbid the use. */ Socket(const Socket&); /** Dummy Operator to forbid the use. */ Socket& operator =(const Socket&); /** Opaque pointer. */ void* opq_; }; /** * Network server abstraction based on TCP/IP. */ class ServerSocket : public Pollable { public: /** * Default constructor. */ explicit ServerSocket(); /** * Destructor. */ ~ServerSocket(); /** * Get the last happened error information. * @return the last happened error information. */ const char* error(); /** * Open a server socket. * @param expr an expression of the address and the port of the server. * @return true on success, or false on failure. */ bool open(const std::string& expr); /** * Close the socket. * @return true on success, or false on failure. */ bool close(); /** * Accept a connection from a client. * @param sock the socket object to manage the connection. * @return true on success, or false on failure. */ bool accept(Socket* sock); /** * Abort the current operation. * @return true on success, or false on failure. */ bool abort(); /** * Set the timeout of each operation. * @param timeout the timeout of each operation in seconds. * @return true on success, or false on failure. */ bool set_timeout(double timeout); /** * Get the expression of the socket. * @return the expression of the socket or an empty string on failure. */ const std::string expression(); /** * Get the descriptor integer. * @return the descriptor integer, or -1 on failure. */ int32_t descriptor(); /** * Set event flags. * @param flags specifies the event mode. The following may be added by bitwise-or: * ServerSocket::EVINPUT for input events, ServerSocket::EVOUTPUT for output events, * ServerSocket::EVERROR for error events. */ void set_event_flags(uint32_t flags); /** * Get the current event flags. * @return the current event flags. */ uint32_t event_flags(); private: /** Dummy constructor to forbid the use. */ ServerSocket(const Socket&); /** Dummy Operator to forbid the use. */ ServerSocket& operator =(const ServerSocket&); /** Opaque pointer. */ void* opq_; }; /** * I/O event notification. */ class Poller { public: /** * Default constructor. */ explicit Poller(); /** * Destructor. */ ~Poller(); /** * Get the last happened error information. * @return the last happened error information. */ const char* error(); /** * Open the poller. * @return true on success, or false on failure. */ bool open(); /** * Close the poller. * @return true on success, or false on failure. */ bool close(); /** * Add a pollable I/O event to the monitored list. * @param event the pollable event object. * @return true on success, or false on failure. */ bool deposit(Pollable* event); /** * Remove a pollable I/O from the monitored list. * @param event the pollable event object. * @return true on success, or false on failure. */ bool withdraw(Pollable* event); /** * Fetch the next notified I/O event. * @return the event object, or NULL on failure. */ Pollable* next(); /** * Enable the next notification of a pollable event. * @param event the pollable event object. * @return true on success, or false on failure. */ bool undo(Pollable* event); /** * Wait one or more notifying events. * @param timeout the timeout in seconds. If it is not more than 0, no timeout is specified. * @return true on success, or false on failure. */ bool wait(double timeout = -1); /** * Notify all registered events. * @return true on success, or false on failure. */ bool flush(); /** * Get the number of events to watch. * @return the number of events to watch, or -1 on failure. */ int64_t count(); /** * Abort the current operation. * @return true on success, or false on failure. */ bool abort(); private: /** Dummy constructor to forbid the use. */ Poller(const Poller&); /** Dummy Operator to forbid the use. */ Poller& operator =(const Poller&); /** Opaque pointer. */ void* opq_; }; } // common namespace #endif // duplication check // END OF FILE kyototycoon-0.9.56/ktutilmgr.cc0000644000175000017500000004333011757471602015564 0ustar mikiomikio/************************************************************************************************* * The command line interface of miscellaneous utilities * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "cmdcommon.h" // global variables const char* g_progname; // program name // function prototypes int main(int argc, char** argv); static void usage(); static int32_t rundate(int32_t argc, char** argv); static int32_t runhttp(int32_t argc, char** argv); static int32_t runrpc(int32_t argc, char** argv); static int32_t runulog(int32_t argc, char** argv); static int32_t runconf(int argc, char** argv); static int32_t procdate(const char* str, int32_t jl, bool wf, bool rf); static int32_t prochttp(const char* url, kt::HTTPClient::Method meth, const char* body, std::map* reqheads, std::map* queries, double tout, bool ph, int32_t ec); static int32_t procrpc(const char* proc, std::map* params, const char* host, int32_t port, double tout, int32_t ienc, int32_t oenc); static int32_t proculog(const char* path, uint64_t ts, bool uw, bool uf); static int32_t procconf(int32_t mode); // main routine int main(int argc, char** argv) { g_progname = argv[0]; kc::setstdiobin(); if (argc < 2) usage(); int32_t rv = 0; if (!std::strcmp(argv[1], "date")) { rv = rundate(argc, argv); } else if (!std::strcmp(argv[1], "http")) { rv = runhttp(argc, argv); } else if (!std::strcmp(argv[1], "rpc")) { rv = runrpc(argc, argv); } else if (!std::strcmp(argv[1], "ulog")) { rv = runulog(argc, argv); } else if (!std::strcmp(argv[1], "conf")) { rv = runconf(argc, argv); } else if (!std::strcmp(argv[1], "version") || !std::strcmp(argv[1], "--version")) { printversion(); rv = 0; } else { usage(); } return rv; } // print the usage and exit static void usage() { eprintf("%s: command line interface of miscellaneous utilities of Kyoto Tycoon\n", g_progname); eprintf("\n"); eprintf("usage:\n"); eprintf(" %s date [-ds str] [-jl num] [-wf] [-rf]\n", g_progname); eprintf(" %s http [-get|-head|-post|-put|-delete] [-body file] [-ah name value]" " [-qs name value] [-tout num] [-ph] [-ec num] url\n", g_progname); eprintf(" %s rpc [-host str] [-port num] [-tout num] [-ienc str] [-oenc str]" " proc [name value ...]\n", g_progname); eprintf(" %s ulog [-ts num] [-uw] [-uf] path\n", g_progname); eprintf(" %s conf [-v|-i|-l|-p]\n", g_progname); eprintf(" %s version\n", g_progname); eprintf("\n"); std::exit(1); } // parse arguments of date command static int32_t rundate(int32_t argc, char** argv) { bool argbrk = false; const char* str = NULL; int32_t jl = kc::INT32MAX; bool wf = false; bool rf = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-ds")) { if (++i >= argc) usage(); str = argv[i]; } else if (!std::strcmp(argv[i], "-jl")) { if (++i >= argc) usage(); jl = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-wf")) { wf = true; } else if (!std::strcmp(argv[i], "-rf")) { rf = true; } else { usage(); } } else { argbrk = true; usage(); } } int32_t rv = procdate(str, jl, wf, rf); return rv; } // parse arguments of http command static int32_t runhttp(int32_t argc, char** argv) { bool argbrk = false; const char* url = NULL; kt::HTTPClient::Method meth = kt::HTTPClient::MUNKNOWN; const char* body = NULL; std::map reqheads; std::map queries; double tout = 0; bool ph = false; int32_t ec = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-get")) { meth = kt::HTTPClient::MGET; } else if (!std::strcmp(argv[i], "-head")) { meth = kt::HTTPClient::MHEAD; } else if (!std::strcmp(argv[i], "-post")) { meth = kt::HTTPClient::MPOST; } else if (!std::strcmp(argv[i], "-put")) { meth = kt::HTTPClient::MPUT; } else if (!std::strcmp(argv[i], "-delete")) { meth = kt::HTTPClient::MDELETE; } else if (!std::strcmp(argv[i], "-body")) { if (++i >= argc) usage(); body = argv[i]; } else if (!std::strcmp(argv[i], "-ah")) { if ((i += 2) >= argc) usage(); char* name = kc::strdup(argv[i-1]); kc::strnrmspc(name); kc::strtolower(name); reqheads[name] = argv[i]; delete[] name; } else if (!std::strcmp(argv[i], "-qs")) { if ((i += 2) >= argc) usage(); queries[argv[i-1]] = argv[i]; } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ph")) { ph = true; } else if (!std::strcmp(argv[i], "-ec")) { if (++i >= argc) usage(); ec = kc::atoi(argv[i]); } else { usage(); } } else if (!url) { argbrk = true; url = argv[i]; } else { usage(); } } if (!url) usage(); int32_t rv = prochttp(url, meth, body, &reqheads, &queries, tout, ph, ec); return rv; } // parse arguments of rpc command static int32_t runrpc(int32_t argc, char** argv) { bool argbrk = false; const char* proc = NULL; std::map params; const char* host = NULL; int32_t port = kt::DEFPORT; double tout = 0; int32_t ienc = 0; int32_t oenc = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-host")) { if (++i >= argc) usage(); host = argv[i]; } else if (!std::strcmp(argv[i], "-port")) { if (++i >= argc) usage(); port = kc::atoi(argv[i]); } else if (!std::strcmp(argv[i], "-tout")) { if (++i >= argc) usage(); tout = kc::atof(argv[i]); } else if (!std::strcmp(argv[i], "-ienc")) { if (++i >= argc) usage(); ienc = argv[i][0]; } else if (!std::strcmp(argv[i], "-oenc")) { if (++i >= argc) usage(); oenc = argv[i][0]; } else { usage(); } } else if (!proc) { argbrk = true; proc = argv[i]; } else { if (++i >= argc) usage(); params[argv[i-1]] = argv[i]; } } if (!proc || port < 1) usage(); int32_t rv = procrpc(proc, ¶ms, host, port, tout, ienc, oenc); return rv; } // parse arguments of ulog command static int32_t runulog(int32_t argc, char** argv) { bool argbrk = false; const char* path = NULL; uint64_t ts = 0; bool uw = false; bool uf = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-ts")) { if (++i >= argc) usage(); if (!std::strcmp(argv[i], "now") || !std::strcmp(argv[i], "-")) { ts = kt::UpdateLogger::clock_pure(); } else { ts = kc::atoix(argv[i]); } } else if (!std::strcmp(argv[i], "-uw")) { uw = true; } else if (!std::strcmp(argv[i], "-uf")) { uf = true; } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = proculog(path, ts, uw, uf); return rv; } // parse arguments of conf command static int32_t runconf(int argc, char** argv) { bool argbrk = false; int32_t mode = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-v")) { mode = 'v'; } else if (!std::strcmp(argv[i], "-i")) { mode = 'i'; } else if (!std::strcmp(argv[i], "-l")) { mode = 'l'; } else if (!std::strcmp(argv[i], "-p")) { mode = 'p'; } else { usage(); } } else { argbrk = true; usage(); } } int32_t rv = procconf(mode); return rv; } // perform date command static int32_t procdate(const char* str, int32_t jl, bool wf, bool rf) { int64_t t = str ? kt::strmktime(str) : std::time(NULL); if (wf) { char buf[48]; kt::datestrwww(t, jl, buf); oprintf("%s\n", buf); } else if (rf) { char buf[48]; kt::datestrhttp(t, jl, buf); oprintf("%s\n", buf); } else { oprintf("%lld\n", (long long)t); } return 0; } // perform http command static int32_t prochttp(const char* url, kt::HTTPClient::Method meth, const char* body, std::map* reqheads, std::map* queries, double tout, bool ph, int32_t ec) { const char* istr = body && *body == '@' ? body + 1 : NULL; std::istream *is; std::ifstream ifs; std::istringstream iss(istr ? istr : ""); if (body) { if (istr) { is = &iss; } else { ifs.open(body, std::ios_base::in | std::ios_base::binary); if (!ifs) { eprintf("%s: %s: open error\n", g_progname, body); return 1; } is = &ifs; } } else { is = &std::cin; } std::string urlstr = url; std::ostringstream oss; bool isbody = body || meth == kt::HTTPClient::MPOST || meth == kt::HTTPClient::MPUT; if (isbody) { if (queries->empty()) { char c; while (is->get(c)) { oss.put(c); } } else { std::map::const_iterator it = queries->begin(); std::map::const_iterator itend = queries->end(); bool first = true; while (it != itend) { char* name = kc::urlencode(it->first.data(), it->first.size()); char* value = kc::urlencode(it->second.data(), it->second.size()); if (first) { first = false; } else { oss << "&"; } oss << name << "=" << value; delete[] value; delete[] name; ++it; } (*reqheads)["content-type"] = "application/x-www-form-urlencoded"; } } else if (!queries->empty()) { std::map::const_iterator it = queries->begin(); std::map::const_iterator itend = queries->end(); bool first = !std::strchr(url, '?'); while (it != itend) { char* name = kc::urlencode(it->first.data(), it->first.size()); char* value = kc::urlencode(it->second.data(), it->second.size()); if (first) { first = false; urlstr.append("?"); } else { urlstr.append("&"); } urlstr.append(name); urlstr.append("="); urlstr.append(value); delete[] value; delete[] name; ++it; } } if (!kt::strmapget(*reqheads, "user-agent")) { std::string uastr; kc::strprintf(&uastr, "KyotoTycoon/%s", kt::VERSION); (*reqheads)["user-agent"] = uastr; } if (!kt::strmapget(*reqheads, "accept")) (*reqheads)["accept"] = "*/*"; const std::string& ostr = oss.str(); const std::string* reqbody = isbody ? &ostr : NULL; std::string resbody; std::map resheads; if (meth == kt::HTTPClient::MUNKNOWN) meth = isbody ? kt::HTTPClient::MPOST : kt::HTTPClient::MGET; bool err = false; int32_t code = kt::HTTPClient::fetch_once(urlstr, meth, &resbody, &resheads, reqbody, reqheads, tout); if ((ec < 1 && code > 0) || code == ec) { if (ph) { std::map::const_iterator it = resheads.begin(); std::map::const_iterator itend = resheads.end(); while (it != itend) { if (it->first.size() < 1) { std::cout << it->second << std::endl; } else { char* name = kc::strdup(it->first.c_str()); kt::strcapitalize(name); std::cout << name << ": " << it->second << std::endl; delete[] name; } ++it; } std::cout << std::endl; } std::cout << resbody; } else { err = true; const char* msg = NULL;; if (code < 0) { msg = resbody.c_str(); } else { msg = kt::strmapget(resheads, ""); } if (!msg) msg = "unknown error"; eprintf("%s: %s: error: %d: %s\n", g_progname, url, code, msg); } return err ? 1 : 0; } // perform rpc command static int32_t procrpc(const char* proc, std::map* params, const char* host, int32_t port, double tout, int32_t ienc, int32_t oenc) { std::string lhost = kt::Socket::get_local_host_name(); if (!host) { if (lhost.empty()) { eprintf("%s: getting the local host name failed", g_progname); return 1; } host = lhost.c_str(); } bool err = false; kt::RPCClient rpc; if (!rpc.open(host, port, tout)) { eprintf("%s: opening the connection failed\n", g_progname); return 1; } if (ienc != 0) kt::tsvmapdecode(params, ienc); std::map outmap; kt::RPCClient::ReturnValue rv = rpc.call(proc, params, &outmap); if (rv != kt::RPCClient::RVSUCCESS) err = true; const char* name; switch (rv) { case kt::RPCClient::RVSUCCESS: name = "RVSUCCESS"; break; case kt::RPCClient::RVEINVALID: name = "RVEINVALID"; break; case kt::RPCClient::RVELOGIC: name = "RVELOGIC"; break; case kt::RPCClient::RVETIMEOUT: name = "RVETIMEOUT"; break; case kt::RPCClient::RVEINTERNAL: name = "RVEINTERNAL"; break; case kt::RPCClient::RVENETWORK: name = "RVENETWORK"; break; default: name = "RVEMISC"; break; } oprintf("RV\t%d: %s\n", (int)rv, name); if (oenc != 0) kt::tsvmapencode(&outmap, oenc); std::map::iterator it = outmap.begin(); std::map::iterator itend = outmap.end(); while (it != itend) { oprintf("%s\t%s\n", it->first.c_str(), it->second.c_str()); ++it; } if (!rpc.close()) { eprintf("%s: closing the connection failed\n", g_progname); err = true; } return err ? 1 : 0; } // perform ulog command static int32_t proculog(const char* path, uint64_t ts, bool uw, bool uf) { kt::UpdateLogger ulog; if (!kc::File::status(path)) { if (!ulog.open(path, 0)) { eprintf("%s: opening the logger failed\n", g_progname); return 1; } if (!ulog.close()) { eprintf("%s: closing the logger failed\n", g_progname); return 1; } } if (!ulog.open(path, kc::INT64MIN)) { eprintf("%s: opening the logger failed\n", g_progname); return 1; } bool err = false; if (uf) { std::vector files; ulog.list_files(&files); std::vector::iterator it = files.begin(); std::vector::iterator itend = files.end(); while (it != itend) { if (it->ts >= ts) oprintf("%s\t%llu\t%llu\n", it->path.c_str(), (unsigned long long)it->size, (unsigned long long)it->ts); ++it; } } else { kt::UpdateLogger::Reader ulrd; if (!ulrd.open(&ulog, ts)) { eprintf("%s: opening the reader failed\n", g_progname); err = true; } while (true) { size_t msiz; uint64_t mts; char* mbuf = ulrd.read(&msiz, &mts); if (mbuf) { oprintf("%llu\t", (unsigned long long)mts); printdata(mbuf, msiz, true); oprintf("\n"); delete[] mbuf; } else if (uw) { kc::Thread::sleep(0.1); } else { break; } } if (!ulrd.close()) { eprintf("%s: closing the reader failed\n", g_progname); err = true; } } if (!ulog.close()) { eprintf("%s: closing the logger failed\n", g_progname); err = true; } return err ? 1 : 0; } // perform conf command static int32_t procconf(int32_t mode) { switch (mode) { case 'v': { oprintf("%s\n", kt::VERSION); break; } case 'i': { oprintf("%s\n", _KT_APPINC); break; } case 'l': { oprintf("%s\n", _KT_APPLIBS); break; } case 'p': { oprintf("%s\n", _KT_BINDIR); break; } default: { oprintf("VERSION: %s\n", kt::VERSION); oprintf("LIBVER: %d\n", kt::LIBVER); oprintf("LIBREV: %d\n", kt::LIBREV); oprintf("OSNAME: %s\n", kc::OSNAME); if (std::strcmp(_KT_PREFIX, "*")) { oprintf("prefix: %s\n", _KT_PREFIX); oprintf("includedir: %s\n", _KT_INCLUDEDIR); oprintf("libdir: %s\n", _KT_LIBDIR); oprintf("bindir: %s\n", _KT_BINDIR); oprintf("libexecdir: %s\n", _KT_LIBEXECDIR); oprintf("appinc: %s\n", _KT_APPINC); oprintf("applibs: %s\n", _KT_APPLIBS); } break; } } return 0; } // END OF FILE kyototycoon-0.9.56/ktplugdbvoid.cc0000644000175000017500000002543511757471602016246 0ustar mikiomikio/************************************************************************************************* * A pluggable database of no operation * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include namespace kc = kyotocabinet; namespace kt = kyototycoon; // pluggable database of no operation class VoidDB : public kt::PluggableDB { public: class Cursor; private: class ScopedVisitor; public: // cursor to indicate a record class Cursor : public BasicDB::Cursor { friend class VoidDB; public: // constructor explicit Cursor(VoidDB* db) : db_(db) { _assert_(db); } // destructor virtual ~Cursor() { _assert_(true); } // accept a visitor to the current record bool accept(Visitor* visitor, bool writable = true, bool step = false) { _assert_(visitor); db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); return false; } // jump the cursor to the first record for forward scan bool jump() { _assert_(true); db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); return false; } // jump the cursor to a record for forward scan bool jump(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); return false; } // jump the cursor to a record for forward scan bool jump(const std::string& key) { _assert_(true); db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); return false; } // jump the cursor to the last record for backward scan bool jump_back() { _assert_(true); db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); return false; } // jump the cursor to a record for backward scan bool jump_back(const char* kbuf, size_t ksiz) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ); db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); return false; } // jump the cursor to a record for backward scan bool jump_back(const std::string& key) { _assert_(true); db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); return false; } // step the cursor to the next record bool step() { _assert_(true); db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); return false; } // step the cursor to the previous record bool step_back() { _assert_(true); db_->set_error(_KCCODELINE_, Error::NOREC, "no record"); return false; } // get the database object VoidDB* db() { _assert_(true); return db_; } private: Cursor(const Cursor&); Cursor& operator =(const Cursor&); VoidDB* db_; }; // default constructor explicit VoidDB() : mlock_(), error_(), logger_(NULL), logkinds_(0), mtrigger_(NULL), path_("") { _assert_(true); } // destructor ~VoidDB() { _assert_(true); } // get the last happened error Error error() const { _assert_(true); return error_; } // set the error information void set_error(const char* file, int32_t line, const char* func, Error::Code code, const char* message) { _assert_(file && line > 0 && func && message); error_->set(code, message); if (logger_) { Logger::Kind kind = code == Error::BROKEN || code == Error::SYSTEM ? Logger::ERROR : Logger::INFO; if (kind & logkinds_) report(file, line, func, kind, "%d: %s: %s", code, Error::codename(code), message); } } // open a database file bool open(const std::string& path, uint32_t mode = OWRITER | OCREATE) { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); path_.append(path); trigger_meta(MetaTrigger::OPEN, "open"); return true; } // close the database file bool close() { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); path_.clear(); trigger_meta(MetaTrigger::CLOSE, "close"); return true; } // accept a visitor to a record bool accept(const char* kbuf, size_t ksiz, Visitor* visitor, bool writable = true) { _assert_(kbuf && ksiz <= kc::MEMMAXSIZ && visitor); kc::ScopedRWLock lock(&mlock_, false); size_t vsiz; visitor->visit_empty(kbuf, ksiz, &vsiz); return true; } // accept a visitor to multiple records at once bool accept_bulk(const std::vector& keys, Visitor* visitor, bool writable = true) { _assert_(visitor); kc::ScopedRWLock lock(&mlock_, writable); ScopedVisitor svis(visitor); std::vector::const_iterator kit = keys.begin(); std::vector::const_iterator kitend = keys.end(); while (kit != kitend) { size_t vsiz; visitor->visit_empty(kit->data(), kit->size(), &vsiz); ++kit; } return true; } // iterate to accept a visitor for each record bool iterate(Visitor *visitor, bool writable = true, ProgressChecker* checker = NULL) { _assert_(visitor); kc::ScopedRWLock lock(&mlock_, true); ScopedVisitor svis(visitor); trigger_meta(MetaTrigger::ITERATE, "iterate"); return true; } // scan each record in parallel bool scan_parallel(Visitor *visitor, size_t thnum, ProgressChecker* checker = NULL) { _assert_(visitor); kc::ScopedRWLock lock(&mlock_, false); ScopedVisitor svis(visitor); trigger_meta(MetaTrigger::ITERATE, "scan_parallel"); return true; } // synchronize updated contents with the file and the device bool synchronize(bool hard = false, FileProcessor* proc = NULL, ProgressChecker* checker = NULL) { _assert_(true); kc::ScopedRWLock lock(&mlock_, false); bool err = false; if (proc && !proc->process(path_, 0, 0)) { set_error(_KCCODELINE_, Error::LOGIC, "postprocessing failed"); err = true; } trigger_meta(MetaTrigger::SYNCHRONIZE, "synchronize"); return !err; } // occupy database by locking and do something meanwhile bool occupy(bool writable = true, FileProcessor* proc = NULL) { _assert_(true); kc::ScopedRWLock lock(&mlock_, writable); bool err = false; if (proc && !proc->process(path_, 0, 0)) { set_error(_KCCODELINE_, Error::LOGIC, "processing failed"); err = true; } trigger_meta(MetaTrigger::OCCUPY, "occupy"); return !err; } // begin transaction bool begin_transaction(bool hard = false) { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction"); return true; } // try to begin transaction bool begin_transaction_try(bool hard = false) { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); trigger_meta(MetaTrigger::BEGINTRAN, "begin_transaction_try"); return true; } // end transaction bool end_transaction(bool commit = true) { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); trigger_meta(commit ? MetaTrigger::COMMITTRAN : MetaTrigger::ABORTTRAN, "end_transaction"); return true; } // remove all records bool clear() { _assert_(true); kc::ScopedRWLock lock(&mlock_, true); trigger_meta(MetaTrigger::CLEAR, "clear"); return true; } // get the number of records int64_t count() { _assert_(true); kc::ScopedRWLock lock(&mlock_, false); return 0; } // get the size of the database file int64_t size() { _assert_(true); kc::ScopedRWLock lock(&mlock_, false); return 0; } // get the path of the database file std::string path() { _assert_(true); kc::ScopedRWLock lock(&mlock_, false); return path_; } // get the miscellaneous status information bool status(std::map* strmap) { _assert_(strmap); kc::ScopedRWLock lock(&mlock_, true); (*strmap)["type"] = kc::strprintf("%u", (unsigned)TYPEMISC); (*strmap)["path"] = path_; (*strmap)["count"] = "0"; (*strmap)["size"] = "0"; return true; } // create a cursor object Cursor* cursor() { _assert_(true); return new Cursor(this); } // write a log message void log(const char* file, int32_t line, const char* func, Logger::Kind kind, const char* message) { _assert_(file && line > 0 && func && message); kc::ScopedRWLock lock(&mlock_, false); if (!logger_) return; logger_->log(file, line, func, kind, message); } // set the internal logger bool tune_logger(Logger* logger, uint32_t kinds = Logger::WARN | Logger::ERROR) { _assert_(logger); kc::ScopedRWLock lock(&mlock_, true); logger_ = logger; logkinds_ = kinds; return true; } // set the internal meta operation trigger bool tune_meta_trigger(MetaTrigger* trigger) { _assert_(trigger); kc::ScopedRWLock lock(&mlock_, true); mtrigger_ = trigger; return true; } protected: // report a message for debugging void report(const char* file, int32_t line, const char* func, Logger::Kind kind, const char* format, ...) { _assert_(file && line > 0 && func && format); if (!logger_ || !(kind & logkinds_)) return; std::string message; kc::strprintf(&message, "%s: ", path_.empty() ? "-" : path_.c_str()); va_list ap; va_start(ap, format); kc::vstrprintf(&message, format, ap); va_end(ap); logger_->log(file, line, func, kind, message.c_str()); } // trigger a meta database operation void trigger_meta(MetaTrigger::Kind kind, const char* message) { _assert_(message); if (mtrigger_) mtrigger_->trigger(kind, message); } private: // scoped visitor class ScopedVisitor { public: explicit ScopedVisitor(Visitor* visitor) : visitor_(visitor) { _assert_(visitor); visitor_->visit_before(); } ~ScopedVisitor() { _assert_(true); visitor_->visit_after(); } private: Visitor* visitor_; }; VoidDB(const VoidDB&); VoidDB& operator =(const VoidDB&); kc::RWLock mlock_; kc::TSD error_; kc::BasicDB::Logger* logger_; uint32_t logkinds_; MetaTrigger* mtrigger_; std::string path_; }; // initializer called by the main server extern "C" void* ktdbinit() { return new VoidDB; } // END OF FILE kyototycoon-0.9.56/ktulog.h0000644000175000017500000005306211757471602014714 0ustar mikiomikio/************************************************************************************************* * Update logger * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTULOG_H // duplication check #define _KTULOG_H #include #include #define KTULPATHEXT "ulog" ///< extension of each file namespace kyototycoon { // common namespace /** * Update logger. */ class UpdateLogger { public: class Reader; struct FileStatus; private: struct Log; /** An alias of cached logs. */ typedef std::vector Cache; /* The maximum size of cached logs. */ static const size_t CACHEMAX = 65536; /* The magic data for meta data. */ static const uint8_t METAMAGIC = 0xa0; /* The magic data for beginning mark. */ static const uint8_t BEGMAGIC = 0xa1; /* The magic data for ending mark. */ static const uint8_t ENDMAGIC = 0xa2; /* The accuracy of wall clock time stamp. */ static const uint64_t TSWACC = 1000; /* The accuracy of logical time stamp. */ static const uint64_t TSLACC = 1000 * 1000; /* The waiting seconds of auto flush. */ static const double FLUSHWAIT = 0.1; public: /** * Reader of update logs. */ class Reader { public: /** * Default constructor. */ explicit Reader() : ulog_(NULL), ts_(0), id_(0), file_(), off_(0) { _assert_(true); } /** * Destructor. */ ~Reader() { _assert_(true); if (ulog_) close(); } /** * Open the reader. * @param ulog the update logger. * @param ts the maximum time stamp of already read logs. * @return true on success, or false on failure. */ bool open(UpdateLogger* ulog, uint64_t ts = 0) { _assert_(ulog); if (ulog_) return false; ulog_ = ulog; ts_ = ts; id_ = 0; std::vector names; kc::File::read_directory(ulog_->path_, &names); std::sort(names.begin(), names.end(), std::greater()); std::vector::iterator it = names.begin(); std::vector::iterator itend = names.end(); uint32_t lid = 0; std::string ext; kc::strprintf(&ext, "%c%s", kc::File::EXTCHR, KTULPATHEXT); while (it != itend && id_ < 1) { const std::string& path = ulog_->path_ + kc::File::PATHCHR + *it; if (kc::strbwm(path, ext) && file_.open(path, kc::File::OREADER | kc::File::ONOLOCK, 0)) { ulog_->flock_.lock_reader(); uint32_t cid = kc::atoi(it->c_str()); if (file_.refresh()) { int64_t fsiz; uint64_t fts; if (read_meta(&fsiz, &fts) && fts + TSWACC * TSLACC < ts) id_ = lid; } ulog_->flock_.unlock(); file_.close(); lid = cid; } ++it; } if (id_ < 1) id_ = lid > 0 ? lid : 1; ulog_->flock_.lock_reader(); const std::string& path = ulog_->generate_path(id_); if (!file_.open(path, kc::File::OREADER | kc::File::ONOLOCK, 0)) { ulog_->flock_.unlock(); ulog_ = NULL; return false; } int64_t fsiz; uint64_t fts; if (!read_meta(&fsiz, &fts)) { file_.close(); ulog_->flock_.unlock(); ulog_ = NULL; return false; } ulog_->flock_.unlock(); read_skip(ts); return true; } /** * Close the reader. */ bool close() { _assert_(true); if (!ulog_) return false; bool err = false; if (!file_.close()) err = true; ulog_ = NULL; return !err; } /** * Read the next message. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param tsp the pointer to the variable into which the time stamp is assigned. * @return the pointer to the region of the message, or NULL on failure. Because the region * of the return value is allocated with the the new[] operator, it should be released with * the delete[] operator when it is no longer in use. */ char* read(size_t* sp, uint64_t* tsp) { _assert_(sp && tsp); if (!ulog_) return NULL; ulog_->flock_.lock_reader(); char* mbuf = read_impl(sp, tsp); ulog_->flock_.unlock(); if (!mbuf) return NULL; if (*tsp <= ts_) { delete[] mbuf; return NULL; } return mbuf; } private: /** * Read the meta data. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param tsp the pointer to the variable into which the time stamp is assigned. * @return true on success, or false on failure. */ bool read_meta(int64_t* sp, uint64_t* tsp) { _assert_(sp && tsp); char hbuf[1+sizeof(uint64_t)+sizeof(uint64_t)]; int64_t psiz = file_.size(); if (psiz < (int64_t)sizeof(hbuf) || !file_.read(0, hbuf, sizeof(hbuf))) return false; const char* rp = hbuf; if (*(uint8_t*)(rp++) != METAMAGIC) return false; int64_t fsiz = kc::readfixnum(rp, sizeof(uint64_t)); rp += sizeof(uint64_t); uint64_t fts = kc::readfixnum(rp, sizeof(uint64_t)); if (psiz < fsiz) return false; *sp = fsiz; *tsp = fts; off_ = sizeof(hbuf); return true; } /** * Read the next message. * @param sp the pointer to the variable into which the size of the region of the return * value is assigned. * @param tsp the pointer to the variable into which the time stamp is assigned. * @return the pointer to the region of the message, or NULL on failure. */ char* read_impl(size_t* sp, uint64_t* tsp) { _assert_(sp && tsp); *sp = 0; *tsp = 0; char buf[1+sizeof(uint64_t)+sizeof(uint32_t)]; if (!file_.refresh()) return NULL; if (!file_.read(off_, buf, sizeof(buf))) { bool ok = false; int64_t nid = id_ + 1; while (nid <= ulog_->id_) { const std::string& path = ulog_->generate_path(nid); if (kc::File::status(path)) { if (!file_.close()) return NULL; if (!file_.open(path, kc::File::OREADER | kc::File::ONOLOCK, 0)) return NULL; int64_t fsiz; uint64_t fts; if (!read_meta(&fsiz, &fts)) return NULL; id_ = nid; if (!file_.read(off_, buf, sizeof(buf))) return NULL; ok = true; break; } nid++; } if (!ok) return NULL; } int64_t noff = off_ + sizeof(buf); const char* rp = buf; if (*(uint8_t*)rp != BEGMAGIC) return NULL; rp++; uint64_t ts = kc::readfixnum(rp, sizeof(uint64_t)); rp += sizeof(uint64_t); size_t msiz = kc::readfixnum(rp, sizeof(uint32_t)); char* mbuf = new char[msiz+1]; if (!file_.read(noff, mbuf, msiz + 1) || ((uint8_t*)mbuf)[msiz] != ENDMAGIC) { delete[] mbuf; return NULL; } off_ = noff + msiz + 1; *sp = msiz; *tsp = ts; return mbuf; } /** * Read and skip messages until a time stamp. * @param ts the time stamp. */ void read_skip(uint64_t ts) { _assert_(true); while (true) { uint32_t oldid = id_; int64_t oldoff = off_; ulog_->flock_.lock_reader(); size_t msiz; uint64_t mts; char* mbuf = read_impl(&msiz, &mts); ulog_->flock_.unlock(); if (mbuf) { delete[] mbuf; if (mts > ts) { if (id_ == oldid) { off_ = oldoff; } else { off_ = 1 + sizeof(uint64_t) + sizeof(uint64_t); } break; } } else { break; } } } /** The update logger. */ UpdateLogger* ulog_; /** The current time stamp. */ uint64_t ts_; /** The current ID number. */ uint32_t id_; /** The current file. */ kc::File file_; /** The current offset. */ int64_t off_; }; /** * Status of each log file. */ struct FileStatus { std::string path; ///< path uint64_t size; ///< file size uint64_t ts; ///< maximum time stamp }; /** * Default constructor. */ explicit UpdateLogger() : path_(), limsiz_(0), asi_(0), id_(0), file_(), cache_(), csiz_(0), cts_(0), clock_(), flock_(), tslock_(), flusher_(this), tswall_(0), tslogic_(0) { _assert_(true); } /** * Destructor. */ ~UpdateLogger() { _assert_(true); if (!path_.empty()) close(); } /** * Open the logger. * @param path the path of the base directory. * @param limsiz the limit size of each log file. If it is not more than 0, no limit is * specified. If it is kyotocabinet::INT64MIN, the logger is opened as reader. * @param asi the interval of auto synchronization. If it is not more than 0, auto * synchronization is not performed. * @return true on success, or false on failure. */ bool open(const std::string& path, int64_t limsiz = -1, double asi = -1) { _assert_(true); if (!path_.empty()) return false; size_t psiz = path.size(); while (psiz > 0 && path[psiz-1] == kc::File::PATHCHR) { psiz--; } const std::string& cpath = path.substr(0, psiz); kc::File::Status sbuf; if (kc::File::status(cpath, &sbuf)) { if (!sbuf.isdir) return false; } else { if (limsiz == kc::INT64MIN) return false; if (!kc::File::make_directory(cpath)) return false; } kc::DirStream dir; if (!dir.open(cpath)) return false; uint32_t id = 0; std::string name; while (dir.read(&name)) { const char* nstr = name.c_str(); if (check_name(nstr)) { int64_t num = kc::atoi(nstr); if (num > id) id = num; } } path_ = cpath; limsiz_ = limsiz > 0 ? limsiz : kc::INT64MAX; asi_ = asi; id_ = id > 0 ? id : 1; const std::string& tpath = generate_path(id_); if (limsiz == kc::INT64MIN) { if (!file_.open(tpath, kc::File::OREADER | kc::File::ONOLOCK, 0)) { path_.clear(); return false; } } else { if (!file_.open(tpath, kc::File::OWRITER | kc::File::OCREATE, 0)) { path_.clear(); return false; } if (file_.size() < 1 && !write_meta()) { file_.close(); path_.clear(); return false; } if (!validate_meta()) { file_.close(); path_.clear(); return false; } } flusher_.start(); return true; } /** * Close the logger. * @return true on success, or false on failure. */ bool close() { _assert_(true); if (path_.empty()) return false; bool err = false; flusher_.stop(); flusher_.join(); if (flusher_.error()) err = true; if (csiz_ > 0 && !flush()) err = true; if (!file_.close()) err = true; path_.clear(); return !err; } /** * Write a log message. * @param mbuf the pointer to the message region. * @param msiz the size of the message region. * @param ts the time stamp of the message. If it is not more than 0, the current time stamp * is specified. * @return true on success, or false on failure. */ bool write(const char* mbuf, size_t msiz, uint64_t ts = 0) { _assert_(mbuf && msiz <= kc::MEMMAXSIZ); char* nbuf = new char[msiz]; std::memcpy(nbuf, mbuf, msiz); return write_volatile(nbuf, msiz, ts); } /** * Write a log message with a volatile buffer. * @param mbuf the pointer to the message region which is allocated by the new[] operator. * @param msiz the size of the message region. * @param ts the time stamp of the message. If it is not more than 0, the current time stamp * is specified. * @return true on success, or false on failure. * @note the message region is to be deleted inside this object implicitly. */ bool write_volatile(char* mbuf, size_t msiz, uint64_t ts = 0) { _assert_(mbuf && msiz <= kc::MEMMAXSIZ); if (path_.empty()) return false; kc::ScopedSpinLock lock(&clock_); if (ts < 1) ts = clock_impl(); bool err = false; Log log = { mbuf, msiz, ts }; cache_.push_back(log); csiz_ += 2 + sizeof(uint64_t) + sizeof(uint32_t) + msiz; if (ts > cts_) cts_ = ts; if (csiz_ > CACHEMAX && !flush()) err = true; return !err; } /** * Write multiple log messages at once. * @param mvec a string vector of log messages. * @param ts the time stamp of the message. If it is not more than 0, the current time stamp * is specified. * @return true on success, or false on failure. */ bool write_bulk(const std::vector& mvec, uint64_t ts = 0) { if (path_.empty()) return false; kc::ScopedSpinLock lock(&clock_); bool err = false; std::vector::const_iterator it = mvec.begin(); std::vector::const_iterator itend = mvec.end(); while (it != itend) { size_t msiz = it->size(); char* mbuf = new char[msiz]; std::memcpy(mbuf, it->data(), msiz); uint64_t mts = ts > 0 ? ts : clock_impl(); Log log = { mbuf, msiz, mts }; cache_.push_back(log); csiz_ += 2 + sizeof(uint64_t) + sizeof(uint32_t) + msiz; if (mts > cts_) cts_ = mts; ++it; } if (csiz_ > CACHEMAX && !flush()) err = true; return !err; } /** * Get the current clock data for time stamp. * @return the current clock data for time stamp. */ uint64_t clock() { _assert_(true); kc::ScopedSpinLock lock(&tslock_); return clock_impl(); } /** * Get status of each log files. * @param fstvec a vector to store status structures of each log files. */ void list_files(std::vector* fstvec) { _assert_(fstvec); if (path_.empty()) return; fstvec->clear(); std::vector names; kc::File::read_directory(path_, &names); std::sort(names.begin(), names.end()); std::vector::iterator it = names.begin(); std::vector::iterator itend = names.end(); while (it != itend) { const std::string& path = path_ + kc::File::PATHCHR + *it; kc::File file; if (file.open(path, kc::File::OREADER | kc::File::ONOLOCK, 0)) { flock_.lock_reader(); if (file.refresh()) { char hbuf[1+sizeof(uint64_t)+sizeof(uint64_t)]; int64_t psiz = file.size(); if (psiz >= (int64_t)sizeof(hbuf) && file.read(0, hbuf, sizeof(hbuf))) { const char* rp = hbuf; if (*(uint8_t*)(rp++) == METAMAGIC) { int64_t fsiz = kc::readfixnum(rp, sizeof(uint64_t)); rp += sizeof(uint64_t); uint64_t fts = kc::readfixnum(rp, sizeof(uint64_t)); FileStatus fs = { path, fsiz, fts }; fstvec->push_back(fs); } } } flock_.unlock(); file.close(); } ++it; } } /** * Get the current pure clock data for time stamp. * @return the current pure clock data for time stamp. */ static uint64_t clock_pure() { return (uint64_t)(kc::time() * TSWACC) * TSLACC; } private: /** * Log message. */ struct Log { char* mbuf; ///< pointer to the message size_t msiz; ///< size of the message uint64_t ts; ///< time stamp }; /** * Automatic flusher of cacheed logs. */ class AutoFlusher : public kc::Thread { public: AutoFlusher(UpdateLogger* ulog) : ulog_(ulog), alive_(true), error_(false) {} void run() { double asnext = 0; while (alive_ && !error_) { kc::Thread::sleep(FLUSHWAIT); if (ulog_->clock_.lock_try()) { if (ulog_->csiz_ > 0 && !ulog_->flush()) error_ = true; ulog_->clock_.unlock(); } if (ulog_->asi_ > 0 && kc::time() >= asnext) { ulog_->clock_.lock(); ulog_->file_.synchronize(true); ulog_->clock_.unlock(); asnext = kc::time() + ulog_->asi_; } } } void stop() { alive_ = false; } bool error() { return error_; } private: UpdateLogger* ulog_; bool alive_; bool error_; }; /** * Check whether a file name is for update log. * @param name the file name. * @return true for update log, or false if not. */ bool check_name(const char* name) { _assert_(name); const char* pv = std::strchr(name, kc::File::PATHCHR); if (pv) name = pv + 1; const char* bp = name; while (*name != '\0') { if (*name == kc::File::EXTCHR) { if (name - bp != 10) return false; return !std::strcmp(name + 1, KTULPATHEXT); } if (*name < '0' || *name > '9') return false; name++; } return false; } /** * Generate the path of a update log file. * @param id the ID number of the file. * @return the path of the file. */ std::string generate_path(uint32_t id) { _assert_(true); return kc::strprintf("%s%c%010u%c%s", path_.c_str(), kc::File::PATHCHR, id, kc::File::EXTCHR, KTULPATHEXT); } /** * Write meta data. * @return true on success, or false on failure. */ bool write_meta() { _assert_(true); char hbuf[1+sizeof(uint64_t)+sizeof(uint64_t)]; char* wp = hbuf; *(wp++) = METAMAGIC; int64_t psiz = file_.size(); if (psiz < (int64_t)sizeof(hbuf)) psiz = sizeof(hbuf); kc::writefixnum(wp, psiz, sizeof(uint64_t)); wp += sizeof(uint64_t); kc::writefixnum(wp, cts_, sizeof(uint64_t)); return file_.write(0, hbuf, sizeof(hbuf)); } /** * Validate the meta data. * @return true on success, or false on failure. */ bool validate_meta() { _assert_(true); char hbuf[1+sizeof(uint64_t)+sizeof(uint64_t)]; int64_t psiz = file_.size(); if (psiz < (int64_t)sizeof(hbuf) || !file_.read(0, hbuf, sizeof(hbuf))) return false; const char* rp = hbuf; if (*(uint8_t*)(rp++) != METAMAGIC) return false; int64_t fsiz = kc::readfixnum(rp, sizeof(uint64_t)); rp += sizeof(uint64_t); uint64_t fts = kc::readfixnum(rp, sizeof(uint64_t)); if (psiz < fsiz || fsiz < (int64_t)sizeof(hbuf)) return false; if (psiz > fsiz && !file_.truncate(fsiz)) return false; tswall_ = fts / TSLACC + 1; return true; } /** * Flush cached logs into a file. * @return true on success, or false on failure. */ bool flush() { _assert_(true); bool err = false; flock_.lock_writer(); if (file_.size() >= limsiz_) { if (asi_ > 0 && !file_.synchronize(true)) err = true; if (!file_.close()) err = true; id_++; const std::string& tpath = generate_path(id_); if (!file_.open(tpath, kc::File::OWRITER | kc::File::OCREATE | kc::File::OTRUNCATE, 0)) err = true; if (!write_meta()) err = true; } char* cbuf = new char[csiz_]; char* wp = cbuf; Cache::iterator it = cache_.begin(); Cache::iterator itend = cache_.end(); while (it != itend) { Log log = *it; *(wp++) = BEGMAGIC; kc::writefixnum(wp, log.ts, sizeof(uint64_t)); wp += sizeof(uint64_t); kc::writefixnum(wp, log.msiz, sizeof(uint32_t)); wp += sizeof(uint32_t); std::memcpy(wp, log.mbuf, log.msiz); wp += log.msiz; *(wp++) = ENDMAGIC; delete[] log.mbuf; ++it; } if (!file_.append(cbuf, csiz_)) err = true; if (!err && !write_meta()) err = true; delete[] cbuf; cache_.clear(); csiz_ = 0; flock_.unlock(); return !err; } /** * Get the current clock data for time stamp. * @return the current clock data for time stamp. */ uint64_t clock_impl() { _assert_(true); uint64_t ct = kc::time() * TSWACC; if (ct > tswall_) { tswall_ = ct; tslogic_ = 0; } else { tslogic_++; } return tswall_ * TSLACC + tslogic_; } /** Dummy constructor to forbid the use. */ UpdateLogger(const UpdateLogger&); /** Dummy Operator to forbid the use. */ UpdateLogger& operator =(const UpdateLogger&); /** The path of the base directory. */ std::string path_; /** The limit size of each file. */ int64_t limsiz_; /** The inverval of auto synchronization. */ double asi_; /** The ID number of the current file. */ uint32_t id_; /** The current file. */ kc::File file_; /** The cached logs. */ Cache cache_; /** The size of the cache. */ size_t csiz_; /** The last time stamp in the cache. */ uint64_t cts_; /** The cache lock. */ kc::SpinLock clock_; /** The file lock. */ kc::SpinRWLock flock_; /** The time stamp lock. */ kc::SpinLock tslock_; /** The automatic flusher. */ AutoFlusher flusher_; /** The wall clock time stamp. */ uint64_t tswall_; /** The logical time stamp. */ uint64_t tslogic_; }; } // common namespace #endif // duplication check // END OF FILE kyototycoon-0.9.56/ktshlib.cc0000644000175000017500000000456211757471602015206 0ustar mikiomikio/************************************************************************************************* * Shared library * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "ktshlib.h" #include "myconf.h" namespace kyototycoon { // common namespace /** * SharedLibrary internal. */ struct SharedLibraryCore { void* lib; ///< library handle }; /** * Default constructor. */ SharedLibrary::SharedLibrary() { _assert_(true); SharedLibraryCore* core = new SharedLibraryCore; core->lib = NULL; opq_ = core; } /** * Destructor */ SharedLibrary::~SharedLibrary() { _assert_(true); SharedLibraryCore* core = (SharedLibraryCore*)opq_; if (core->lib) close(); delete core; } /** * Open a shared library. */ bool SharedLibrary::open(const char* path) { _assert_(path); SharedLibraryCore* core = (SharedLibraryCore*)opq_; if (core->lib) return false; void* lib = ::dlopen(path, RTLD_LAZY); if (!lib) return false; core->lib = lib; return true; } /** * Close the shared library. */ bool SharedLibrary::close() { _assert_(true); SharedLibraryCore* core = (SharedLibraryCore*)opq_; if (!core->lib) return false; bool err = false; if (::dlclose(core->lib) != 0) err = true; core->lib = NULL; return !err; } /** * Get the pointer to a symbol. */ void* SharedLibrary::symbol(const char* name) { _assert_(name); SharedLibraryCore* core = (SharedLibraryCore*)opq_; if (!core->lib) return NULL; return ::dlsym(core->lib, name); } } // common namespace // END OF FILE kyototycoon-0.9.56/ktsocket.cc0000644000175000017500000013427311757471602015400 0ustar mikiomikio/************************************************************************************************* * Network functions * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include "ktsocket.h" #include "myconf.h" #if defined(_KT_EVENT_EPOLL) extern "C" { #include } #elif defined(_KT_EVENT_KQUEUE) #include #endif namespace kyototycoon { // common namespace /** * Constants for implementation. */ namespace { const int32_t NAMEBUFSIZ = 256; ///< size of the name buffer const int32_t IOBUFSIZ = 4096; ///< size of the IO buffer const double WAITTIME = 0.1; ///< interval to check timeout const int32_t RECVMAXSIZ = 1 << 30; ///< maximum size to receive } /** * Hidden initializer. */ static int32_t _init_func() { struct ::sigaction sa; std::memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); ::sigaction(SIGPIPE, &sa, NULL); ::sigset_t sigmask; sigemptyset(&sigmask); sigaddset(&sigmask, SIGPIPE); ::pthread_sigmask(SIG_BLOCK, &sigmask, NULL); return 0; } int32_t _init_var = _init_func(); /** * Socket internal. */ struct SocketCore { const char* errmsg; ///< error message int32_t fd; ///< file descriptor std::string expr; ///< address expression double timeout; ///< timeout bool aborted; ///< flag for abortion uint32_t evflags; ///< event flags char* buf; ///< receiving buffer const char* rp; ///< reading pointer const char* ep; ///< end pointer }; /** * ServerSocket internal. */ struct ServerSocketCore { const char* errmsg; ///< error message int32_t fd; ///< file descriptor std::string expr; ///< address expression double timeout; ///< timeout bool aborted; ///< flag for abortion uint32_t evflags; ///< event flags }; /** * Poller internal. */ struct PollerCore { #if defined(_KT_EVENT_EPOLL) const char* errmsg; ///< error message int32_t fd; ///< file descriptor std::set events; ///< monitored events std::set hits; ///< notified file descriptors kc::SpinLock elock; ///< lock for events bool aborted; ///< flag for abortion #elif defined(_KT_EVENT_KQUEUE) const char* errmsg; ///< error message int32_t fd; ///< file descriptor std::set events; ///< monitored events std::set hits; ///< notified file descriptors kc::SpinLock elock; ///< lock for events bool aborted; ///< flag for abortion #else const char* errmsg; ///< error message bool open; ///< flag for open std::set events; ///< monitored events std::set hits; ///< notified file descriptors kc::SpinLock elock; ///< lock for events ::pthread_t th; ///< main thread ID bool aborted; ///< flag for abortion #endif }; /** * Dummy signal handler. * @param signum the signal number. */ static void dummysighandler(int signum); /** * Parse an address expression. * @param expr an address expression. * @param buf the pointer to the buffer into which the address is written. * @param portp the pointer to the variable into which the port is assigned. */ static void parseaddr(const char* expr, char* addr, int32_t* portp); /** * Check whether an error code is retriable. * @param ecode the error code. * @return true if the error code is retriable, or false if not. */ static bool checkerrnoretriable(int32_t ecode); /** * Set options of a sockeet. * @param fd the file descriptor of the socket. * @return true on success, or false on failure. */ static bool setsocketoptions(int32_t fd); /** * Clear the error status of a socket. * @param fd the file descriptor of the socket. */ static void clearsocketerror(int32_t fd); /** * Wait an I/O event of a socket. * @param fd the file descriptor of the socket. * @param mode the kind of events: 0 for reading, 1 for writing, 2 for exception. * @param timeout the timeout in seconds. * @return true on success, or false on failure. */ static bool waitsocket(int32_t fd, uint32_t mode, double timeout); /** * Set the error message of a socket. * @param core the inner condition of the socket. * @param msg the error message. */ static void sockseterrmsg(SocketCore* core, const char* msg); /** * Receive one byte from a socket. * @param core the inner condition of the socket. * @return the received byte or -1 on failure. */ static int32_t sockgetc(SocketCore* core); /** * Set the error message of a server. * @param core the inner condition of the server. * @param msg the error message. */ static void servseterrmsg(ServerSocketCore* core, const char* msg); /** * Set the error message of a poller. * @param core the inner condition of the poller. * @param msg the error message. */ static void pollseterrmsg(PollerCore* core, const char* msg); /** * Default constructor. */ Socket::Socket() { _assert_(true); SocketCore* core = new SocketCore; core->errmsg = NULL; core->fd = -1; core->timeout = kc::UINT32MAX; core->aborted = false; core->buf = NULL; core->rp = NULL; core->ep = NULL; core->evflags = 0; opq_ = core; } /** * Destructor. */ Socket::~Socket() { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (core->fd >= 0) close(); delete core; } /** * Get the last happened error information. * @return the last happened error information. */ const char* Socket::error() { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (!core->errmsg) return "no error"; return core->errmsg; } /** * Open a client socket. */ bool Socket::open(const std::string& expr) { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (core->fd > 0) { sockseterrmsg(core, "already opened"); return false; } char addr[NAMEBUFSIZ]; int32_t port; parseaddr(expr.c_str(), addr, &port); if (kc::atoi(addr) < 1 || port < 1 || port > kc::INT16MAX) { sockseterrmsg(core, "invalid address expression"); return false; } struct ::sockaddr_in sain; std::memset(&sain, 0, sizeof(sain)); sain.sin_family = AF_INET; if (::inet_aton(addr, &sain.sin_addr) == 0) { sockseterrmsg(core, "inet_aton failed"); return false; } uint16_t snum = port; sain.sin_port = htons(snum); int32_t fd = ::socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { sockseterrmsg(core, "socket failed"); return false; } if (!setsocketoptions(fd)) { sockseterrmsg(core, "setsocketoptions failed"); ::close(fd); return false; } int32_t flags = ::fcntl(fd, F_GETFL, NULL); if (::fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { sockseterrmsg(core, "fcntl failed"); ::close(fd); return false; } double ct = kc::time(); while (true) { if (::connect(fd, (struct sockaddr*)&sain, sizeof(sain)) == 0 || errno == EISCONN) break; if (!checkerrnoretriable(errno)) { sockseterrmsg(core, "connect failed"); ::close(fd); return false; } if (kc::time() > ct + core->timeout) { sockseterrmsg(core, "operation timed out"); ::close(fd); return false; } if (core->aborted) { sockseterrmsg(core, "operation was aborted"); ::close(fd); return false; } if (!waitsocket(fd, 1, WAITTIME)) { sockseterrmsg(core, "waitsocket failed"); ::close(fd); return false; } } if (::fcntl(fd, F_SETFL, flags) != 0) { sockseterrmsg(core, "fcntl failed"); ::close(fd); return false; } core->fd = fd; core->expr.clear(); kc::strprintf(&core->expr, "%s:%d", addr, port); return true; } /** * Close the socket. */ bool Socket::close(bool grace) { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (core->fd < 1) { sockseterrmsg(core, "not opened"); return false; } bool err = false; int32_t flags = ::fcntl(core->fd, F_GETFL, NULL); if (::fcntl(core->fd, F_SETFL, flags | O_NONBLOCK) != 0) { sockseterrmsg(core, "fcntl failed"); err = true; } if (grace) { double ct = kc::time(); while (true) { int32_t rv = ::shutdown(core->fd, SHUT_RDWR); if (rv == 0 || !checkerrnoretriable(errno)) break; if (kc::time() > ct + core->timeout) { sockseterrmsg(core, "operation timed out"); err = true; break; } if (core->aborted) break; if (!waitsocket(core->fd, 1, WAITTIME)) { sockseterrmsg(core, "waitsocket failed"); break; } } } else { struct ::linger optli; optli.l_onoff = 1; optli.l_linger = 0; ::setsockopt(core->fd, SOL_SOCKET, SO_LINGER, (char*)&optli, sizeof(optli)); } if (::close(core->fd) != 0) { sockseterrmsg(core, "close failed"); err = true; } core->fd = -1; delete[] core->buf; core->buf = NULL; core->rp = NULL; core->ep = NULL; core->aborted = false; return !err; } /** * Send data. */ bool Socket::send(const void* buf, size_t size) { _assert_(buf && size <= kc::MEMMAXSIZ); SocketCore* core = (SocketCore*)opq_; if (core->fd < 1) { sockseterrmsg(core, "not opened"); return false; } const char* rp = (const char*)buf; double ct = kc::time(); while (size > 0) { int32_t wb = ::send(core->fd, rp, size, 0); switch (wb) { case -1: { if (!checkerrnoretriable(errno)) { sockseterrmsg(core, "send failed"); return false; } if (kc::time() > ct + core->timeout) { sockseterrmsg(core, "operation timed out"); return false; } if (core->aborted) { sockseterrmsg(core, "operation was aborted"); return false; } if (!waitsocket(core->fd, 1, WAITTIME)) { sockseterrmsg(core, "waitsocket failed"); return false; } break; } case 0: { break; } default: { rp += wb; size -= wb; break; } } } return true; } /** * Send data. */ bool Socket::send(const std::string& str) { _assert_(true); return send(str.data(), str.size()); } /** * Send formatted data. */ bool Socket::printf(const char* format, ...) { _assert_(format); va_list ap; va_start(ap, format); bool rv = vprintf(format, ap); va_end(ap); return rv; } /** * Send formatted data. */ bool Socket::vprintf(const char* format, va_list ap) { _assert_(format); std::string str; kc::vstrprintf(&str, format, ap); return send(str); } /** * Receive data. */ bool Socket::receive(void* buf, size_t size) { _assert_(buf && size <= kc::MEMMAXSIZ); SocketCore* core = (SocketCore*)opq_; if (core->fd < 1) { sockseterrmsg(core, "not opened"); return false; } if (core->rp + size <= core->ep) { std::memcpy(buf, core->rp, size); core->rp += size; return true; } bool err = false; char* wp = (char*)buf; while (size > 0) { int32_t c = sockgetc(core); if (c < 0) { err = true; break; } *(wp++) = c; size--; } return !err; } /** * Receive one byte. */ int32_t Socket::receive_byte() { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (core->fd < 1) { sockseterrmsg(core, "not opened"); return false; } return sockgetc(core); } /** * Push one byte back. */ bool Socket::undo_receive_byte(int32_t c) { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (core->fd < 1) { sockseterrmsg(core, "not opened"); return false; } if (core->rp <= core->buf) return false; core->rp--; *(unsigned char*)core->rp = c; return true; } /** * Receive one line of characters. */ bool Socket::receive_line(void* buf, size_t max) { _assert_(buf && max > 0 && max <= kc::MEMMAXSIZ); SocketCore* core = (SocketCore*)opq_; if (core->fd < 1) { sockseterrmsg(core, "not opened"); return false; } bool err = false; char* wp = (char*)buf; while (max > 1) { int32_t c = sockgetc(core); if (c == '\n') break; if (c < 0) { err = true; break; } if (c != '\r') { *(wp++) = c; max--; } } *wp = '\0'; return !err; } /** * Get the size of left data in the receiving buffer. */ size_t Socket::left_size() { _assert_(true); SocketCore* core = (SocketCore*)opq_; return core->ep - core->rp; } /** * Abort the current operation. */ bool Socket::abort() { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (core->fd < 1) { sockseterrmsg(core, "not opened"); return false; } core->aborted = true; return true; } /** * Set the timeout of each operation. */ bool Socket::set_timeout(double timeout) { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (core->fd > 0) { sockseterrmsg(core, "already opened"); return false; } core->timeout = timeout > 0 ? timeout : kc::UINT32MAX; if (timeout > kc::UINT32MAX) timeout = kc::UINT32MAX; return true; } /** * Get the expression of the socket. */ const std::string Socket::expression() { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (core->fd < 0) { sockseterrmsg(core, "not opened"); return ""; } return core->expr; } /** * Get the descriptor integer. */ int32_t Socket::descriptor() { _assert_(true); SocketCore* core = (SocketCore*)opq_; if (core->fd < 0) { sockseterrmsg(core, "not opened"); return -1; } return core->fd; } /** * Set event flags. */ void Socket::set_event_flags(uint32_t flags) { _assert_(true); SocketCore* core = (SocketCore*)opq_; core->evflags = flags; } /** * Get the current event flags. */ uint32_t Socket::event_flags() { _assert_(true); SocketCore* core = (SocketCore*)opq_; return core->evflags; } /** * Get the primary name of the local host. */ std::string Socket::get_local_host_name() { _assert_(true); char name[NAMEBUFSIZ]; if (::gethostname(name, sizeof(name) - 1) != 0) return ""; return name; } /** * Get the address of a host. */ std::string Socket::get_host_address(const std::string& name) { _assert_(true); struct ::addrinfo hints, *result; std::memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = 0; hints.ai_protocol = IPPROTO_TCP; hints.ai_canonname = NULL; hints.ai_addr = NULL; hints.ai_next = NULL; if (::getaddrinfo(name.c_str(), NULL, &hints, &result) != 0) return ""; if (!result || result->ai_addr->sa_family != AF_INET) { ::freeaddrinfo(result); return ""; } char addr[NAMEBUFSIZ]; if (::getnameinfo(result->ai_addr, result->ai_addrlen, addr, sizeof(addr) - 1, NULL, 0, NI_NUMERICHOST) != 0) { ::freeaddrinfo(result); return ""; } ::freeaddrinfo(result); return addr; } /** * Default constructor. */ ServerSocket::ServerSocket() { _assert_(true); ServerSocketCore* core = new ServerSocketCore; core->errmsg = NULL; core->fd = -1; core->timeout = kc::UINT32MAX; core->aborted = false; core->evflags = 0; opq_ = core; } /** * Destructor. */ ServerSocket::~ServerSocket() { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; if (core->fd >= 0) close(); delete core; } /** * Get the last happened error information. */ const char* ServerSocket::error() { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; if (!core->errmsg) return "no error"; return core->errmsg; } /** * Open a server socket. */ bool ServerSocket::open(const std::string& expr) { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; if (core->fd > 0) { servseterrmsg(core, "already opened"); return false; } char addr[NAMEBUFSIZ]; int32_t port; parseaddr(expr.c_str(), addr, &port); if (*addr == '\0') { std::sprintf(addr, "0.0.0.0"); } else if (kc::atoi(addr) < 1) { servseterrmsg(core, "invalid address expression"); return false; } if (port < 1 || port > kc::INT16MAX) { servseterrmsg(core, "invalid address expression"); return false; } struct ::sockaddr_in sain; std::memset(&sain, 0, sizeof(sain)); sain.sin_family = AF_INET; if (::inet_aton(addr, &sain.sin_addr) == 0) { servseterrmsg(core, "inet_aton failed"); return false; } uint16_t snum = port; sain.sin_port = htons(snum); int32_t fd = ::socket(PF_INET, SOCK_STREAM, 0); if (fd < 0) { servseterrmsg(core, "socket failed"); return false; } int32_t optint = 1; ::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&optint, sizeof(optint)); if (::bind(fd, (struct sockaddr*)&sain, sizeof(sain)) != 0) { servseterrmsg(core, "bind failed"); ::close(fd); return false; } if (::listen(fd, SOMAXCONN) != 0) { servseterrmsg(core, "listen failed"); ::close(fd); return -1; } int32_t flags = ::fcntl(fd, F_GETFL, NULL); if (::fcntl(fd, F_SETFL, flags | O_NONBLOCK) != 0) { servseterrmsg(core, "fcntl failed"); ::close(fd); return false; } core->fd = fd; core->expr.clear(); kc::strprintf(&core->expr, "%s:%d", addr, port); core->aborted = false; return true; } /** * Close the socket. */ bool ServerSocket::close() { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; if (core->fd < 1) { servseterrmsg(core, "not opened"); return false; } bool err = false; if (::close(core->fd) != 0) { servseterrmsg(core, "close failed"); err = true; } core->fd = -1; core->aborted = false; return !err; } /** * Accept a connection from a client. */ bool ServerSocket::accept(Socket* sock) { _assert_(sock); ServerSocketCore* core = (ServerSocketCore*)opq_; if (core->fd < 1) { servseterrmsg(core, "not opened"); return false; } SocketCore* sockcore = (SocketCore*)sock->opq_; if (sockcore->fd >= 0) { servseterrmsg(core, "socket was already opened"); return false; } double ct = kc::time(); while (true) { struct sockaddr_in sain; std::memset(&sain, 0, sizeof(sain)); sain.sin_family = AF_INET; ::socklen_t slen = sizeof(sain); int32_t fd = ::accept(core->fd, (struct sockaddr*)&sain, &slen); if (fd >= 0) { if (!setsocketoptions(fd)) { servseterrmsg(core, "setsocketoptions failed"); ::close(fd); return false; } char addr[NAMEBUFSIZ]; if (::getnameinfo((struct sockaddr*)&sain, sizeof(sain), addr, sizeof(addr), NULL, 0, NI_NUMERICHOST) != 0) std::sprintf(addr, "0.0.0.0"); int32_t port = ntohs(sain.sin_port); sockcore->fd = fd; sockcore->expr.clear(); kc::strprintf(&sockcore->expr, "%s:%d", addr, port); sockcore->aborted = false; return true; } else { if (!checkerrnoretriable(errno)) { servseterrmsg(core, "accept failed"); break; } if (kc::time() > ct + core->timeout) { servseterrmsg(core, "operation timed out"); break; } if (core->aborted) { servseterrmsg(core, "operation was aborted"); break; } if (!waitsocket(core->fd, 1, WAITTIME)) { servseterrmsg(core, "waitsocket failed"); break; } } } return false; } /** * Abort the current operation. */ bool ServerSocket::abort() { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; if (core->fd < 1) { servseterrmsg(core, "not opened"); return false; } core->aborted = true; return true; } /** * Set the timeout of each operation. */ bool ServerSocket::set_timeout(double timeout) { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; if (core->fd > 0) { servseterrmsg(core, "already opened"); return false; } core->timeout = timeout > 0 ? timeout : kc::UINT32MAX; if (timeout > kc::UINT32MAX) timeout = kc::UINT32MAX; return true; } /** * Get the expression of the socket. */ const std::string ServerSocket::expression() { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; if (core->fd < 0) { servseterrmsg(core, "not opened"); return ""; } return core->expr; } /** * Get the descriptor integer. */ int32_t ServerSocket::descriptor() { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; if (core->fd < 0) { servseterrmsg(core, "not opened"); return -1; } return core->fd; } /** * Set event flags. */ void ServerSocket::set_event_flags(uint32_t flags) { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; core->evflags = flags; } /** * Get the current event flags. */ uint32_t ServerSocket::event_flags() { _assert_(true); ServerSocketCore* core = (ServerSocketCore*)opq_; return core->evflags; } /** * Default constructor. */ Poller::Poller() { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = new PollerCore; core->errmsg = NULL; core->fd = -1; core->aborted = false; opq_ = core; dummysighandler(0); #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = new PollerCore; core->errmsg = NULL; core->fd = -1; core->aborted = false; opq_ = core; dummysighandler(0); #else _assert_(true); PollerCore* core = new PollerCore; core->errmsg = NULL; core->open = false; core->th = ::pthread_self(); core->aborted = false; opq_ = core; dummysighandler(0); #endif } /** * Destructor. */ Poller::~Poller() { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd >= 0) close(); delete core; #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd >= 0) close(); delete core; #else _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->open) close(); delete core; #endif } /** * Get the last happened error information. */ const char* Poller::error() { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (!core->errmsg) return "no error"; return core->errmsg; #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (!core->errmsg) return "no error"; return core->errmsg; #else _assert_(true); PollerCore* core = (PollerCore*)opq_; if (!core->errmsg) return "no error"; return core->errmsg; #endif } /** * Open the poller. */ bool Poller::open() { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd >= 0) { pollseterrmsg(core, "already opened"); return false; } int32_t fd = ::epoll_create(256); if (fd < 0) { pollseterrmsg(core, "epoll_create failed"); return false; } core->fd = fd; return true; #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd >= 0) { pollseterrmsg(core, "already opened"); return false; } int32_t fd = ::kqueue(); if (fd < 0) { pollseterrmsg(core, "kqueue failed"); return false; } core->fd = fd; return true; #else _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->open) { pollseterrmsg(core, "already opened"); return false; } core->open = true; return true; #endif } /** * Close the poller. */ bool Poller::close() { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } bool err = false; if (::close(core->fd) != 0) { pollseterrmsg(core, "close failed"); return false; } core->hits.clear(); core->events.clear(); core->fd = -1; core->aborted = false; return !err; #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } bool err = false; if (::close(core->fd) != 0) { pollseterrmsg(core, "close failed"); return false; } core->hits.clear(); core->events.clear(); core->fd = -1; core->aborted = false; return !err; #else _assert_(true); PollerCore* core = (PollerCore*)opq_; if (!core->open) { pollseterrmsg(core, "not opened"); return false; } core->hits.clear(); core->events.clear(); core->open = false; core->aborted = false; return true; #endif } /** * Add a pollable I/O event to the monitored list. */ bool Poller::deposit(Pollable* event) { #if defined(_KT_EVENT_EPOLL) _assert_(event); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } core->elock.lock(); struct ::epoll_event ev; std::memset(&ev, 0, sizeof(ev)); uint32_t flags = event->event_flags(); ev.events = EPOLLONESHOT; if (flags & Pollable::EVINPUT) ev.events |= EPOLLIN; if (flags & Pollable::EVOUTPUT) ev.events |= EPOLLOUT; if (flags & Pollable::EVEXCEPT) ev.events |= EPOLLHUP | EPOLLPRI; ev.data.ptr = event; if (::epoll_ctl(core->fd, EPOLL_CTL_ADD, event->descriptor(), &ev) != 0) { pollseterrmsg(core, "epoll_ctl failed"); core->elock.unlock(); return false; } core->events.insert(event); core->elock.unlock(); return true; #elif defined(_KT_EVENT_KQUEUE) _assert_(event); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } core->elock.lock(); struct ::kevent ev; std::memset(&ev, 0, sizeof(ev)); uint32_t flags = event->event_flags(); uint32_t filter = 0; if (flags & Pollable::EVINPUT) filter |= EVFILT_READ; if (flags & Pollable::EVOUTPUT) filter |= EVFILT_WRITE; EV_SET(&ev, event->descriptor(), filter, EV_ADD | EV_ONESHOT, 0, 0, event); if (::kevent(core->fd, &ev, 1, NULL, 0, NULL) != 0) { pollseterrmsg(core, "kevent failed a"); core->elock.unlock(); return false; } core->events.insert(event); core->elock.unlock(); return true; #else _assert_(event); PollerCore* core = (PollerCore*)opq_; if (!core->open) { pollseterrmsg(core, "not opened"); return false; } core->elock.lock(); if (!core->events.insert(event).second) { pollseterrmsg(core, "duplicated"); core->elock.unlock(); return false; } core->elock.unlock(); return true; #endif } /** * Remove a pollable I/O from the monitored list. */ bool Poller::withdraw(Pollable* event) { #if defined(_KT_EVENT_EPOLL) _assert_(event); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } bool err = false; core->elock.lock(); core->events.erase(event); if (::epoll_ctl(core->fd, EPOLL_CTL_DEL, event->descriptor(), NULL) != 0) { pollseterrmsg(core, "epoll_ctl failed"); err = true; } core->elock.unlock(); return !err; #elif defined(_KT_EVENT_KQUEUE) _assert_(event); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } bool err = false; core->elock.lock(); core->events.erase(event); core->elock.unlock(); return !err; #else _assert_(event); PollerCore* core = (PollerCore*)opq_; if (!core->open) { pollseterrmsg(core, "not opened"); return false; } return true; #endif } /** * Fetch the next notified I/O event. */ Pollable* Poller::next() { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return NULL; } core->elock.lock(); if (core->hits.empty()) { pollseterrmsg(core, "no event"); core->elock.unlock(); return NULL; } Pollable* item = *core->hits.begin(); core->hits.erase(item); core->elock.unlock(); return item; #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return NULL; } core->elock.lock(); if (core->hits.empty()) { pollseterrmsg(core, "no event"); core->elock.unlock(); return NULL; } Pollable* item = *core->hits.begin(); core->hits.erase(item); core->elock.unlock(); return item; #else _assert_(true); PollerCore* core = (PollerCore*)opq_; if (!core->open) { pollseterrmsg(core, "not opened"); return NULL; } core->elock.lock(); if (core->hits.empty()) { pollseterrmsg(core, "no event"); core->elock.unlock(); return NULL; } Pollable* item = *core->hits.begin(); core->hits.erase(item); core->elock.unlock(); return item; #endif } /** * Enable the next notification of a pollable event. */ bool Poller::undo(Pollable* event) { #if defined(_KT_EVENT_EPOLL) _assert_(event); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } core->elock.lock(); struct ::epoll_event ev; std::memset(&ev, 0, sizeof(ev)); uint32_t flags = event->event_flags(); ev.events = EPOLLONESHOT; if (flags & Pollable::EVINPUT) ev.events |= EPOLLIN; if (flags & Pollable::EVOUTPUT) ev.events |= EPOLLOUT; if (flags & Pollable::EVEXCEPT) ev.events |= EPOLLHUP | EPOLLPRI; ev.data.ptr = event; if (::epoll_ctl(core->fd, EPOLL_CTL_MOD, event->descriptor(), &ev) != 0) { pollseterrmsg(core, "epoll_ctl failed"); core->elock.unlock(); return false; } core->elock.unlock(); return true; #elif defined(_KT_EVENT_KQUEUE) _assert_(event); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } core->elock.lock(); struct ::kevent ev; std::memset(&ev, 0, sizeof(ev)); uint32_t flags = event->event_flags(); uint32_t filter = 0; if (flags & Pollable::EVINPUT) filter |= EVFILT_READ; if (flags & Pollable::EVOUTPUT) filter |= EVFILT_WRITE; EV_SET(&ev, event->descriptor(), filter, EV_ADD | EV_ONESHOT, 0, 0, event); if (::kevent(core->fd, &ev, 1, NULL, 0, NULL) != 0) { pollseterrmsg(core, "kevent failed"); core->elock.unlock(); return false; } core->elock.unlock(); return true; #else _assert_(event); PollerCore* core = (PollerCore*)opq_; if (!core->open) { pollseterrmsg(core, "not opened"); return false; } core->elock.lock(); if (!core->events.insert(event).second) { pollseterrmsg(core, "duplicated"); core->elock.unlock(); return false; } core->elock.unlock(); ::pthread_kill(core->th, SIGUSR2); return true; #endif } /** * Wait one or more notifying events. */ bool Poller::wait(double timeout) { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } core->hits.clear(); double ct = kc::time(); while (true) { struct ::epoll_event events[256]; int32_t tout = timeout > 0 ? timeout * 1000 : -1; int32_t rv = epoll_wait(core->fd, events, sizeof(events) / sizeof(*events), tout); if (rv > 0) { for (int32_t i = 0; i < rv; i++) { Pollable* item = (Pollable*)events[i].data.ptr; uint32_t epflags = events[i].events; uint32_t flags = 0; if (epflags & EPOLLIN) flags |= Pollable::EVINPUT; if (epflags & EPOLLOUT) flags |= Pollable::EVOUTPUT; if ((epflags & EPOLLHUP) || (epflags & EPOLLPRI)) flags |= Pollable::EVEXCEPT; core->elock.lock(); if (core->hits.insert(item).second) { item->set_event_flags(flags); } else { uint32_t oflags = item->event_flags(); item->set_event_flags(oflags | flags); } core->elock.unlock(); } return true; } else if (rv == 0 || checkerrnoretriable(errno)) { if (kc::time() > ct + timeout) { pollseterrmsg(core, "operation timed out"); break; } if (core->aborted) { pollseterrmsg(core, "operation was aborted"); break; } } else { pollseterrmsg(core, "epoll_wait failed"); break; } } return false; #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } if (timeout <= 0) timeout = kc::UINT32MAX; core->hits.clear(); double ct = kc::time(); while (true) { double integ, fract; fract = std::modf(timeout, &integ); struct ::timespec ts; ts.tv_sec = integ; ts.tv_nsec = fract * 999999000; struct ::kevent events[256]; int32_t rv = ::kevent(core->fd, NULL, 0, events, sizeof(events) / sizeof(*events), &ts); if (rv > 0) { for (int32_t i = 0; i < rv; i++) { Pollable* item = (Pollable*)events[i].udata; uint32_t filter = events[i].filter; uint32_t flags = 0; if (filter & EVFILT_READ) flags |= Pollable::EVINPUT; if (filter & EVFILT_WRITE) flags |= Pollable::EVOUTPUT; core->elock.lock(); if (core->hits.insert(item).second) { item->set_event_flags(flags); } else { uint32_t oflags = item->event_flags(); item->set_event_flags(oflags | flags); } core->elock.unlock(); } return true; } else if (rv == 0 || checkerrnoretriable(errno)) { if (kc::time() > ct + timeout) { pollseterrmsg(core, "operation timed out"); break; } if (core->aborted) { pollseterrmsg(core, "operation was aborted"); break; } } else { pollseterrmsg(core, "epoll_wait failed"); break; } } return false; #else _assert_(true); PollerCore* core = (PollerCore*)opq_; if (!core->open) { pollseterrmsg(core, "not opened"); return false; } if (timeout <= 0) timeout = kc::UINT32MAX; core->hits.clear(); ::sigset_t sigmask; sigemptyset(&sigmask); sigaddset(&sigmask, SIGUSR2); ::pthread_sigmask(SIG_BLOCK, &sigmask, NULL); struct ::sigaction sa; std::memset(&sa, 0, sizeof(sa)); sa.sa_flags = 0; sa.sa_handler = dummysighandler; sigemptyset(&sa.sa_mask); ::sigaction(SIGUSR2, &sa, NULL); ::sigset_t empmask; sigemptyset(&empmask); double ct = kc::time(); while (true) { core->elock.lock(); ::fd_set rset, wset, xset; FD_ZERO(&rset); FD_ZERO(&wset); FD_ZERO(&xset); std::map rmap; std::map wmap; std::map xmap; int32_t maxfd = 0; std::set::iterator it = core->events.begin(); std::set::iterator itend = core->events.end(); while (it != itend) { Pollable* item = *it; int32_t fd = item->descriptor(); uint32_t flags = item->event_flags(); if (flags & Pollable::EVINPUT) { FD_SET(fd, &rset); rmap[fd] = item; } if (flags & Pollable::EVOUTPUT) { FD_SET(fd, &wset); wmap[fd] = item; } if (flags & Pollable::EVEXCEPT) { FD_SET(fd, &xset); xmap[fd] = item; } if (fd > maxfd) maxfd = fd; ++it; } core->elock.unlock(); double integ, fract; fract = std::modf(WAITTIME, &integ); struct ::timespec ts; ts.tv_sec = integ; ts.tv_nsec = fract * 999999000; int32_t rv = ::pselect(maxfd + 1, &rset, &wset, &xset, &ts, &empmask); if (rv > 0) { if (!rmap.empty()) { std::map::iterator mit = rmap.begin(); std::map::iterator mitend = rmap.end(); while (mit != mitend) { if (FD_ISSET(mit->first, &rset)) { Pollable* item = mit->second; if (core->hits.insert(item).second) { item->set_event_flags(Pollable::EVINPUT); } else { uint32_t flags = item->event_flags(); item->set_event_flags(flags | Pollable::EVINPUT); } core->elock.lock(); core->events.erase(item); core->elock.unlock(); } ++mit; } } if (!wmap.empty()) { std::map::iterator mit = wmap.begin(); std::map::iterator mitend = wmap.end(); while (mit != mitend) { if (FD_ISSET(mit->first, &wset)) { Pollable* item = mit->second; if (core->hits.insert(item).second) { item->set_event_flags(Pollable::EVOUTPUT); } else { uint32_t flags = item->event_flags(); item->set_event_flags(flags | Pollable::EVOUTPUT); } core->elock.lock(); core->events.erase(item); core->elock.unlock(); } ++mit; } } if (!xmap.empty()) { std::map::iterator mit = xmap.begin(); std::map::iterator mitend = xmap.end(); while (mit != mitend) { if (FD_ISSET(mit->first, &xset)) { Pollable* item = mit->second; if (core->hits.insert(item).second) { item->set_event_flags(Pollable::EVEXCEPT); } else { uint32_t flags = item->event_flags(); item->set_event_flags(flags | Pollable::EVEXCEPT); } core->elock.lock(); core->events.erase(item); core->elock.unlock(); } ++mit; } } return true; } else if (rv == 0 || checkerrnoretriable(errno)) { if (kc::time() > ct + timeout) { pollseterrmsg(core, "operation timed out"); break; } if (core->aborted) { pollseterrmsg(core, "operation was aborted"); break; } } else { pollseterrmsg(core, "pselect failed"); break; } } return false; #endif } /** * Notify all registered events. */ bool Poller::flush() { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } core->elock.lock(); core->hits.clear(); std::set::iterator it = core->events.begin(); std::set::iterator itend = core->events.end(); while (it != itend) { Pollable* item = *it; item->set_event_flags(0); core->hits.insert(item); ++it; } core->elock.unlock(); return true; #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } core->elock.lock(); core->hits.clear(); std::set::iterator it = core->events.begin(); std::set::iterator itend = core->events.end(); while (it != itend) { Pollable* item = *it; item->set_event_flags(0); core->hits.insert(item); ++it; } core->elock.unlock(); return true; #else _assert_(true); PollerCore* core = (PollerCore*)opq_; if (!core->open) { pollseterrmsg(core, "not opened"); return false; } core->elock.lock(); core->hits.clear(); std::set::iterator it = core->events.begin(); std::set::iterator itend = core->events.end(); while (it != itend) { Pollable* item = *it; item->set_event_flags(0); core->hits.insert(item); ++it; } core->elock.unlock(); return true; #endif } /** * Get the number of events to watch. */ int64_t Poller::count() { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return -1; } core->elock.lock(); int64_t count = core->events.size(); core->elock.unlock(); return count; #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return -1; } core->elock.lock(); int64_t count = core->events.size(); core->elock.unlock(); return count; #else _assert_(true); PollerCore* core = (PollerCore*)opq_; if (!core->open) { pollseterrmsg(core, "not opened"); return -1; } core->elock.lock(); int64_t count = core->events.size(); core->elock.unlock(); return count; #endif } /** * Abort the current operation. */ bool Poller::abort() { #if defined(_KT_EVENT_EPOLL) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } core->aborted = true; return true; #elif defined(_KT_EVENT_KQUEUE) _assert_(true); PollerCore* core = (PollerCore*)opq_; if (core->fd < 0) { pollseterrmsg(core, "not opened"); return false; } core->aborted = true; return true; #else _assert_(true); PollerCore* core = (PollerCore*)opq_; if (!core->open) { pollseterrmsg(core, "not opened"); return false; } core->aborted = true; return true; #endif } /** * Dummy signal handler. */ static void dummysighandler(int signum) { _assert_(true); } /** * Parse an address expression. */ static void parseaddr(const char* expr, char* addr, int32_t* portp) { _assert_(expr && addr && portp); while (*expr > '\0' && *expr <= ' ') { expr++; } const char* pv = std::strchr(expr, ':'); if (pv) { size_t len = pv - expr; if (len > NAMEBUFSIZ - 1) len = NAMEBUFSIZ - 1; std::memcpy(addr, expr, len); addr[len] = '\0'; *portp = kc::atoi(pv + 1); } else { size_t len = std::strlen(expr); if (len > NAMEBUFSIZ - 1) len = NAMEBUFSIZ - 1; std::memcpy(addr, expr, len); addr[len] = '\0'; *portp = DEFPORT; } } /** * Check whether an error code is retriable. */ static bool checkerrnoretriable(int32_t ecode) { switch (ecode) { case EINTR: return true; case EAGAIN: return true; case EINPROGRESS: return true; case EALREADY: return true; case ETIMEDOUT: return true; } if (ecode == EWOULDBLOCK) return true; return false; } /** * Set options of a sockeet. */ static bool setsocketoptions(int32_t fd) { _assert_(fd >= 0); bool err = false; double integ; double fract = std::modf(WAITTIME, &integ); struct ::timeval opttv; opttv.tv_sec = (time_t)integ; opttv.tv_usec = (long)(fract * 999999); ::setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, (char*)&opttv, sizeof(opttv)); opttv.tv_sec = (time_t)integ; opttv.tv_usec = (long)(fract * 999999); ::setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&opttv, sizeof(opttv)); int32_t optint = 1; if (::setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (char*)&optint, sizeof(optint)) != 0) err = true; optint = 1; if (::setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&optint, sizeof(optint)) != 0) err = true; return !err; } /** * Clear the error status of a socket. */ static void clearsocketerror(int32_t fd) { _assert_(fd >= 0); int32_t optint = 1; ::socklen_t len = sizeof(optint); ::getsockopt(fd, SOL_SOCKET, SO_ERROR, (char*)&optint, &len); } /** * Wait an I/O event of a socket. */ static bool waitsocket(int32_t fd, uint32_t mode, double timeout) { #if defined(_KT_EVENT_EPOLL) || defined(_KT_EVENT_KQUEUE) _assert_(fd >= 0); struct pollfd pfd; pfd.fd = fd; pfd.events = 0; pfd.revents = 0; switch (mode) { case 0: { pfd.events |= POLLIN; break; } case 1: { pfd.events |= POLLOUT; break; } case 2: { pfd.events |= POLLERR; break; } } int32_t rv = poll(&pfd, 1, timeout * 1000); if (rv >= 0 || checkerrnoretriable(errno)) { clearsocketerror(fd); return true; } clearsocketerror(fd); return false; #else _assert_(fd >= 0); ::fd_set set; FD_ZERO(&set); FD_SET(fd, &set); double integ, fract; fract = std::modf(timeout, &integ); struct ::timespec ts; ts.tv_sec = integ; ts.tv_nsec = fract * 999999000; int32_t rv = -1; switch (mode) { case 0: { rv = ::pselect(fd + 1, &set, NULL, NULL, &ts, NULL); break; } case 1: { rv = ::pselect(fd + 1, NULL, &set, NULL, &ts, NULL); break; } case 2: { rv = ::pselect(fd + 1, NULL, NULL, &set, &ts, NULL); break; } } if (rv >= 0 || checkerrnoretriable(errno)) { clearsocketerror(fd); return true; } clearsocketerror(fd); return false; #endif } /** * Set the error message of a socket. */ static void sockseterrmsg(SocketCore* core, const char* msg) { _assert_(core && msg); core->errmsg = msg; } /** * Receive one byte from a socket. */ static int32_t sockgetc(SocketCore* core) { _assert_(core); if (core->rp < core->ep) return *(unsigned char*)(core->rp++); if (!core->buf) { core->buf = new char[IOBUFSIZ]; core->rp = core->buf; core->ep = core->buf; } double ct = kc::time(); while (true) { int32_t rv = ::recv(core->fd, core->buf, IOBUFSIZ, 0); if (rv > 0) { core->rp = core->buf + 1; core->ep = core->buf + rv; return *(unsigned char*)core->buf; } else if (rv == 0) { sockseterrmsg(core, "end of stream"); return -1; } if (!checkerrnoretriable(errno)) break; if (kc::time() > ct + core->timeout) { sockseterrmsg(core, "operation timed out"); return -1; } if (core->aborted) { sockseterrmsg(core, "operation was aborted"); return -1; } if (!waitsocket(core->fd, 0, WAITTIME)) { sockseterrmsg(core, "waitsocket failed"); return -1; } } sockseterrmsg(core, "recv failed"); return -1; } /** * Set the error message of a server. */ static void servseterrmsg(ServerSocketCore* core, const char* msg) { _assert_(core && msg); core->errmsg = msg; } /** * Set the error message of a poller. */ static void pollseterrmsg(PollerCore* core, const char* msg) { _assert_(core && msg); core->errmsg = msg; } } // common namespace // END OF FILE kyototycoon-0.9.56/kttimedtest.cc0000644000175000017500000026712211757471602016112 0ustar mikiomikio/************************************************************************************************* * The test cases of the timed database * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #include #include "cmdcommon.h" // global variables const char* g_progname; // program name uint32_t g_randseed; // random seed int64_t g_memusage; // memory usage // function prototypes int main(int argc, char** argv); static void usage(); static void dberrprint(kt::TimedDB* db, int32_t line, const char* func); static void dbmetaprint(kt::TimedDB* db, bool verbose); static int32_t runorder(int argc, char** argv); static int32_t runqueue(int argc, char** argv); static int32_t runwicked(int argc, char** argv); static int32_t runtran(int argc, char** argv); static int32_t runmapred(int argc, char** argv); static int32_t runmisc(int argc, char** argv); static int32_t procorder(const char* path, int64_t rnum, int32_t thnum, bool rnd, int32_t mode, bool tran, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv); static int32_t procqueue(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, bool rnd, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv); static int32_t procwicked(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv); static int32_t proctran(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, bool hard, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv); static int32_t procmapred(const char* path, int64_t rnum, bool rnd, bool ru, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv, const char* tmpdir, int64_t dbnum, int64_t clim, int64_t cbnum, int32_t opts); static int32_t procmisc(const char* path); // main routine int main(int argc, char** argv) { g_progname = argv[0]; const char* ebuf = kc::getenv("KTRNDSEED"); g_randseed = ebuf ? (uint32_t)kc::atoi(ebuf) : (uint32_t)(kc::time() * 1000); mysrand(g_randseed); g_memusage = memusage(); kc::setstdiobin(); if (argc < 2) usage(); int32_t rv = 0; if (!std::strcmp(argv[1], "order")) { rv = runorder(argc, argv); } else if (!std::strcmp(argv[1], "queue")) { rv = runqueue(argc, argv); } else if (!std::strcmp(argv[1], "wicked")) { rv = runwicked(argc, argv); } else if (!std::strcmp(argv[1], "tran")) { rv = runtran(argc, argv); } else if (!std::strcmp(argv[1], "mapred")) { rv = runmapred(argc, argv); } else if (!std::strcmp(argv[1], "misc")) { rv = runmisc(argc, argv); } else { usage(); } if (rv != 0) { oprintf("FAILED: KCRNDSEED=%u PID=%ld", g_randseed, (long)kc::getpid()); for (int32_t i = 0; i < argc; i++) { oprintf(" %s", argv[i]); } oprintf("\n\n"); } return rv; } // print the usage and exit static void usage() { eprintf("%s: test cases of the timed database of Kyoto Tycoon\n", g_progname); eprintf("\n"); eprintf("usage:\n"); eprintf(" %s order [-th num] [-rnd] [-set|-get|-getw|-rem|-etc] [-tran]" " [-oat|-oas|-onl|-otl|-onr] [-ulog str] [-ulim num] [-sid num] [-dbid num]" " [-lv] path rnum\n", g_progname); eprintf(" %s queue [-th num] [-it num] [-rnd] [-oat|-oas|-onl|-otl|-onr]" " [-ulog str] [-ulim num] [-sid num] [-dbid num] [-lv] path rnum\n", g_progname); eprintf(" %s wicked [-th num] [-it num] [-oat|-oas|-onl|-otl|-onr]" " [-ulog str] [-ulim num] [-sid num] [-dbid num] [-lv] path rnum\n", g_progname); eprintf(" %s tran [-th num] [-it num] [-hard] [-oat|-oas|-onl|-otl|-onr]" " [-ulog str] [-ulim num] [-sid num] [-dbid num] [-lv] path rnum\n", g_progname); eprintf(" %s mapred [-rnd] [-oat|-oas|-onl|-otl|-onr]" " [-ulog str] [-ulim num] [-sid num] [-dbid num] [-lv] [-tmp str]" " [-dbnum num] [-clim num] [-cbnum num] [-xnl] [-xpm] [-xpr] [-xpf] [-xnc]" " path rnum\n", g_progname); eprintf(" %s misc path\n", g_progname); eprintf("\n"); std::exit(1); } // print the error message of a database static void dberrprint(kt::TimedDB* db, int32_t line, const char* func) { const kc::BasicDB::Error& err = db->error(); oprintf("%s: %d: %s: %s: %d: %s: %s\n", g_progname, line, func, db->path().c_str(), err.code(), err.name(), err.message()); } // print members of a database static void dbmetaprint(kt::TimedDB* db, bool verbose) { if (verbose) { std::map status; if (db->status(&status)) { std::map::iterator it = status.begin(); std::map::iterator itend = status.end(); while (it != itend) { oprintf("%s: %s\n", it->first.c_str(), it->second.c_str()); ++it; } } } else { oprintf("count: %lld\n", (long long)db->count()); oprintf("size: %lld\n", (long long)db->size()); } int64_t musage = memusage(); if (musage > 0) oprintf("memory: %lld\n", (long long)(musage - g_memusage)); } // parse arguments of order command static int32_t runorder(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* rstr = NULL; int32_t thnum = 1; bool rnd = false; int32_t mode = 0; bool tran = false; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool lv = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-rnd")) { rnd = true; } else if (!std::strcmp(argv[i], "-set")) { mode = 's'; } else if (!std::strcmp(argv[i], "-get")) { mode = 'g'; } else if (!std::strcmp(argv[i], "-getw")) { mode = 'w'; } else if (!std::strcmp(argv[i], "-rem")) { mode = 'r'; } else if (!std::strcmp(argv[i], "-etc")) { mode = 'e'; } else if (!std::strcmp(argv[i], "-tran")) { tran = true; } else if (!std::strcmp(argv[i], "-oat")) { oflags |= kc::BasicDB::OAUTOTRAN; } else if (!std::strcmp(argv[i], "-oas")) { oflags |= kc::BasicDB::OAUTOSYNC; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-lv")) { lv = true; } else { usage(); } } else if (!path) { argbrk = false; path = argv[i]; } else if (!rstr) { rstr = argv[i]; } else { usage(); } } if (!path || !rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = procorder(path, rnum, thnum, rnd, mode, tran, oflags, ulogpath, ulim, sid, dbid, lv); return rv; } // parse arguments of queue command static int32_t runqueue(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* rstr = NULL; int32_t thnum = 1; int32_t itnum = 1; bool rnd = false; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool lv = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-it")) { if (++i >= argc) usage(); itnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-rnd")) { rnd = true; } else if (!std::strcmp(argv[i], "-oat")) { oflags |= kc::BasicDB::OAUTOTRAN; } else if (!std::strcmp(argv[i], "-oas")) { oflags |= kc::BasicDB::OAUTOSYNC; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-lv")) { lv = true; } else { usage(); } } else if (!path) { argbrk = false; path = argv[i]; } else if (!rstr) { rstr = argv[i]; } else { usage(); } } if (!path || !rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1 || itnum < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = procqueue(path, rnum, thnum, itnum, rnd, oflags, ulogpath, ulim, sid, dbid, lv); return rv; } // parse arguments of wicked command static int32_t runwicked(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* rstr = NULL; int32_t thnum = 1; int32_t itnum = 1; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool lv = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-it")) { if (++i >= argc) usage(); itnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-oat")) { oflags |= kc::BasicDB::OAUTOTRAN; } else if (!std::strcmp(argv[i], "-oas")) { oflags |= kc::BasicDB::OAUTOSYNC; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-lv")) { lv = true; } else { usage(); } } else if (!path) { argbrk = false; path = argv[i]; } else if (!rstr) { rstr = argv[i]; } else { usage(); } } if (!path || !rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1 || itnum < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = procwicked(path, rnum, thnum, itnum, oflags, ulogpath, ulim, sid, dbid, lv); return rv; } // parse arguments of tran command static int32_t runtran(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* rstr = NULL; int32_t thnum = 1; int32_t itnum = 1; bool hard = false; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool lv = false; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-th")) { if (++i >= argc) usage(); thnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-it")) { if (++i >= argc) usage(); itnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-hard")) { hard = true; } else if (!std::strcmp(argv[i], "-oat")) { oflags |= kc::BasicDB::OAUTOTRAN; } else if (!std::strcmp(argv[i], "-oas")) { oflags |= kc::BasicDB::OAUTOSYNC; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-lv")) { lv = true; } else { usage(); } } else if (!path) { argbrk = false; path = argv[i]; } else if (!rstr) { rstr = argv[i]; } else { usage(); } } if (!path || !rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1 || thnum < 1 || itnum < 1) usage(); if (thnum > THREADMAX) thnum = THREADMAX; int32_t rv = proctran(path, rnum, thnum, itnum, hard, oflags, ulogpath, ulim, sid, dbid, lv); return rv; } // parse arguments of mapred command static int32_t runmapred(int argc, char** argv) { bool argbrk = false; const char* path = NULL; const char* rstr = NULL; bool rnd = false; bool ru = false; int32_t oflags = 0; const char* ulogpath = NULL; int64_t ulim = DEFULIM; uint16_t sid = 0; uint16_t dbid = 0; bool lv = false; const char* tmpdir = ""; int64_t dbnum = -1; int64_t clim = -1; int64_t cbnum = -1; int32_t opts = 0; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else if (!std::strcmp(argv[i], "-rnd")) { rnd = true; } else if (!std::strcmp(argv[i], "-ru")) { ru = true; } else if (!std::strcmp(argv[i], "-oat")) { oflags |= kc::BasicDB::OAUTOTRAN; } else if (!std::strcmp(argv[i], "-oas")) { oflags |= kc::BasicDB::OAUTOSYNC; } else if (!std::strcmp(argv[i], "-onl")) { oflags |= kc::BasicDB::ONOLOCK; } else if (!std::strcmp(argv[i], "-otl")) { oflags |= kc::BasicDB::OTRYLOCK; } else if (!std::strcmp(argv[i], "-onr")) { oflags |= kc::BasicDB::ONOREPAIR; } else if (!std::strcmp(argv[i], "-ulog")) { if (++i >= argc) usage(); ulogpath = argv[i]; } else if (!std::strcmp(argv[i], "-ulim")) { if (++i >= argc) usage(); ulim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-sid")) { if (++i >= argc) usage(); sid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-dbid")) { if (++i >= argc) usage(); dbid = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-lv")) { lv = true; } else if (!std::strcmp(argv[i], "-tmp")) { if (++i >= argc) usage(); tmpdir = argv[i]; } else if (!std::strcmp(argv[i], "-dbnum")) { if (++i >= argc) usage(); dbnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-clim")) { if (++i >= argc) usage(); clim = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-cbnum")) { if (++i >= argc) usage(); cbnum = kc::atoix(argv[i]); } else if (!std::strcmp(argv[i], "-xnl")) { opts |= kt::MapReduce::XNOLOCK; } else if (!std::strcmp(argv[i], "-xpm")) { opts |= kt::MapReduce::XPARAMAP; } else if (!std::strcmp(argv[i], "-xpr")) { opts |= kt::MapReduce::XPARARED; } else if (!std::strcmp(argv[i], "-xpf")) { opts |= kt::MapReduce::XPARAFLS; } else if (!std::strcmp(argv[i], "-xnc")) { opts |= kt::MapReduce::XNOCOMP; } else { usage(); } } else if (!path) { argbrk = true; path = argv[i]; } else if (!rstr) { rstr = argv[i]; } else { usage(); } } if (!path || !rstr) usage(); int64_t rnum = kc::atoix(rstr); if (rnum < 1) usage(); int32_t rv = procmapred(path, rnum, rnd, ru, oflags, ulogpath, ulim, sid, dbid, lv, tmpdir, dbnum, clim, cbnum, opts); return rv; } // parse arguments of misc command static int32_t runmisc(int argc, char** argv) { bool argbrk = false; const char* path = NULL; for (int32_t i = 2; i < argc; i++) { if (!argbrk && argv[i][0] == '-') { if (!std::strcmp(argv[i], "--")) { argbrk = true; } else usage(); } else if (!path) { argbrk = false; path = argv[i]; } else { usage(); } } if (!path) usage(); int32_t rv = procmisc(path); return rv; } // perform order command static int32_t procorder(const char* path, int64_t rnum, int32_t thnum, bool rnd, int32_t mode, bool tran, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv) { oprintf("\n seed=%u path=%s rnum=%lld thnum=%d rnd=%d mode=%d tran=%d" " oflags=%d ulog=%s ulim=%lld sid=%u dbid=%u lv=%d\n\n", g_randseed, path, (long long)rnum, thnum, rnd, mode, tran, oflags, ulogpath ? ulogpath : "", (long long)ulim, sid, dbid, lv); bool err = false; kt::TimedDB db; oprintf("opening the database:\n"); double stime = kc::time(); db.tune_logger(stddblogger(g_progname, &std::cout), lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, __LINE__, "DB::tune_update_trigger"); err = true; } } else { dberrprint(&db, __LINE__, "UpdateLogger::open"); err = true; } } uint32_t omode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE | kc::BasicDB::OTRUNCATE; if (mode == 'r') { omode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE; } else if (mode == 'g' || mode == 'w') { omode = kc::BasicDB::OREADER; } if (!db.open(path, omode | oflags)) { dberrprint(&db, __LINE__, "DB::open"); err = true; } double etime = kc::time(); dbmetaprint(&db, false); oprintf("time: %.3f\n", etime - stime); if (mode == 0 || mode == 's' || mode == 'e') { oprintf("setting records:\n"); stime = kc::time(); class ThreadSet : public kc::Thread { public: void setparams(int32_t id, kt::TimedDB* db, int64_t rnum, int32_t thnum, bool rnd, bool tran) { id_ = id; db_ = db; rnum_ = rnum; thnum_ = thnum; err_ = false; rnd_ = rnd; tran_ = tran; } bool error() { return err_; } void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { if (tran_ && !db_->begin_transaction(false)) { dberrprint(db_, __LINE__, "DB::begin_transaction"); err_ = true; } char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; if (!db_->set(kbuf, ksiz, kbuf, ksiz, xt)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } if (rnd_ && i % 8 == 0) { switch (myrand(8)) { case 0: { if (!db_->set(kbuf, ksiz, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } break; } case 1: { if (!db_->append(kbuf, ksiz, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::append"); err_ = true; } break; } case 2: { if (!db_->remove(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::remove"); err_ = true; } break; } case 3: { kt::TimedDB::Cursor* cur = db_->cursor(); if (cur->jump(kbuf, ksiz)) { switch (myrand(8)) { default: { size_t rsiz; char* rbuf = cur->get_key(&rsiz, myrand(10) == 0); if (rbuf) { delete[] rbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get_key"); err_ = true; } break; } case 1: { size_t rsiz; char* rbuf = cur->get_value(&rsiz, myrand(10) == 0); if (rbuf) { delete[] rbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get_value"); err_ = true; } break; } case 2: { size_t rksiz; const char* rvbuf; size_t rvsiz; char* rkbuf = cur->get(&rksiz, &rvbuf, &rvsiz, NULL, myrand(10) == 0); if (rkbuf) { delete[] rkbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get"); err_ = true; } break; } case 3: { std::string key, value; if (!cur->get(&key, &value, NULL, myrand(10) == 0) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get"); err_ = true; } break; } case 4: { if (myrand(8) == 0 && !cur->remove() && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::remove"); err_ = true; } break; } } } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::jump"); err_ = true; } delete cur; break; } default: { size_t vsiz; char* vbuf = db_->get(kbuf, ksiz, &vsiz); if (vbuf) { delete[] vbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } break; } } } if (tran_ && !db_->end_transaction(true)) { dberrprint(db_, __LINE__, "DB::end_transaction"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } private: int32_t id_; kt::TimedDB* db_; int64_t rnum_; int32_t thnum_; bool err_; bool rnd_; bool tran_; }; ThreadSet threadsets[THREADMAX]; if (thnum < 2) { threadsets[0].setparams(0, &db, rnum, thnum, rnd, tran); threadsets[0].run(); if (threadsets[0].error()) err = true; } else { for (int32_t i = 0; i < thnum; i++) { threadsets[i].setparams(i, &db, rnum, thnum, rnd, tran); threadsets[i].start(); } for (int32_t i = 0; i < thnum; i++) { threadsets[i].join(); if (threadsets[i].error()) err = true; } } etime = kc::time(); dbmetaprint(&db, mode == 's'); oprintf("time: %.3f\n", etime - stime); } if (mode == 'e') { oprintf("adding records:\n"); stime = kc::time(); class ThreadAdd : public kc::Thread { public: void setparams(int32_t id, kt::TimedDB* db, int64_t rnum, int32_t thnum, bool rnd, bool tran) { id_ = id; db_ = db; rnum_ = rnum; thnum_ = thnum; err_ = false; rnd_ = rnd; tran_ = tran; } bool error() { return err_; } void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { if (tran_ && !db_->begin_transaction(false)) { dberrprint(db_, __LINE__, "DB::begin_transaction"); err_ = true; } char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; if (!db_->add(kbuf, ksiz, kbuf, ksiz, xt) && db_->error() != kc::BasicDB::Error::DUPREC) { dberrprint(db_, __LINE__, "DB::add"); err_ = true; } if (tran_ && !db_->end_transaction(true)) { dberrprint(db_, __LINE__, "DB::end_transaction"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } private: int32_t id_; kt::TimedDB* db_; int64_t rnum_; int32_t thnum_; bool err_; bool rnd_; bool tran_; }; ThreadAdd threadadds[THREADMAX]; if (thnum < 2) { threadadds[0].setparams(0, &db, rnum, thnum, rnd, tran); threadadds[0].run(); if (threadadds[0].error()) err = true; } else { for (int32_t i = 0; i < thnum; i++) { threadadds[i].setparams(i, &db, rnum, thnum, rnd, tran); threadadds[i].start(); } for (int32_t i = 0; i < thnum; i++) { threadadds[i].join(); if (threadadds[i].error()) err = true; } } etime = kc::time(); dbmetaprint(&db, false); oprintf("time: %.3f\n", etime - stime); } if (mode == 'e') { oprintf("appending records:\n"); stime = kc::time(); class ThreadAppend : public kc::Thread { public: void setparams(int32_t id, kt::TimedDB* db, int64_t rnum, int32_t thnum, bool rnd, bool tran) { id_ = id; db_ = db; rnum_ = rnum; thnum_ = thnum; err_ = false; rnd_ = rnd; tran_ = tran; } bool error() { return err_; } void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { if (tran_ && !db_->begin_transaction(false)) { dberrprint(db_, __LINE__, "DB::begin_transaction"); err_ = true; } char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); int64_t xt = rnd_ ? myrand(600) + 1 : kc::INT64MAX; if (!db_->append(kbuf, ksiz, kbuf, ksiz, xt)) { dberrprint(db_, __LINE__, "DB::append"); err_ = true; } if (tran_ && !db_->end_transaction(true)) { dberrprint(db_, __LINE__, "DB::end_transaction"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } private: int32_t id_; kt::TimedDB* db_; int64_t rnum_; int32_t thnum_; bool err_; bool rnd_; bool tran_; }; ThreadAppend threadappends[THREADMAX]; if (thnum < 2) { threadappends[0].setparams(0, &db, rnum, thnum, rnd, tran); threadappends[0].run(); if (threadappends[0].error()) err = true; } else { for (int32_t i = 0; i < thnum; i++) { threadappends[i].setparams(i, &db, rnum, thnum, rnd, tran); threadappends[i].start(); } for (int32_t i = 0; i < thnum; i++) { threadappends[i].join(); if (threadappends[i].error()) err = true; } } etime = kc::time(); dbmetaprint(&db, false); oprintf("time: %.3f\n", etime - stime); } if (mode == 0 || mode == 'g' || mode == 'e') { oprintf("getting records:\n"); stime = kc::time(); class ThreadGet : public kc::Thread { public: void setparams(int32_t id, kt::TimedDB* db, int64_t rnum, int32_t thnum, bool rnd, bool tran) { id_ = id; db_ = db; rnum_ = rnum; thnum_ = thnum; err_ = false; rnd_ = rnd; tran_ = tran; } bool error() { return err_; } void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { if (tran_ && !db_->begin_transaction(false)) { dberrprint(db_, __LINE__, "DB::begin_transaction"); err_ = true; } char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); size_t vsiz; char* vbuf = db_->get(kbuf, ksiz, &vsiz); if (vbuf) { if (vsiz < ksiz || std::memcmp(vbuf, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } delete[] vbuf; } else if (!rnd_ || db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } if (rnd_ && i % 8 == 0) { switch (myrand(8)) { case 0: { if (!db_->set(kbuf, ksiz, kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOPERM) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } break; } case 1: { if (!db_->append(kbuf, ksiz, kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOPERM) { dberrprint(db_, __LINE__, "DB::append"); err_ = true; } break; } case 2: { if (!db_->remove(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOPERM && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::remove"); err_ = true; } break; } case 3: { kt::TimedDB::Cursor* cur = db_->cursor(); if (cur->jump(kbuf, ksiz)) { switch (myrand(8)) { default: { size_t rsiz; char* rbuf = cur->get_key(&rsiz, myrand(10) == 0); if (rbuf) { delete[] rbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get_key"); err_ = true; } break; } case 1: { size_t rsiz; char* rbuf = cur->get_value(&rsiz, myrand(10) == 0); if (rbuf) { delete[] rbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get_value"); err_ = true; } break; } case 2: { size_t rksiz; const char* rvbuf; size_t rvsiz; char* rkbuf = cur->get(&rksiz, &rvbuf, &rvsiz, NULL, myrand(10) == 0); if (rkbuf) { delete[] rkbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get"); err_ = true; } break; } case 3: { std::string key, value; if (!cur->get(&key, &value, NULL, myrand(10) == 0) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get"); err_ = true; } break; } case 4: { if (myrand(8) == 0 && !cur->remove() && db_->error() != kc::BasicDB::Error::NOPERM && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::remove"); err_ = true; } break; } } } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::jump"); err_ = true; } delete cur; break; } default: { size_t vsiz; char* vbuf = db_->get(kbuf, ksiz, &vsiz); if (vbuf) { delete[] vbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } break; } } } if (tran_ && !db_->end_transaction(true)) { dberrprint(db_, __LINE__, "DB::end_transaction"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } private: int32_t id_; kt::TimedDB* db_; int64_t rnum_; int32_t thnum_; bool err_; bool rnd_; bool tran_; }; ThreadGet threadgets[THREADMAX]; if (thnum < 2) { threadgets[0].setparams(0, &db, rnum, thnum, rnd, tran); threadgets[0].run(); if (threadgets[0].error()) err = true; } else { for (int32_t i = 0; i < thnum; i++) { threadgets[i].setparams(i, &db, rnum, thnum, rnd, tran); threadgets[i].start(); } for (int32_t i = 0; i < thnum; i++) { threadgets[i].join(); if (threadgets[i].error()) err = true; } } etime = kc::time(); dbmetaprint(&db, mode == 'g'); oprintf("time: %.3f\n", etime - stime); } if (mode == 'w' || mode == 'e') { oprintf("getting records with a buffer:\n"); stime = kc::time(); class ThreadGetBuffer : public kc::Thread { public: void setparams(int32_t id, kt::TimedDB* db, int64_t rnum, int32_t thnum, bool rnd, bool tran) { id_ = id; db_ = db; rnum_ = rnum; thnum_ = thnum; err_ = false; rnd_ = rnd; tran_ = tran; } bool error() { return err_; } void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { if (tran_ && !db_->begin_transaction(false)) { dberrprint(db_, __LINE__, "DB::begin_transaction"); err_ = true; } char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); char vbuf[RECBUFSIZ]; int32_t vsiz = db_->get(kbuf, ksiz, vbuf, sizeof(vbuf)); if (vsiz >= 0) { if (vsiz < (int32_t)ksiz || std::memcmp(vbuf, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } } else if (!rnd_ || db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } if (tran_ && !db_->end_transaction(true)) { dberrprint(db_, __LINE__, "DB::end_transaction"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } private: int32_t id_; kt::TimedDB* db_; int64_t rnum_; int32_t thnum_; bool err_; bool rnd_; bool tran_; }; ThreadGetBuffer threadgetbuffers[THREADMAX]; if (thnum < 2) { threadgetbuffers[0].setparams(0, &db, rnum, thnum, rnd, tran); threadgetbuffers[0].run(); if (threadgetbuffers[0].error()) err = true; } else { for (int32_t i = 0; i < thnum; i++) { threadgetbuffers[i].setparams(i, &db, rnum, thnum, rnd, tran); threadgetbuffers[i].start(); } for (int32_t i = 0; i < thnum; i++) { threadgetbuffers[i].join(); if (threadgetbuffers[i].error()) err = true; } } etime = kc::time(); dbmetaprint(&db, mode == 'w'); oprintf("time: %.3f\n", etime - stime); } if (mode == 'e') { oprintf("traversing the database by the inner iterator:\n"); stime = kc::time(); int64_t cnt = db.count(); class VisitorIterator : public kt::TimedDB::Visitor { public: explicit VisitorIterator(int64_t rnum, bool rnd) : rnum_(rnum), rnd_(rnd), cnt_(0), rbuf_() { std::memset(rbuf_, '+', sizeof(rbuf_)); } int64_t cnt() { return cnt_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { cnt_++; const char* rv = NOP; switch (rnd_ ? myrand(7) : cnt_ % 7) { case 0: { rv = rbuf_; *sp = rnd_ ? myrand(sizeof(rbuf_)) : sizeof(rbuf_) / (cnt_ % 5 + 1); *xtp = rnd_ ? myrand(100) + 1 : kc::INT64MAX; break; } case 1: { rv = REMOVE; break; } } if (rnum_ > 250 && cnt_ % (rnum_ / 250) == 0) { oputchar('.'); if (cnt_ == rnum_ || cnt_ % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt_); } return rv; } int64_t rnum_; bool rnd_; int64_t cnt_; char rbuf_[RECBUFSIZ]; } visitoriterator(rnum, rnd); if (tran && !db.begin_transaction(false)) { dberrprint(&db, __LINE__, "DB::begin_transaction"); err = true; } if (!db.iterate(&visitoriterator, true)) { dberrprint(&db, __LINE__, "DB::iterate"); err = true; } if (rnd) oprintf(" (end)\n"); if (tran && !db.end_transaction(true)) { dberrprint(&db, __LINE__, "DB::end_transaction"); err = true; } if (!rnd && visitoriterator.cnt() != cnt) { dberrprint(&db, __LINE__, "DB::iterate"); err = true; } etime = kc::time(); dbmetaprint(&db, false); oprintf("time: %.3f\n", etime - stime); } if (mode == 'e') { oprintf("traversing the database by the outer cursor:\n"); stime = kc::time(); int64_t cnt = db.count(); class VisitorCursor : public kt::TimedDB::Visitor { public: explicit VisitorCursor(int64_t rnum, bool rnd) : rnum_(rnum), rnd_(rnd), cnt_(0), rbuf_() { std::memset(rbuf_, '-', sizeof(rbuf_)); } int64_t cnt() { return cnt_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { cnt_++; const char* rv = NOP; switch (rnd_ ? myrand(7) : cnt_ % 7) { case 0: { rv = rbuf_; *sp = rnd_ ? myrand(sizeof(rbuf_)) : sizeof(rbuf_) / (cnt_ % 5 + 1); *xtp = rnd_ ? myrand(100) + 1 : kc::INT64MAX; break; } case 1: { rv = REMOVE; break; } } if (rnum_ > 250 && cnt_ % (rnum_ / 250) == 0) { oputchar('.'); if (cnt_ == rnum_ || cnt_ % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt_); } return rv; } int64_t rnum_; bool rnd_; int64_t cnt_; char rbuf_[RECBUFSIZ]; } visitorcursor(rnum, rnd); if (tran && !db.begin_transaction(false)) { dberrprint(&db, __LINE__, "DB::begin_transaction"); err = true; } kt::TimedDB::Cursor cur(&db); if (!cur.jump() && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, __LINE__, "Cursor::jump"); err = true; } kt::TimedDB::Cursor* paracur = db.cursor(); int64_t range = rnum * thnum; while (!err && cur.accept(&visitorcursor, true, !rnd)) { if (rnd) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)myrand(range)); switch (myrand(3)) { case 0: { if (!db.remove(kbuf, ksiz) && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, __LINE__, "DB::remove"); err = true; } break; } case 1: { if (!paracur->jump(kbuf, ksiz) && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, __LINE__, "Cursor::jump"); err = true; } break; } default: { if (!cur.step() && db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, __LINE__, "Cursor::step"); err = true; } break; } } } } if (db.error() != kc::BasicDB::Error::NOREC) { dberrprint(&db, __LINE__, "Cursor::accept"); err = true; } oprintf(" (end)\n"); delete paracur; if (tran && !db.end_transaction(true)) { dberrprint(&db, __LINE__, "DB::end_transaction"); err = true; } if (!rnd && visitorcursor.cnt() != cnt) { dberrprint(&db, __LINE__, "Cursor::accept"); err = true; } etime = kc::time(); dbmetaprint(&db, false); oprintf("time: %.3f\n", etime - stime); } if (mode == 'e') { oprintf("synchronizing the database:\n"); stime = kc::time(); if (!db.synchronize(false, NULL)) { dberrprint(&db, __LINE__, "DB::synchronize"); err = true; } class SyncProcessor : public kc::BasicDB::FileProcessor { public: explicit SyncProcessor(int64_t size) : size_(size) {} private: bool process(const std::string& path, int64_t count, int64_t size) { if (size != size_) return false; return true; } int64_t rnum_; bool rnd_; int64_t size_; int64_t msiz_; } syncprocessor(db.size()); if (!db.synchronize(false, &syncprocessor)) { dberrprint(&db, __LINE__, "DB::synchronize"); err = true; } etime = kc::time(); dbmetaprint(&db, false); oprintf("time: %.3f\n", etime - stime); } if (mode == 'e' && db.size() < (256LL << 20)) { oprintf("dumping records into snapshot:\n"); stime = kc::time(); std::ostringstream ostrm; if (!db.dump_snapshot(&ostrm)) { dberrprint(&db, __LINE__, "DB::dump_snapshot"); err = true; } etime = kc::time(); dbmetaprint(&db, false); oprintf("time: %.3f\n", etime - stime); oprintf("loading records from snapshot:\n"); stime = kc::time(); int64_t cnt = db.count(); if (rnd && myrand(2) == 0 && !db.clear()) { dberrprint(&db, __LINE__, "DB::clear"); err = true; } const std::string& str = ostrm.str(); std::istringstream istrm(str); if (!db.load_snapshot(&istrm) || db.count() != cnt) { dberrprint(&db, __LINE__, "DB::load_snapshot"); err = true; } etime = kc::time(); dbmetaprint(&db, false); oprintf("time: %.3f\n", etime - stime); } if (mode == 0 || mode == 'r' || mode == 'e') { oprintf("removing records:\n"); stime = kc::time(); class ThreadRemove : public kc::Thread { public: void setparams(int32_t id, kt::TimedDB* db, int64_t rnum, int32_t thnum, bool rnd, int32_t mode, bool tran) { id_ = id; db_ = db; rnum_ = rnum; thnum_ = thnum; err_ = false; rnd_ = rnd; mode_ = mode; tran_ = tran; } bool error() { return err_; } void run() { int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { if (tran_ && !db_->begin_transaction(false)) { dberrprint(db_, __LINE__, "DB::begin_transaction"); err_ = true; } char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)(rnd_ ? myrand(range) + 1 : base + i)); if (!db_->remove(kbuf, ksiz) && ((!rnd_ && mode_ != 'e') || db_->error() != kc::BasicDB::Error::NOREC)) { dberrprint(db_, __LINE__, "DB::remove"); err_ = true; } if (rnd_ && i % 8 == 0) { switch (myrand(8)) { case 0: { if (!db_->set(kbuf, ksiz, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } break; } case 1: { if (!db_->append(kbuf, ksiz, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::append"); err_ = true; } break; } case 2: { if (!db_->remove(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::remove"); err_ = true; } break; } case 3: { kt::TimedDB::Cursor* cur = db_->cursor(); if (cur->jump(kbuf, ksiz)) { switch (myrand(8)) { default: { size_t rsiz; char* rbuf = cur->get_key(&rsiz, myrand(10) == 0); if (rbuf) { delete[] rbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get_key"); err_ = true; } break; } case 1: { size_t rsiz; char* rbuf = cur->get_value(&rsiz, myrand(10) == 0); if (rbuf) { delete[] rbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get_value"); err_ = true; } break; } case 2: { size_t rksiz; const char* rvbuf; size_t rvsiz; char* rkbuf = cur->get(&rksiz, &rvbuf, &rvsiz, NULL, myrand(10) == 0); if (rkbuf) { delete[] rkbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get"); err_ = true; } break; } case 3: { std::string key, value; if (!cur->get(&key, &value, NULL, myrand(10) == 0) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::get"); err_ = true; } break; } case 4: { if (myrand(8) == 0 && !cur->remove() && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::remove"); err_ = true; } break; } } } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::jump"); err_ = true; } delete cur; break; } default: { size_t vsiz; char* vbuf = db_->get(kbuf, ksiz, &vsiz); if (vbuf) { delete[] vbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } break; } } } if (tran_ && !db_->end_transaction(true)) { dberrprint(db_, __LINE__, "DB::end_transaction"); err_ = true; } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } } private: int32_t id_; kt::TimedDB* db_; int64_t rnum_; int32_t thnum_; bool err_; bool rnd_; int32_t mode_; bool tran_; }; ThreadRemove threadremoves[THREADMAX]; if (thnum < 2) { threadremoves[0].setparams(0, &db, rnum, thnum, rnd, mode, tran); threadremoves[0].run(); if (threadremoves[0].error()) err = true; } else { for (int32_t i = 0; i < thnum; i++) { threadremoves[i].setparams(i, &db, rnum, thnum, rnd, mode, tran); threadremoves[i].start(); } for (int32_t i = 0; i < thnum; i++) { threadremoves[i].join(); if (threadremoves[i].error()) err = true; } } etime = kc::time(); dbmetaprint(&db, mode == 'r' || mode == 'e'); oprintf("time: %.3f\n", etime - stime); } oprintf("closing the database:\n"); stime = kc::time(); if (!db.close()) { dberrprint(&db, __LINE__, "DB::close"); err = true; } if (ulogpath && !ulog.close()) { dberrprint(&db, __LINE__, "UpdateLogger::close"); err = true; } etime = kc::time(); oprintf("time: %.3f\n", etime - stime); oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform queue command static int32_t procqueue(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, bool rnd, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv) { oprintf("\n seed=%u path=%s rnum=%lld thnum=%d itnum=%d rnd=%d" " oflags=%d ulog=%s ulim=%lld sid=%u dbid=%u lv=%d\n\n", g_randseed, path, (long long)rnum, thnum, itnum, rnd, oflags, ulogpath ? ulogpath : "", (long long)ulim, sid, dbid, lv); bool err = false; kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cout), lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, __LINE__, "DB::tune_update_trigger"); err = true; } } else { dberrprint(&db, __LINE__, "UpdateLogger::open"); err = true; } } for (int32_t itcnt = 1; itcnt <= itnum; itcnt++) { if (itnum > 1) oprintf("iteration %d:\n", itcnt); double stime = kc::time(); uint32_t omode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE; if (itcnt == 1) omode |= kc::BasicDB::OTRUNCATE; if (!db.open(path, omode)) { dberrprint(&db, __LINE__, "DB::open"); err = true; } class ThreadQueue : public kc::Thread { public: void setparams(int32_t id, kt::TimedDB* db, int64_t rnum, int32_t thnum, bool rnd, int64_t width) { id_ = id; db_ = db; rnum_ = rnum; thnum_ = thnum; rnd_ = rnd; width_ = width; err_ = false; } bool error() { return err_; } void run() { kt::TimedDB::Cursor* cur = db_->cursor(); int64_t base = id_ * rnum_; int64_t range = rnum_ * thnum_; for (int64_t i = 1; !err_ && i <= rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%010lld", (long long)(base + i)); if (!db_->set(kbuf, ksiz, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } if (rnd_) { if (myrand(width_ / 2) == 0) { if (!cur->jump() && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::jump"); err_ = true; } ksiz = std::sprintf(kbuf, "%010lld", (long long)myrand(range) + 1); switch (myrand(10)) { case 0: { if (!db_->set(kbuf, ksiz, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } break; } case 1: { if (!db_->append(kbuf, ksiz, kbuf, ksiz)) { dberrprint(db_, __LINE__, "DB::append"); err_ = true; } break; } case 2: { if (!db_->remove(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::remove"); err_ = true; } break; } } int64_t dnum = myrand(width_) + 2; for (int64_t j = 0; j < dnum; j++) { if (!cur->remove() && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::remove"); err_ = true; } } } } else { if (i > width_) { if (!cur->jump() && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::jump"); err_ = true; } if (!cur->remove() && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::remove"); err_ = true; } } } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } delete cur; } private: int32_t id_; kt::TimedDB* db_; int64_t rnum_; int32_t thnum_; bool rnd_; int64_t width_; bool err_; }; int64_t width = rnum / 10; ThreadQueue threads[THREADMAX]; if (thnum < 2) { threads[0].setparams(0, &db, rnum, thnum, rnd, width); threads[0].run(); if (threads[0].error()) err = true; } else { for (int32_t i = 0; i < thnum; i++) { threads[i].setparams(i, &db, rnum, thnum, rnd, width); threads[i].start(); } for (int32_t i = 0; i < thnum; i++) { threads[i].join(); if (threads[i].error()) err = true; } } int64_t count = db.count(); if (!rnd && itcnt == 1 && count != width * thnum) { dberrprint(&db, __LINE__, "DB::count"); err = true; } if ((rnd ? (myrand(2) == 0) : itcnt == itnum) && count > 0) { kt::TimedDB::Cursor* cur = db.cursor(); if (!cur->jump()) { dberrprint(&db, __LINE__, "Cursor::jump"); err = true; } for (int64_t i = 1; i <= count; i++) { if (!cur->remove()) { dberrprint(&db, __LINE__, "Cursor::jump"); err = true; } if (rnum > 250 && i % (rnum / 250) == 0) { oputchar('.'); if (i == rnum || i % (rnum / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } if (rnd) oprintf(" (end)\n"); delete cur; if (db.count() != 0) { dberrprint(&db, __LINE__, "DB::count"); err = true; } } dbmetaprint(&db, itcnt == itnum); if (!db.close()) { dberrprint(&db, __LINE__, "DB::close"); err = true; } oprintf("time: %.3f\n", kc::time() - stime); } if (ulogpath && !ulog.close()) { dberrprint(&db, __LINE__, "UpdateLogger::close"); err = true; } oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform wicked command static int32_t procwicked(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv) { oprintf("\n seed=%u path=%s rnum=%lld thnum=%d itnum=%d" " oflags=%d ulog=%s ulim=%lld sid=%u dbid=%u lv=%d\n\n", g_randseed, path, (long long)rnum, thnum, itnum, oflags, ulogpath ? ulogpath : "", (long long)ulim, sid, dbid, lv); bool err = false; kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cout), lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, __LINE__, "DB::tune_update_trigger"); err = true; } } else { dberrprint(&db, __LINE__, "UpdateLogger::open"); err = true; } } for (int32_t itcnt = 1; itcnt <= itnum; itcnt++) { if (itnum > 1) oprintf("iteration %d:\n", itcnt); double stime = kc::time(); uint32_t omode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE; if (itcnt == 1) omode |= kc::BasicDB::OTRUNCATE; if (!db.open(path, omode | oflags)) { dberrprint(&db, __LINE__, "DB::open"); err = true; } class ThreadWicked : public kc::Thread { public: void setparams(int32_t id, kt::TimedDB* db, int64_t rnum, int32_t thnum, const char* lbuf) { id_ = id; db_ = db; rnum_ = rnum; thnum_ = thnum; lbuf_ = lbuf; err_ = false; } bool error() { return err_; } void run() { kt::TimedDB::Cursor* cur = db_->cursor(); int64_t range = rnum_ * thnum_ / 2; for (int64_t i = 1; !err_ && i <= rnum_; i++) { bool tran = myrand(100) == 0; if (tran) { if (myrand(2) == 0) { if (!db_->begin_transaction(myrand(rnum_) == 0)) { if (db_->error() != kc::BasicDB::Error::NOIMPL) { dberrprint(db_, __LINE__, "DB::begin_transaction"); tran = false; err_ = true; } tran = false; } } else { if (!db_->begin_transaction_try(myrand(rnum_) == 0)) { if (db_->error() != kc::BasicDB::Error::LOGIC && db_->error() != kc::BasicDB::Error::NOIMPL) { dberrprint(db_, __LINE__, "DB::begin_transaction_try"); err_ = true; } tran = false; } } } char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1)); if (myrand(1000) == 0) { ksiz = myrand(RECBUFSIZ) + 1; if (myrand(2) == 0) { for (size_t j = 0; j < ksiz; j++) { kbuf[j] = j; } } else { for (size_t j = 0; j < ksiz; j++) { kbuf[j] = myrand(256); } } } const char* vbuf = kbuf; size_t vsiz = ksiz; if (myrand(10) == 0) { vbuf = lbuf_; vsiz = myrand(RECBUFSIZL) / (myrand(5) + 1); } int64_t xt = myrand(600); do { switch (myrand(10)) { case 0: { if (!db_->set(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } break; } case 1: { if (!db_->add(kbuf, ksiz, vbuf, vsiz, xt) && db_->error() != kc::BasicDB::Error::DUPREC) { dberrprint(db_, __LINE__, "DB::add"); err_ = true; } break; } case 2: { if (!db_->replace(kbuf, ksiz, vbuf, vsiz, xt) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::replace"); err_ = true; } break; } case 3: { if (!db_->append(kbuf, ksiz, vbuf, vsiz, xt)) { dberrprint(db_, __LINE__, "DB::append"); err_ = true; } break; } case 4: { if (myrand(2) == 0) { int64_t num = myrand(rnum_); int64_t orig = myrand(10) == 0 ? kc::INT64MIN : myrand(rnum_); if (myrand(10) == 0) orig = orig == kc::INT64MIN ? kc::INT64MAX : -orig; if (db_->increment(kbuf, ksiz, num, orig, xt) == kc::INT64MIN && db_->error() != kc::BasicDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::increment"); err_ = true; } } else { double num = myrand(rnum_ * 10) / (myrand(rnum_) + 1.0); double orig = myrand(10) == 0 ? -kc::inf() : myrand(rnum_); if (myrand(10) == 0) orig = -orig; if (kc::chknan(db_->increment_double(kbuf, ksiz, num, orig, xt)) && db_->error() != kc::BasicDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::increment_double"); err_ = true; } } break; } case 5: { if (!db_->cas(kbuf, ksiz, kbuf, ksiz, vbuf, vsiz, xt) && db_->error() != kc::BasicDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::cas"); err_ = true; } break; } case 6: { if (!db_->remove(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::remove"); err_ = true; } break; } case 7: { if (myrand(2) == 0) { int32_t vsiz = db_->check(kbuf, ksiz); if (vsiz < 0 && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::check"); err_ = true; } } else { size_t rsiz; char* rbuf = db_->seize(kbuf, ksiz, &rsiz); if (rbuf) { delete[] rbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::seize"); err_ = true; } } break; } case 8: { if (myrand(10) == 0) { if (myrand(4) == 0) { if (!cur->jump_back(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOIMPL && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::jump_back"); err_ = true; } } else { if (!cur->jump(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::jump"); err_ = true; } } } else { class VisitorImpl : public kt::TimedDB::Visitor { public: explicit VisitorImpl(const char* lbuf) : lbuf_(lbuf) {} private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { const char* rv = NOP; switch (myrand(3)) { case 0: { rv = lbuf_; *sp = myrand(RECBUFSIZL) / (myrand(5) + 1); *xtp = myrand(100) + 1; break; } case 1: { rv = REMOVE; break; } } return rv; } const char* lbuf_; } visitor(lbuf_); if (!cur->accept(&visitor, true, myrand(2) == 0) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::accept"); err_ = true; } if (myrand(5) > 0 && !cur->step() && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::step"); err_ = true; } } if (myrand(rnum_ / 50 + 1) == 0) { std::vector keys; std::string prefix(kbuf, ksiz > 0 ? ksiz - 1 : 0); if (db_->match_prefix(prefix, &keys, myrand(10)) == -1) { dberrprint(db_, __LINE__, "DB::match_prefix"); err_ = true; } } if (myrand(rnum_ / 50 + 1) == 0) { std::vector keys; std::string regex(kbuf, ksiz > 0 ? ksiz - 1 : 0); if (db_->match_regex(regex, &keys, myrand(10)) == -1 && db_->error() != kc::BasicDB::Error::LOGIC) { dberrprint(db_, __LINE__, "DB::match_regex"); err_ = true; } } if (myrand(rnum_ / 50 + 1) == 0) { std::vector keys; std::string origin(kbuf, ksiz > 0 ? ksiz - 1 : 0); if (db_->match_similar(origin, 3, myrand(2) == 0, &keys, myrand(10)) == -1) { dberrprint(db_, __LINE__, "DB::match_similar"); err_ = true; } } break; } default: { size_t rsiz; char* rbuf = db_->get(kbuf, ksiz, &rsiz); if (rbuf) { delete[] rbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::get"); err_ = true; } break; } } } while (myrand(100) == 0); if (i == rnum_ / 2) { if (myrand(thnum_ * 4) == 0 && !db_->clear()) { dberrprint(db_, __LINE__, "DB::clear"); err_ = true; } else { class SyncProcessor : public kc::BasicDB::FileProcessor { private: bool process(const std::string& path, int64_t count, int64_t size) { yield(); return true; } } syncprocessor; if (!db_->synchronize(false, &syncprocessor)) { dberrprint(db_, __LINE__, "DB::synchronize"); err_ = true; } } } if (tran) { yield(); if (!db_->end_transaction(myrand(10) > 0)) { dberrprint(db_, __LINE__, "DB::end_transactin"); err_ = true; } } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } delete cur; } private: int32_t id_; kt::TimedDB* db_; int64_t rnum_; int32_t thnum_; const char* lbuf_; bool err_; }; char lbuf[RECBUFSIZL]; std::memset(lbuf, '*', sizeof(lbuf)); ThreadWicked threads[THREADMAX]; if (thnum < 2) { threads[0].setparams(0, &db, rnum, thnum, lbuf); threads[0].run(); if (threads[0].error()) err = true; } else { for (int32_t i = 0; i < thnum; i++) { threads[i].setparams(i, &db, rnum, thnum, lbuf); threads[i].start(); } for (int32_t i = 0; i < thnum; i++) { threads[i].join(); if (threads[i].error()) err = true; } } dbmetaprint(&db, itcnt == itnum); if (!db.close()) { dberrprint(&db, __LINE__, "DB::close"); err = true; } oprintf("time: %.3f\n", kc::time() - stime); } if (ulogpath && !ulog.close()) { dberrprint(&db, __LINE__, "UpdateLogger::close"); err = true; } oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform tran command static int32_t proctran(const char* path, int64_t rnum, int32_t thnum, int32_t itnum, bool hard, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv) { oprintf("\n seed=%u path=%s rnum=%lld thnum=%d itnum=%d hard=%d" " oflags=%d ulog=%s ulim=%lld sid=%u dbid=%u lv=%d\n\n", g_randseed, path, (long long)rnum, thnum, itnum, hard, oflags, ulogpath ? ulogpath : "", (long long)ulim, sid, dbid, lv); bool err = false; kt::TimedDB db; kt::TimedDB paradb; db.tune_logger(stddblogger(g_progname, &std::cout), lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR); paradb.tune_logger(stddblogger(g_progname, &std::cout), lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, __LINE__, "DB::tune_update_trigger"); err = true; } } else { dberrprint(&db, __LINE__, "UpdateLogger::open"); err = true; } } for (int32_t itcnt = 1; itcnt <= itnum; itcnt++) { oprintf("iteration %d updating:\n", itcnt); double stime = kc::time(); uint32_t omode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE; if (itcnt == 1) omode |= kc::BasicDB::OTRUNCATE; if (!db.open(path, omode | oflags)) { dberrprint(&db, __LINE__, "DB::open"); err = true; } std::string parapath = db.path() + "-para.kch"; if (!paradb.open(parapath, omode)) { dberrprint(¶db, __LINE__, "DB::open"); err = true; } class ThreadTran : public kc::Thread { public: void setparams(int32_t id, kt::TimedDB* db, kt::TimedDB* paradb, int64_t rnum, int32_t thnum, bool hard, const char* lbuf) { id_ = id; db_ = db; paradb_ = paradb; rnum_ = rnum; thnum_ = thnum; hard_ = hard; lbuf_ = lbuf; err_ = false; } bool error() { return err_; } void run() { kt::TimedDB::Cursor* cur = db_->cursor(); int64_t range = rnum_ * thnum_; char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1)); if (!cur->jump(kbuf, ksiz) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::jump"); err_ = true; } bool tran = true; if (!db_->begin_transaction(hard_)) { dberrprint(db_, __LINE__, "DB::begin_transaction"); tran = false; err_ = true; } bool commit = myrand(10) > 0; for (int64_t i = 1; !err_ && i <= rnum_; i++) { ksiz = std::sprintf(kbuf, "%lld", (long long)(myrand(range) + 1)); const char* vbuf = kbuf; size_t vsiz = ksiz; if (myrand(10) == 0) { vbuf = lbuf_; vsiz = myrand(RECBUFSIZL) / (myrand(5) + 1); } class VisitorImpl : public kt::TimedDB::Visitor { public: explicit VisitorImpl(const char* vbuf, size_t vsiz, kt::TimedDB* paradb) : vbuf_(vbuf), vsiz_(vsiz), paradb_(paradb) {} private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { return visit_empty(kbuf, ksiz, sp, xtp); } const char* visit_empty(const char* kbuf, size_t ksiz, size_t* sp, int64_t* xtp) { const char* rv = NOP; switch (myrand(3)) { case 0: { rv = vbuf_; *sp = vsiz_; *xtp = kc::INT64MAX; if (paradb_) paradb_->set(kbuf, ksiz, vbuf_, vsiz_); break; } case 1: { rv = REMOVE; if (paradb_) paradb_->remove(kbuf, ksiz); break; } } return rv; } const char* vbuf_; size_t vsiz_; kt::TimedDB* paradb_; } visitor(vbuf, vsiz, !tran || commit ? paradb_ : NULL); if (myrand(4) == 0) { if (!cur->accept(&visitor, true, myrand(2) == 0) && db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "Cursor::accept"); err_ = true; } } else { if (!db_->accept(kbuf, ksiz, &visitor, true)) { dberrprint(db_, __LINE__, "DB::accept"); err_ = true; } } if (tran && myrand(100) == 0) { if (db_->end_transaction(commit)) { yield(); if (!db_->begin_transaction(hard_)) { dberrprint(db_, __LINE__, "DB::begin_transaction"); tran = false; err_ = true; } } else { dberrprint(db_, __LINE__, "DB::end_transaction"); err_ = true; } } if (id_ < 1 && rnum_ > 250 && i % (rnum_ / 250) == 0) { oputchar('.'); if (i == rnum_ || i % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)i); } } if (tran && !db_->end_transaction(commit)) { dberrprint(db_, __LINE__, "DB::end_transaction"); err_ = true; } delete cur; } private: int32_t id_; kt::TimedDB* db_; kt::TimedDB* paradb_; int64_t rnum_; int32_t thnum_; bool hard_; const char* lbuf_; bool err_; }; char lbuf[RECBUFSIZL]; std::memset(lbuf, '*', sizeof(lbuf)); ThreadTran threads[THREADMAX]; if (thnum < 2) { threads[0].setparams(0, &db, ¶db, rnum, thnum, hard, lbuf); threads[0].run(); if (threads[0].error()) err = true; } else { for (int32_t i = 0; i < thnum; i++) { threads[i].setparams(i, &db, ¶db, rnum, thnum, hard, lbuf); threads[i].start(); } for (int32_t i = 0; i < thnum; i++) { threads[i].join(); if (threads[i].error()) err = true; } } oprintf("iteration %d checking:\n", itcnt); if (db.count() != paradb.count()) { dberrprint(&db, __LINE__, "DB::count"); err = true; } class VisitorImpl : public kt::TimedDB::Visitor { public: explicit VisitorImpl(int64_t rnum, kt::TimedDB* paradb) : rnum_(rnum), paradb_(paradb), err_(false), cnt_(0) {} bool error() { return err_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { cnt_++; size_t rsiz; char* rbuf = paradb_->get(kbuf, ksiz, &rsiz); if (rbuf) { delete[] rbuf; } else { dberrprint(paradb_, __LINE__, "DB::get"); err_ = true; } if (rnum_ > 250 && cnt_ % (rnum_ / 250) == 0) { oputchar('.'); if (cnt_ == rnum_ || cnt_ % (rnum_ / 10) == 0) oprintf(" (%08lld)\n", (long long)cnt_); } return NOP; } int64_t rnum_; kt::TimedDB* paradb_; bool err_; int64_t cnt_; } visitor(rnum, ¶db), paravisitor(rnum, &db); if (!db.iterate(&visitor, false)) { dberrprint(&db, __LINE__, "DB::iterate"); err = true; } oprintf(" (end)\n"); if (visitor.error()) err = true; if (!paradb.iterate(¶visitor, false)) { dberrprint(&db, __LINE__, "DB::iterate"); err = true; } oprintf(" (end)\n"); if (paravisitor.error()) err = true; if (!paradb.close()) { dberrprint(¶db, __LINE__, "DB::close"); err = true; } dbmetaprint(&db, itcnt == itnum); if (!db.close()) { dberrprint(&db, __LINE__, "DB::close"); err = true; } oprintf("time: %.3f\n", kc::time() - stime); } if (ulogpath && !ulog.close()) { dberrprint(&db, __LINE__, "UpdateLogger::close"); err = true; } oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform mapred command static int32_t procmapred(const char* path, int64_t rnum, bool rnd, bool ru, int32_t oflags, const char* ulogpath, int64_t ulim, uint16_t sid, uint16_t dbid, bool lv, const char* tmpdir, int64_t dbnum, int64_t clim, int64_t cbnum, int32_t opts) { oprintf("\n seed=%u path=%s rnum=%lld rnd=%d ru=%d oflags=%d" " ulog=%s ulim=%lld sid=%u dbid=%u lv=%d tmp=%s dbnum=%lld" " clim=%lld cbnum=%lld opts=%d\n\n", g_randseed, path, (long long)rnum, rnd, ru, oflags, ulogpath ? ulogpath : "", (long long)ulim, sid, dbid, lv, tmpdir, (long long)dbnum, (long long)clim, (long long)cbnum, opts); bool err = false; kt::TimedDB db; db.tune_logger(stddblogger(g_progname, &std::cout), lv ? kc::UINT32MAX : kc::BasicDB::Logger::WARN | kc::BasicDB::Logger::ERROR); double stime = kc::time(); kt::UpdateLogger ulog; DBUpdateLogger ulogdb; if (ulogpath) { if (ulog.open(ulogpath, ulim)) { ulogdb.initialize(&ulog, sid, dbid); if (!db.tune_update_trigger(&ulogdb)) { dberrprint(&db, __LINE__, "DB::tune_update_trigger"); err = true; } } else { dberrprint(&db, __LINE__, "UpdateLogger::open"); err = true; } } uint32_t omode = kc::BasicDB::OWRITER | kc::BasicDB::OCREATE | kc::BasicDB::OTRUNCATE; if (ru) omode = kc::PolyDB::OREADER; if (!db.open(path, omode | oflags)) { dberrprint(&db, __LINE__, "DB::open"); err = true; } class MapReduceImpl : public kt::MapReduce { public: MapReduceImpl() : mapcnt_(0), redcnt_(0), lock_() {} bool map(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz) { mapcnt_.add(1); return emit(vbuf, vsiz, kbuf, ksiz); } bool reduce(const char* kbuf, size_t ksiz, ValueIterator* iter) { const char* vbuf; size_t vsiz; while ((vbuf = iter->next(&vsiz)) != NULL) { redcnt_.add(1); } return true; } bool preprocess() { oprintf("preprocessing:\n"); if (!emit("pre", 3, "process", 7)) return false; if (!emit("PROCESS", 7, "PRE", 3)) return false; return true; } bool midprocess() { oprintf("midprocessing:\n"); if (!emit("mid", 3, "process", 7)) return false; if (!emit("PROCESS", 7, "MID", 3)) return false; return true; } bool postprocess() { oprintf("postprocessing:\n"); return true; } bool log(const char* name, const char* message) { kc::ScopedMutex lock(&lock_); oprintf("%s: %s\n", name, message); return true; } int64_t mapcnt() { return mapcnt_; } int64_t redcnt() { return redcnt_; } private: kc::AtomicInt64 mapcnt_; kc::AtomicInt64 redcnt_; kc::Mutex lock_; }; MapReduceImpl mr; mr.tune_storage(dbnum, clim, cbnum); if (!ru) { mr.log("misc", "setting records"); int64_t pnum = rnum / 100; if (pnum < 1) pnum = 1; for (int64_t i = 1; !err && i <= rnum; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%lld", (long long)(rnd ? myrand(rnum) + 1 : i)); char vbuf[RECBUFSIZ]; size_t vsiz = std::sprintf(vbuf, "%lld", (long long)(rnd ? myrand(pnum) + 1 : i % pnum)); if (!db.append(kbuf, ksiz, vbuf, vsiz)) { dberrprint(&db, __LINE__, "DB::append"); err = true; } } } if (!mr.execute(&db, tmpdir, opts)) { dberrprint(&db, __LINE__, "MapReduce::execute"); err = true; } if (!rnd && mr.mapcnt() != rnum) { dberrprint(&db, __LINE__, "MapReduce::mapcnt"); err = true; } if (!rnd && rnum % 100 == 0 && mr.redcnt() != rnum + 4) { dberrprint(&db, __LINE__, "MapReduce::redcnt"); err = true; } if (!db.close()) { dberrprint(&db, __LINE__, "DB::close"); err = true; } if (ulogpath && !ulog.close()) { dberrprint(&db, __LINE__, "UpdateLogger::close"); err = true; } oprintf("time: %.3f\n", kc::time() - stime); oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // perform misc command static int32_t procmisc(const char* path) { oprintf("\n seed=%u path=%s\n\n", g_randseed, path); bool err = false; oprintf("opening the database:\n"); kt::TimedDB* db = new kt::TimedDB; db->open(path, kc::BasicDB::OWRITER | kc::BasicDB::OCREATE | kc::BasicDB::OTRUNCATE); oprintf("setting records:\n"); int64_t rnum = 10000; for (int64_t i = 1; !err && i <= rnum; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)i); if (!db->set(kbuf, ksiz, kbuf, ksiz)) { dberrprint(db, __LINE__, "DB::set"); err = true; } } oprintf("deploying cursors:\n"); const int32_t cnum = 100; kt::TimedDB::Cursor* curs[cnum]; for (int32_t i = 0; i < cnum; i++) { curs[i] = db->cursor(); char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)i + 1); if (!curs[i]->jump(kbuf, ksiz)) { dberrprint(db, __LINE__, "Cursor::jump"); err = true; } } oprintf("accessing records:\n"); for (int64_t i = 1; !err && i <= rnum; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)i); if (i % 3 == 0) { size_t vsiz; char* vbuf = db->get(kbuf, ksiz, &vsiz); if (vbuf) { delete[] vbuf; } else if (db->error() != kc::BasicDB::Error::NOREC) { dberrprint(db, __LINE__, "DB::get"); err = true; } } else { if (!db->remove(kbuf, ksiz)) { dberrprint(db, __LINE__, "DB::remove"); err = true; } } } oprintf("updating records with cursors:\n"); for (int32_t i = 0; i < cnum; i++) { kt::TimedDB::Cursor* cur = curs[i]; switch (i % 7) { default: { size_t ksiz; char* kbuf = cur->get_key(&ksiz, i % 3 == 0); if (kbuf) { delete[] kbuf; } else if (cur->error() != kc::BasicDB::Error::NOREC) { dberrprint(db, __LINE__, "Cursor::get_key"); err = true; } break; } case 1: { size_t vsiz; char* vbuf = cur->get_key(&vsiz, i % 3 == 0); if (vbuf) { delete[] vbuf; } else if (cur->error() != kc::BasicDB::Error::NOREC) { dberrprint(db, __LINE__, "Cursor::get_key"); err = true; } break; } case 2: { size_t ksiz; const char* vbuf; size_t vsiz; char* kbuf = cur->get(&ksiz, &vbuf, &vsiz, NULL, i % 3 == 0); if (kbuf) { delete[] kbuf; } else if (cur->error() != kc::BasicDB::Error::NOREC) { dberrprint(db, __LINE__, "Cursor::get"); err = true; } break; } case 3: { char vbuf[RECBUFSIZ]; size_t vsiz = std::sprintf(vbuf, "kyoto:%d", i); if (!cur->set_value(vbuf, vsiz) && cur->error() != kc::BasicDB::Error::NOREC) { dberrprint(db, __LINE__, "Cursor::set_value"); err = true; } break; } case 4: { if (!cur->remove() && cur->error() != kc::BasicDB::Error::NOREC) { dberrprint(db, __LINE__, "Cursor::remove"); err = true; } break; } } } oprintf("bulk operations:\n"); class VisitorBulk : public kt::TimedDB::Visitor { public: VisitorBulk() : before_(0), after_(0) {} int64_t before() { return before_; } int64_t after() { return after_; } private: void visit_before() { before_++; } void visit_after() { after_++; } int64_t before_; int64_t after_; }; std::vector keys; for (int64_t i = 1; !err && i <= rnum; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)i); keys.push_back(std::string(kbuf, ksiz)); if (i % 10 == 0) { VisitorBulk visitor; if (db->accept_bulk(keys, &visitor, i % 3 > 0)) { if (visitor.before() != 1 || visitor.after() != 1) { dberrprint(db, __LINE__, "DB::accept_bulk"); err = true; } } else { dberrprint(db, __LINE__, "DB::accept_bulk"); err = true; } keys.clear(); } } oprintf("scanning in parallel:\n"); class VisitorCount : public kt::TimedDB::Visitor { public: explicit VisitorCount() : cnt_(0) {} int64_t cnt() { return cnt_; } private: const char* visit_full(const char* kbuf, size_t ksiz, const char* vbuf, size_t vsiz, size_t* sp, int64_t* xtp) { cnt_.add(1); return NOP; } kc::AtomicInt64 cnt_; } visitorcount; class ProgressCheckerCount : public kc::BasicDB::ProgressChecker { public: explicit ProgressCheckerCount() : cnt_(0) {} int64_t cnt() { return cnt_; } private: bool check(const char* name, const char* message, int64_t curcnt, int64_t allcnt) { cnt_.add(1); return true; } kc::AtomicInt64 cnt_; } checkercount; class ThreadWicked : public kc::Thread { public: explicit ThreadWicked(kt::TimedDB* db, int64_t rnum) : db_(db), rnum_(rnum), err_(false) {} bool error() { return err_; } private: void run() { for (int64_t i = 0; i < rnum_; i++) { char kbuf[RECBUFSIZ]; size_t ksiz = std::sprintf(kbuf, "%08lld", (long long)i); size_t vsiz; char* vbuf = db_->get(kbuf, ksiz, &vsiz); if (vbuf) { delete[] vbuf; } else if (db_->error() != kc::BasicDB::Error::NOREC) { dberrprint(db_, __LINE__, "DB::set"); err_ = true; } } } kt::TimedDB* db_; int64_t rnum_; bool err_; } threadwicked(db, rnum); threadwicked.start(); if (!db->scan_parallel(&visitorcount, 4, &checkercount)) { dberrprint(db, __LINE__, "DB::scan_parallel"); err = true; } threadwicked.join(); if (threadwicked.error()) err = true; if (visitorcount.cnt() != db->count()) { dberrprint(db, __LINE__, "DB::scan_parallel"); err = true; } if (checkercount.cnt() < db->count() + 2) { dberrprint(db, __LINE__, "DB::scan_parallel ss"); err = true; } oprintf("deleting the database object:\n"); delete db; oprintf("deleting the cursor objects:\n"); for (int32_t i = 0; i < cnum; i++) { delete curs[i]; } oprintf("re-opening the database object with a external database:\n"); kt::TimedDB* tdb = new kt::TimedDB; if (!tdb->set_internal_db(new kc::PolyDB)) { dberrprint(tdb, __LINE__, "DB::set_internal_db"); err = true; } if (!tdb->open(path, kc::BasicDB::OREADER)) { dberrprint(tdb, __LINE__, "DB::open"); err = true; } oprintf("deleting the database object:\n"); delete tdb; oprintf("%s\n\n", err ? "error" : "ok"); return err ? 1 : 0; } // END OF FILE kyototycoon-0.9.56/ktutil.h0000644000175000017500000006270511757471602014727 0ustar mikiomikio/************************************************************************************************* * Utility functions * Copyright (C) 2009-2012 FAL Labs * This file is part of Kyoto Tycoon. * This program is free software: you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by the Free Software Foundation, either version * 3 of the License, or any later version. * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. * You should have received a copy of the GNU General Public License along with this program. * If not, see . *************************************************************************************************/ #ifndef _KTUTIL_H // duplication check #define _KTUTIL_H #include namespace kyototycoon { // common namespace /** The package version. */ extern const char* const VERSION; /** The library version. */ extern const int32_t LIBVER; /** The library revision. */ extern const int32_t LIBREV; /** The extra feature list. */ extern const char* const FEATURES; /** The default port number. */ const int32_t DEFPORT = 1978; /** * Set the signal handler for termination signals. * @param handler the function pointer of the signal handler. * @return true on success, or false on failure. */ bool setkillsignalhandler(void (*handler)(int)); /** * Set the signal mask of the current to ignore all. * @return true on success, or false on failure. */ bool maskthreadsignal(); /** * Switch the process into the background. * @return true on success, or false on failure. */ bool daemonize(); /** * Execute a shell command. * @param args an array of the command name and its arguments. * @return the exit code of the command or `INT32_MIN' on failure. * @note The command name and the arguments are quoted and meta characters are escaped. */ int32_t executecommand(const std::vector& args); /** * Get the C-style string value of a record in a string map. * @param map the target string map. * @param key the key. * @param sp the pointer to the variable into which the size of the region of the return value * is assigned. If it is NULL, it is ignored. * @return the C-style string value of the corresponding record, or NULL if there is no * corresponding record. */ const char* strmapget(const std::map& map, const char* key, size_t* sp = NULL); /** * Print all records in a string vector. * @param vec the target string vector. * @param strm the output stream. */ void printstrvec(const std::vector& vec, std::ostream& strm = std::cout); /** * Print all records in a string map. * @param map the target string map. * @param strm the output stream. */ void printstrmap(const std::map& map, std::ostream& strm = std::cout); /** * Break up a URL into elements. * @param url the URL string. * @param elems the map object to contain the result elements. The key "self" indicates the URL * itself. "scheme" indicates the scheme. "host" indicates the host of the server. "port" * indicates the port number of the server. "authority" indicates the authority information. * "path" indicates the path of the resource. "file" indicates the file name without the * directory section. "query" indicates the query string. "fragment" indicates the fragment * string. * @note Supported schema are HTTP, HTTPS, FTP, and FILE. Both of absolute URL and relative URL * are supported. */ void urlbreak(const char* url, std::map* elems); /** * Escape meta characters in a string with the entity references of XML. * @param str the string. * @return the escaped string. * @note Because the region of the return value is allocated with the the new[] operator, it * should be released with the delete[] operator when it is no longer in use. */ char* xmlescape(const char* str); /** * Unescape meta characters in a string with the entity references of XML. * @param str the string. * @return the unescaped string. * @note Because the region of the return value is allocated with the the new[] operator, it * should be released with the delete[] operator when it is no longer in use. */ char* xmlunescape(const char* str); /** * Parse a www-form-urlencoded string and store each records into a map. * @param str the source string. * @param map the destination string map. */ void wwwformtomap(const std::string& str, std::map* map); /** * Serialize a string map into a www-form-urlencoded string. * @param map the source string map. * @param str the destination string. */ void maptowwwform(const std::map& map, std::string* str); /** * Parse a TSV string and store each records into a map. * @param str the source string. * @param map the destination string map. */ void tsvtomap(const std::string& str, std::map* map); /** * Serialize a string map into a TSV string. * @param map the source string map. * @param str the destination string. */ void maptotsv(const std::map& map, std::string* str); /** * Encode each record of a string map. * @param map the string map. * @param mode the encoding mode. 'B' for Base64 encoding, 'Q' for Quoted-printable encoding, * 'U' for URL encoding. */ void tsvmapencode(std::map* map, int32_t mode); /** * Decode each record of a string map. * @param map the string map. * @param mode the encoding mode. 'B' for Base64 encoding, 'Q' for Quoted-printable encoding, * 'U' for URL encoding. */ void tsvmapdecode(std::map* map, int32_t mode); /** * Check the best suited encoding of a string map. * @param map the string map. * @return the the best suited encoding. 0 for the raw format, 'B' for Base64 encoding, 'Q' for * Quoted-printable encoding, */ int32_t checkmapenc(const std::map& map); /** * Capitalize letters of a string. * @param str the string to convert. * @return the string itself. */ char* strcapitalize(char* str); /** * Check a string is composed of alphabets or numbers only. * @return true if it is composed of alphabets or numbers only, or false if not. */ bool strisalnum(const char* str); /** * Tokenize a string separating by space characters. * @param str the source string. * @param tokens a string vector to contain the result tokens. */ void strtokenize(const char* str, std::vector* tokens); /** * Get the Gregorian calendar of a time. * @param t the source time in seconds from the epoch. If it is kyotocabinet::INT64MAX, the * current time is specified. * @param jl the jet lag of a location in seconds. If it is kyotocabinet::INT32MAX, the local * jet lag is specified. * @param yearp the pointer to a variable to which the year is assigned. If it is NULL, it is * not used. * @param monp the pointer to a variable to which the month is assigned. If it is NULL, it is * not used. 1 means January and 12 means December. * @param dayp the pointer to a variable to which the day of the month is assigned. If it is * NULL, it is not used. * @param hourp the pointer to a variable to which the hours is assigned. If it is NULL, it is * not used. * @param minp the pointer to a variable to which the minutes is assigned. If it is NULL, it is * not used. * @param secp the pointer to a variable to which the seconds is assigned. If it is NULL, it is * not used. */ void getcalendar(int64_t t, int32_t jl, int32_t* yearp = NULL, int32_t* monp = NULL, int32_t* dayp = NULL, int32_t* hourp = NULL, int32_t* minp = NULL, int32_t* secp = NULL); /** * Format a date as a string in W3CDTF. * @param t the source time in seconds from the epoch. If it is kyotocabinet::INT64MAX, the * current time is specified. * @param jl the jet lag of a location in seconds. If it is kyotocabinet::INT32MAX, the local * jet lag is specified. * @param buf the pointer to the region into which the result string is written. The size of * the buffer should be equal to or more than 48 bytes. */ void datestrwww(int64_t t, int32_t jl, char* buf); /** * Format a date as a string in W3CDTF with the fraction part. * @param t the source time in seconds from the epoch. If it is Not-a-Number, the current time * is specified. * @param jl the jet lag of a location in seconds. If it is kyotocabinet::INT32MAX, the local * jet lag is specified. * @param acr the accuracy of time by the number of columns of the fraction part. * @param buf the pointer to the region into which the result string is written. The size of * the buffer should be equal to or more than 48 bytes. */ void datestrwww(double t, int32_t jl, int32_t acr, char* buf); /** * Format a date as a string in RFC 1123 format. * @param t the source time in seconds from the epoch. If it is kyotocabinet::INT64MAX, the * current time is specified. * @param jl the jet lag of a location in seconds. If it is kyotocabinet::INT32MAX, the local * jet lag is specified. * @param buf the pointer to the region into which the result string is written. The size of * the buffer should be equal to or more than 48 bytes. */ void datestrhttp(int64_t t, int32_t jl, char* buf); /** * Get the time value of a date string. * @param str the date string in decimal, hexadecimal, W3CDTF, or RFC 822 (1123). Decimal can * be trailed by "s" for in seconds, "m" for in minutes, "h" for in hours, and "d" for in days. * @return the time value of the date or INT64_MIN if the format is invalid. */ int64_t strmktime(const char* str); /** * Get the jet lag of the local time. * @return the jet lag of the local time in seconds. */ int32_t jetlag(); /** * Get the day of week of a date. * @param year the year of a date. * @param mon the month of the date. * @param day the day of the date. * @return the day of week of the date. 0 means Sunday and 6 means Saturday. */ int32_t dayofweek(int32_t year, int32_t mon, int32_t day); /** * Get the local time of a time. * @param time the time. * @param result the resulb buffer. * @return true on success, or false on failure. */ bool getlocaltime(time_t time, struct std::tm* result); /** * Get the GMT local time of a time. * @param time the time. * @param result the resulb buffer. * @return true on success, or false on failure. */ bool getgmtime(time_t time, struct std::tm* result); /** * Make the GMT from a time structure. * @param tm the pointer to the time structure. * @return the GMT. */ time_t mkgmtime(struct std::tm *tm); /** * Get the C-style string value of a record in a string map. */ inline const char* strmapget(const std::map& map, const char* key, size_t* sp) { _assert_(key); std::map::const_iterator it = map.find(key); if (it == map.end()) { if (sp) *sp = 0; return NULL; } if (sp) *sp = it->second.size(); return it->second.c_str(); } /** * Print all records in a string vector. */ inline void printstrvec(const std::vector& vec, std::ostream& strm) { _assert_(true); std::vector::const_iterator it = vec.begin(); std::vector::const_iterator itend = vec.end(); while (it != itend) { strm << *it << std::endl; ++it; } } /** * Print all records in a string map. */ inline void printstrmap(const std::map& map, std::ostream& strm) { _assert_(true); std::map::const_iterator it = map.begin(); std::map::const_iterator itend = map.end(); while (it != itend) { strm << it->first << '\t' << it->second << std::endl; ++it; } } /** * Break up a URL into elements. */ inline void urlbreak(const char* url, std::map* elems) { _assert_(url); char* trim = kc::strdup(url); kc::strtrim(trim); char* rp = trim; char* norm = new char[std::strlen(trim)*3+1]; char* wp = norm; while (*rp != '\0') { if (*rp > 0x20 && *rp < 0x7f) { *(wp++) = *rp; } else { *(wp++) = '%'; int32_t num = *(unsigned char*)rp >> 4; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } num = *rp & 0x0f; if (num < 10) { *(wp++) = '0' + num; } else { *(wp++) = 'a' + num - 10; } } rp++; } *wp = '\0'; rp = norm; (*elems)["self"] = rp; bool serv = false; if (kc::strifwm(rp, "http://")) { (*elems)["scheme"] = "http"; rp += 7; serv = true; } else if (kc::strifwm(rp, "https://")) { (*elems)["scheme"] = "https"; rp += 8; serv = true; } else if (kc::strifwm(rp, "ftp://")) { (*elems)["scheme"] = "ftp"; rp += 6; serv = true; } else if (kc::strifwm(rp, "sftp://")) { (*elems)["scheme"] = "sftp"; rp += 7; serv = true; } else if (kc::strifwm(rp, "ftps://")) { (*elems)["scheme"] = "ftps"; rp += 7; serv = true; } else if (kc::strifwm(rp, "tftp://")) { (*elems)["scheme"] = "tftp"; rp += 7; serv = true; } else if (kc::strifwm(rp, "ldap://")) { (*elems)["scheme"] = "ldap"; rp += 7; serv = true; } else if (kc::strifwm(rp, "ldaps://")) { (*elems)["scheme"] = "ldaps"; rp += 8; serv = true; } else if (kc::strifwm(rp, "file://")) { (*elems)["scheme"] = "file"; rp += 7; serv = true; } char* ep; if ((ep = std::strchr(rp, '#')) != NULL) { (*elems)["fragment"] = ep + 1; *ep = '\0'; } if ((ep = std::strchr(rp, '?')) != NULL) { (*elems)["query"] = ep + 1; *ep = '\0'; } if (serv) { if ((ep = std::strchr(rp, '/')) != NULL) { (*elems)["path"] = ep; *ep = '\0'; } else { (*elems)["path"] = "/"; } if ((ep = std::strchr(rp, '@')) != NULL) { *ep = '\0'; if (rp[0] != '\0') (*elems)["authority"] = rp; rp = ep + 1; } if ((ep = std::strchr(rp, ':')) != NULL) { if (ep[1] != '\0') (*elems)["port"] = ep + 1; *ep = '\0'; } if (rp[0] != '\0') (*elems)["host"] = rp; } else { (*elems)["path"] = rp; } delete[] norm; delete[] trim; const char* file = strmapget(*elems, "path"); if (file) { const char* pv = std::strrchr(file, '/'); if (pv) file = pv + 1; if (*file != '\0' && std::strcmp(file, ".") && std::strcmp(file, "..")) (*elems)["file"] = file; } } /** * Escape meta characters in a string with the entity references of XML. */ inline char* xmlescape(const char* str) { _assert_(str); const char* rp = str; size_t bsiz = 0; while (*rp != '\0') { switch (*rp) { case '&': bsiz += 5; break; case '<': bsiz += 4; break; case '>': bsiz += 4; break; case '"': bsiz += 6; break; default: bsiz++; break; } rp++; } char* buf = new char[bsiz+1]; char* wp = buf; while (*str != '\0') { switch (*str) { case '&': { std::memcpy(wp, "&", 5); wp += 5; break; } case '<': { std::memcpy(wp, "<", 4); wp += 4; break; } case '>': { std::memcpy(wp, ">", 4); wp += 4; break; } case '"': { std::memcpy(wp, """, 6); wp += 6; break; } default: { *(wp++) = *str; break; } } str++; } *wp = '\0'; return buf; } /** * Unescape meta characters in a string with the entity references of XML. */ inline char* xmlunescape(const char* str) { _assert_(str); char* buf = new char[std::strlen(str)+1]; char* wp = buf; while (*str != '\0') { if (*str == '&') { if (kc::strfwm(str, "&")) { *(wp++) = '&'; str += 5; } else if (kc::strfwm(str, "<")) { *(wp++) = '<'; str += 4; } else if (kc::strfwm(str, ">")) { *(wp++) = '>'; str += 4; } else if (kc::strfwm(str, """)) { *(wp++) = '"'; str += 6; } else { *(wp++) = *(str++); } } else { *(wp++) = *(str++); } } *wp = '\0'; return buf; } /** * Parse a www-form-urlencoded string and store each records into a map. */ inline void wwwformtomap(const std::string& str, std::map* map) { _assert_(true); const char* rp = str.data(); const char* pv = rp; const char* ep = rp + str.size(); while (rp < ep) { if (*rp == '&' || *rp == ';') { while (pv < rp && *pv > '\0' && *pv <= ' ') { pv++; } if (rp > pv) { size_t len = rp - pv; char* rbuf = new char[len+1]; std::memcpy(rbuf, pv, len); rbuf[len] = '\0'; char* sep = std::strchr(rbuf, '='); const char* vp = ""; if (sep) { *(sep++) = '\0'; vp = sep; } size_t ksiz; char* kbuf = kc::urldecode(rbuf, &ksiz); size_t vsiz; char* vbuf = kc::urldecode(vp, &vsiz); std::string key(kbuf, ksiz); std::string value(vbuf, vsiz); (*map)[key] = value; delete[] vbuf; delete[] kbuf; delete[] rbuf; } pv = rp + 1; } rp++; } while (pv < rp && *pv > '\0' && *pv <= ' ') { pv++; } if (rp > pv) { size_t len = rp - pv; char* rbuf = new char[len+1]; std::memcpy(rbuf, pv, len); rbuf[len] = '\0'; const char* vp = ""; char* sep = std::strchr(rbuf, '='); if (sep) { *(sep++) = '\0'; vp = sep; } size_t ksiz; char* kbuf = kc::urldecode(rbuf, &ksiz); size_t vsiz; char* vbuf = kc::urldecode(vp, &vsiz); std::string key(kbuf, ksiz); std::string value(vbuf, vsiz); (*map)[key] = value; delete[] vbuf; delete[] kbuf; delete[] rbuf; } } /** * Serialize a string map into a www-form-urlencoded string. */ inline void maptowwwform(const std::map& map, std::string* str) { _assert_(true); std::map::const_iterator it = map.begin(); std::map::const_iterator itend = map.end(); str->reserve(kc::UINT8MAX); it = map.begin(); while (it != itend) { if (str->size() > 0) str->append("&"); char* zstr = kc::urlencode(it->first.data(), it->first.size()); str->append(zstr); delete[] zstr; str->append("="); zstr = kc::urlencode(it->second.data(), it->second.size()); str->append(zstr); delete[] zstr; ++it; } } /** * Parse a TSV string and store each records into a map. */ inline void tsvtomap(const std::string& str, std::map* map) { _assert_(true); std::string::const_iterator it = str.begin(); std::string::const_iterator pv = it; std::string field; while (it != str.end()) { if (*it == '\n') { if (it > pv) { std::string::const_iterator ev = it; if (ev[-1] == '\r') ev--; std::string::const_iterator rv = pv; while (rv < ev) { if (*rv == '\t') { std::string name(pv, rv); rv++; std::string value(rv, ev); (*map)[name] = value; break; } rv++; } } pv = it + 1; } ++it; } if (it > pv) { std::string::const_iterator ev = it; if (ev[-1] == '\r') ev--; std::string::const_iterator rv = pv; while (rv < ev) { if (*rv == '\t') { std::string name(pv, rv); rv++; std::string value(rv, ev); (*map)[name] = value; break; } rv++; } } } /** * Serialize a string map into a TSV string. */ inline void maptotsv(const std::map& map, std::string* str) { _assert_(true); std::map::const_iterator it = map.begin(); std::map::const_iterator itend = map.end(); size_t size = 0; while (it != itend) { size += it->first.size() + it->second.size() + 2; ++it; } str->reserve(size); it = map.begin(); while (it != itend) { str->append(it->first); str->append("\t"); str->append(it->second); str->append("\n"); ++it; } } /** * Encode each record of a string map. */ inline void tsvmapencode(std::map* map, int32_t mode) { _assert_(map); std::map nmap; std::map::iterator it = map->begin(); std::map::iterator itend = map->end(); while (it != itend) { char* kstr, *vstr; switch (mode) { case 'B': case 'b': { kstr = kc::baseencode(it->first.data(), it->first.size()); vstr = kc::baseencode(it->second.data(), it->second.size()); break; } case 'Q': case 'q': { kstr = kc::quoteencode(it->first.data(), it->first.size()); vstr = kc::quoteencode(it->second.data(), it->second.size()); break; } case 'U': case 'u': { kstr = kc::urlencode(it->first.data(), it->first.size()); vstr = kc::urlencode(it->second.data(), it->second.size()); break; } default: { kstr = NULL; vstr = NULL; break; } } if (kstr && vstr) { std::string key(kstr); std::string value(vstr); nmap[key] = value; } delete[] vstr; delete[] kstr; ++it; } map->swap(nmap); } /** * Decode each record of a string map. */ inline void tsvmapdecode(std::map* map, int32_t mode) { _assert_(map); std::map nmap; std::map::iterator it = map->begin(); std::map::iterator itend = map->end(); while (it != itend) { char* kbuf, *vbuf; size_t ksiz, vsiz; switch (mode) { case 'B': case 'b': { kbuf = kc::basedecode(it->first.c_str(), &ksiz); vbuf = kc::basedecode(it->second.c_str(), &vsiz); break; } case 'Q': case 'q': { kbuf = kc::quotedecode(it->first.c_str(), &ksiz); vbuf = kc::quotedecode(it->second.c_str(), &vsiz); break; } case 'U': case 'u': { kbuf = kc::urldecode(it->first.c_str(), &ksiz); vbuf = kc::urldecode(it->second.c_str(), &vsiz); break; } default: { kbuf = NULL; vbuf = NULL; break; } } if (kbuf && vbuf) { std::string key(kbuf, ksiz); std::string value(vbuf, vsiz); nmap[key] = value; } delete[] vbuf; delete[] kbuf; ++it; } map->swap(nmap); } /** * Check the best suited encoding of a string map. */ inline int32_t checkmapenc(const std::map& map) { _assert_(true); bool bin = false; size_t blen = 0; size_t ulen = 0; std::map::const_iterator it = map.begin(); std::map::const_iterator itend = map.end(); while (it != itend) { const char* buf = it->first.data(); size_t size = it->first.size(); if (size > kc::UINT8MAX) { size = kc::UINT8MAX; bin = true; } blen += size * 6 / 4 + 3; for (size_t i = 0; i < size; i++) { int32_t c = ((unsigned char*)buf)[i]; if (c < ' ' || c == 0x7f) bin = true; if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c != '\0' && std::strchr("_-.!~*'()", c))) { ulen++; } else { ulen += 3; } } buf = it->second.data(); size = it->second.size(); if (size > kc::UINT8MAX) { size = kc::UINT8MAX; bin = true; } blen += size * 6 / 4 + 3; for (size_t i = 0; i < size; i++) { int32_t c = ((unsigned char*)buf)[i]; if (c < ' ' || c == 0x7f) bin = true; if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c != '\0' && std::strchr("_-.!~*'()", c))) { ulen++; } else { ulen += 3; } } ++it; } if (!bin) return 0; return blen < ulen ? 'B' : 'U'; } /** * Capitalize letters of a string. */ inline char* strcapitalize(char* str) { _assert_(str); char* wp = str; bool head = true; while (*wp != '\0') { if (head && *wp >= 'a' && *wp <= 'z') *wp -= 'a' - 'A'; head = *wp == '-' || *wp == ' '; wp++; } return str; } /** * Check a string is composed of alphabets or numbers only. */ inline bool strisalnum(const char* str) { _assert_(str); while (*str != '\0') { if (!(*str >= 'a' && *str <= 'z') && !(*str >= 'A' && *str <= 'Z') && !(*str >= '0' && *str <= '9')) return false; str++; } return true; } /** * Tokenize a string separating by space characters. */ inline void strtokenize(const char* str, std::vector* tokens) { _assert_(str && tokens); tokens->clear(); while (*str == ' ' || *str == '\t') { str++; } const char* pv = str; while (*str != '\0') { if (*str > '\0' && *str <= ' ') { if (str > pv) { std::string elem(pv, str - pv); tokens->push_back(elem); } while (*str > '\0' && *str <= ' ') { str++; } pv = str; } else { str++; } } if (str > pv) { std::string elem(pv, str - pv); tokens->push_back(elem); } } } // common namespace #endif // duplication check // END OF FILE