adbd.c
来自「基于DHT的对等协议」· C语言 代码 · 共 1,538 行 · 第 1/3 页
C
1,538 行
if (rt < exptime) { str filepath = subdirpath << "/" << sdp->d_name; if (unlink (filepath) < 0) warn ("unlink: %s: %m\n", filepath.cstr ()); } } closedir (subdir); rmdir (subdirpath); } } closedir (datadir); return 0;}// }}}// }}}// {{{ DB Managerclass dbmanager { str dbpath; str logpath; ihash<str, dbns, &dbns::name, &dbns::hlink> dbs; void dbcloser (dbns *db);public: dbmanager (str, str); ~dbmanager (); const str &getdbpath () { return dbpath; }; dbns *get (const str &n) { return dbs[n]; }; dbns *createdb (const str &n, bool aux);};voidmkdir_wrapper (str path){ // Make path if necessary struct stat sb; if (stat (path, &sb) < 0) { if (errno == ENOENT) { if (mkdir (path, 0755) < 0) fatal ("mkdir (%s): %m\n", path.cstr ()); } else { fatal ("stat (%s): %m\n", path.cstr ()); } } else { if (!S_ISDIR (sb.st_mode)) fatal ("%s is not a directory\n", path.cstr ()); if (access (path, W_OK) < 0) fatal ("access (%s, W_OK): %m\n", path.cstr ()); }}static strcanonicalize_path (str path){ // Convert path to full path char realpath[MAXPATHLEN]; int fd = -1; if (((fd = open (".", O_RDONLY)) >= 0) && chdir (path) >= 0) { if (getcwd (realpath, sizeof (realpath))) errno = 0; else if (!errno) errno = EINVAL; if (fchdir (fd)) warn ("fchdir: %m\n"); } return str (realpath);}dbmanager::dbmanager (str p, str lp = NULL) : dbpath (p), logpath (lp){ mkdir_wrapper (dbpath); if (logpath) { mkdir_wrapper (logpath); logpath = canonicalize_path (logpath); } // Add trailing slash if necessary str x = canonicalize_path (dbpath); if (x[x.len () - 1] != '/') dbpath = strbuf () << x << "/"; else dbpath = x;}dbmanager::~dbmanager (){ dbs.traverse (wrap (this, &dbmanager::dbcloser)); dbs.clear ();}voiddbmanager::dbcloser (dbns *db){ if (db) { warn << "Closing db " << db->name << "\n"; delete db; db = NULL; }}dbns *dbmanager::createdb (const str &n, bool aux){ dbns *db = dbs[n]; if (!db) { if (logpath) mkdir_wrapper (strbuf() << logpath << "/" << n); db = New dbns (dbpath, n, aux, logpath); dbs.insert (db); } return db;}// }}}// {{{ Shutdown functionsEXITFN (cleanup);static voidcleanup (){ if (dbstarted) { if (clntfd >= 0) { fdcb (clntfd, selread, NULL); close (clntfd); } unlink (dbsock); }}static voidhalt (){ warn << "Exiting on command...\n"; delete dbm; exit (0);}// }}}// {{{ RPC execution// {{{ do_initspacevoiddo_initspace (dbmanager *dbm, svccb *sbp){ adb_initspacearg *arg = sbp->Xtmpl getarg<adb_initspacearg> (); adb_status stat (ADB_OK); dbns *db = dbm->get (arg->name); if (db) { sbp->replyref (stat); return; } db = dbm->createdb (arg->name, arg->hasaux); stat = (db ? ADB_OK : ADB_ERR); sbp->replyref (stat);}// }}}// {{{ do_storevoiddo_store (dbmanager *dbm, svccb *sbp){ adb_storearg *arg = sbp->Xtmpl getarg<adb_storearg> (); dbns *db = dbm->get (arg->name); if (!db) { sbp->replyref (ADB_ERR); return; } u_int64_t t = io_start (); DBT data; bzero (&data, sizeof (data)); data.data = arg->data.base (); data.size = arg->data.size (); int r = db->insert (arg->key, data, arg->auxdata, arg->expiration); io_finish (t, strbuf("store %s", arg->name.cstr ())); adb_status stat = ADB_OK; switch (r) { case 0: case DB_KEYEXIST: break; case ENOSPC: stat = ADB_DISKFULL; break; default: stat = ADB_ERR; break; } sbp->replyref (stat); if (db->quotacheck (quota) > expire_threshold) { u_int64_t t = io_start (); db->expire (expire_batch_size); io_finish (t, strbuf ("expire %s", db->getname ().cstr ())); }}// }}}// {{{ do_fetchvoiddo_fetch (dbmanager *dbm, svccb *sbp){ adb_fetcharg *arg = sbp->Xtmpl getarg<adb_fetcharg> (); adb_fetchres res (ADB_OK); dbns *db = dbm->get (arg->name); if (!db) { res.set_status (ADB_ERR); sbp->replyref (res); return; } u_int64_t t = io_start (); str data; adb_metadata_t md; bzero (&md, sizeof (md)); int r; chordID key; if (arg->nextkey) { r = db->lookup_nextkey (arg->key, key); data = ""; } else { r = db->lookup (arg->key, data, md); key = arg->key; } if (r) { res.set_status ((r == DB_NOTFOUND ? ADB_NOTFOUND : ADB_ERR)); } else { res.resok->key = key; res.resok->data = data; res.resok->expiration = md.expiration; } io_finish (t, strbuf ("fetch %s", arg->name.cstr ())); sbp->replyref (res);}// }}}// {{{ do_getkeysvoiddo_getkeys (dbmanager *dbm, svccb *sbp){ adb_getkeysarg *arg = sbp->Xtmpl getarg<adb_getkeysarg> (); adb_getkeysres res (ADB_OK); dbns *db = dbm->get (arg->name); if (!db) { res.set_status (ADB_ERR); sbp->replyref (res); return; } res.resok->hasaux = db->hasaux () && arg->getaux; res.resok->ordered = arg->ordered; int r (-1); r = db->getkeys (arg->continuation, arg->batchsize, arg->getaux, res.resok->keyaux); if (!r) res.resok->continuation = incID (res.resok->keyaux.back ().key); res.resok->complete = (r == DB_NOTFOUND); if (r && r != DB_NOTFOUND) res.set_status (ADB_ERR); sbp->replyref (res);}// }}}// {{{ do_deletevoiddo_delete (dbmanager *dbm, svccb *sbp){ adb_deletearg *arg = sbp->Xtmpl getarg<adb_deletearg> (); dbns *db = dbm->get (arg->name); if (!db) { sbp->replyref (ADB_ERR); return; } int r = db->del (arg->key, arg->auxdata); sbp->replyref ((r == 0) ? ADB_OK : ADB_NOTFOUND);}// }}}// {{{ do_getspaceinfovoiddo_getspaceinfo (dbmanager *dbm, svccb *sbp){ adb_dbnamearg *arg = sbp->Xtmpl getarg<adb_dbnamearg> (); adb_getspaceinfores *res = sbp->Xtmpl getres<adb_getspaceinfores> (); res->status = ADB_OK; dbns *db = dbm->get (arg->name); if (!db) { sbp->replyref (ADB_ERR); return; } res->fullpath = strbuf () << dbm->getdbpath () << arg->name; res->hasaux = db->hasaux (); sbp->reply (res);}// }}}// {{{ do_syncvoiddo_sync (dbmanager *dbm, svccb *sbp){ adb_dbnamearg *arg = sbp->Xtmpl getarg<adb_dbnamearg> (); adb_status res (ADB_OK); dbns *db = dbm->get (arg->name); if (!db) { res = ADB_ERR; } else { u_int64_t t = io_start (); db->sync (); io_finish (t, strbuf ("sync %s", arg->name.cstr ())); } sbp->replyref (res);}// }}}// {{{ do_expirevoiddo_expire (dbmanager *dbm, svccb *sbp){ adb_expirearg *arg = sbp->Xtmpl getarg<adb_expirearg> (); adb_status res (ADB_OK); dbns *db = dbm->get (arg->name); if (!db) { res = ADB_ERR; } else { u_int64_t t = io_start (); db->expire (arg->limit, arg->deadline); io_finish (t, strbuf ("expire %s", arg->name.cstr ())); } sbp->replyref (res);}// }}}// }}}// {{{ RPC accept and dispatchvoiddispatch (ref<axprt_stream> s, ptr<asrv> a, dbmanager *dbm, svccb *sbp){ if (sbp == NULL) { warn << "EOF from client\n"; a->setcb (NULL); return; } switch (sbp->proc ()) { case ADBPROC_INITSPACE: do_initspace (dbm, sbp); break; case ADBPROC_STORE: do_store (dbm, sbp); break; case ADBPROC_FETCH: do_fetch (dbm, sbp); break; case ADBPROC_GETKEYS: do_getkeys (dbm, sbp); break; case ADBPROC_DELETE: do_delete (dbm, sbp); break; case ADBPROC_GETSPACEINFO: do_getspaceinfo (dbm, sbp); break; case ADBPROC_SYNC: do_sync (dbm, sbp); break; case ADBPROC_EXPIRE: do_expire (dbm, sbp); break; default: fatal << "unknown procedure: " << sbp->proc () << "\n"; } return;}static void accept_cb (int lfd, dbmanager *dbm);static voidlisten_unix (str sock_name, dbmanager *dbm){ unlink (sock_name); clntfd = unixsocket (sock_name); if (clntfd < 0) fatal << "Error creating socket (UNIX)" << strerror (errno) << "\n"; if (listen (clntfd, 128) < 0) { fatal ("Error from listen: %m\n"); close (clntfd); } else { fdcb (clntfd, selread, wrap (accept_cb, clntfd, dbm)); } dbstarted = true;}static void accept_cb (int lfd, dbmanager *dbm){ sockaddr_un sun; bzero (&sun, sizeof (sun)); socklen_t sunlen = sizeof (sun); int fd = accept (lfd, reinterpret_cast<sockaddr *> (&sun), &sunlen); if (fd < 0) fatal ("EOF\n"); ref<axprt_stream> x = axprt_stream::alloc (fd, asrvbufsize); ptr<asrv> a = asrv::alloc (x, adb_program_1); a->setcb (wrap (dispatch, x, a, dbm));}// }}}voidusage (){ warnx << "Usage: adbd -d db -S sock [-D] [-q quota]\n"; exit (0);}int main (int argc, char **argv){ setprogname (argv[0]); mp_set_memory_functions (NULL, simple_realloc, NULL); char ch; str db_name = "/var/tmp/db"; str log_path = NULL; dbsock = "/tmp/db-sock"; bool do_daemonize (false); while ((ch = getopt (argc, argv, "Dd:l:q:S:"))!=-1) switch (ch) { case 'D': do_daemonize = true; break; case 'd': db_name = optarg; break; case 'l': log_path = optarg; break; case 'q': { u_int64_t factor = u_int64_t (1024) * 1024 * 1024; char f = optarg[strlen (optarg) - 1]; if (!isdigit (f)) optarg[strlen (optarg) - 1] = 0; bool ok = convertint (optarg, "a); if (!ok) usage (); switch (f) { case 'b': factor = 1; break; case 'K': factor = 1024; break; case 'M': factor = 1024 * 1024; break; case 'G': factor = u_int64_t (1024) * 1024 * 1024; break; default: if (!isdigit (f)) fatal ("Unknown conversion factor '%c'\n", f); } quota *= factor; } break; case 'S': dbsock = optarg; break; default: usage (); } if (do_daemonize) { warn << "starting daemonized\n"; daemonize (); } warn << "db path: " << db_name << "\n"; if (log_path) warn << "log path: " << log_path << "\n"; warn << "db socket: " << dbsock << "\n"; dbm = New dbmanager (db_name, log_path); sigcb (SIGHUP, wrap (&halt)); sigcb (SIGINT, wrap (&halt)); sigcb (SIGTERM, wrap (&halt)); sigcb (SIGUSR1, wrap (&toggle_iotime)); bzero (&master_metadata, sizeof (master_metadata)); master_metadata.data = strdup ("MASTER_INFO"); master_metadata.size = strlen ("MASTER_INFO"); //setup the asrv listen_unix (dbsock, dbm); amain ();}// vim: foldmethod=marker
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?