Wed Apr 6 11:29:44 2011

Asterisk developer's documentation


db.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief ASTdb Management
00022  *
00023  * \author Mark Spencer <markster@digium.com> 
00024  *
00025  * \note DB3 is licensed under Sleepycat Public License and is thus incompatible
00026  * with GPL.  To avoid having to make another exception (and complicate 
00027  * licensing even further) we elect to use DB1 which is BSD licensed 
00028  */
00029 
00030 #include "asterisk.h"
00031 
00032 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 286112 $")
00033 
00034 #include "asterisk/_private.h"
00035 #include "asterisk/paths.h"   /* use ast_config_AST_DB */
00036 #include <sys/time.h>
00037 #include <signal.h>
00038 #include <dirent.h>
00039 
00040 #include "asterisk/channel.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/app.h"
00043 #include "asterisk/dsp.h"
00044 #include "asterisk/astdb.h"
00045 #include "asterisk/cli.h"
00046 #include "asterisk/utils.h"
00047 #include "asterisk/lock.h"
00048 #include "asterisk/manager.h"
00049 #include "db1-ast/include/db.h"
00050 
00051 /*** DOCUMENTATION
00052    <manager name="DBGet" language="en_US">
00053       <synopsis>
00054          Get DB Entry.
00055       </synopsis>
00056       <syntax>
00057          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00058          <parameter name="Family" required="true" />
00059          <parameter name="Key" required="true" />
00060       </syntax>
00061       <description>
00062       </description>
00063    </manager>
00064    <manager name="DBPut" language="en_US">
00065       <synopsis>
00066          Put DB entry.
00067       </synopsis>
00068       <syntax>
00069          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00070          <parameter name="Family" required="true" />
00071          <parameter name="Key" required="true" />
00072          <parameter name="Val" />
00073       </syntax>
00074       <description>
00075       </description>
00076    </manager>
00077    <manager name="DBDel" language="en_US">
00078       <synopsis>
00079          Delete DB entry.
00080       </synopsis>
00081       <syntax>
00082          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00083          <parameter name="Family" required="true" />
00084          <parameter name="Key" required="true" />
00085       </syntax>
00086       <description>
00087       </description>
00088    </manager>
00089    <manager name="DBDelTree" language="en_US">
00090       <synopsis>
00091          Delete DB Tree.
00092       </synopsis>
00093       <syntax>
00094          <xi:include xpointer="xpointer(/docs/manager[@name='Login']/syntax/parameter[@name='ActionID'])" />
00095          <parameter name="Family" required="true" />
00096          <parameter name="Key" />
00097       </syntax>
00098       <description>
00099       </description>
00100    </manager>
00101  ***/
00102 
00103 static DB *astdb;
00104 AST_MUTEX_DEFINE_STATIC(dblock);
00105 static ast_cond_t dbcond;
00106 
00107 static void db_sync(void);
00108 
00109 static int dbinit(void) 
00110 {
00111    if (!astdb && !(astdb = dbopen(ast_config_AST_DB, O_CREAT | O_RDWR, AST_FILE_MODE, DB_BTREE, NULL))) {
00112       ast_log(LOG_WARNING, "Unable to open Asterisk database '%s': %s\n", ast_config_AST_DB, strerror(errno));
00113       return -1;
00114    }
00115    return 0;
00116 }
00117 
00118 
00119 static inline int keymatch(const char *key, const char *prefix)
00120 {
00121    int preflen = strlen(prefix);
00122    if (!preflen)
00123       return 1;
00124    if (!strcasecmp(key, prefix))
00125       return 1;
00126    if ((strlen(key) > preflen) && !strncasecmp(key, prefix, preflen)) {
00127       if (key[preflen] == '/')
00128          return 1;
00129    }
00130    return 0;
00131 }
00132 
00133 static inline int subkeymatch(const char *key, const char *suffix)
00134 {
00135    int suffixlen = strlen(suffix);
00136    if (suffixlen) {
00137       const char *subkey = key + strlen(key) - suffixlen;
00138       if (subkey < key)
00139          return 0;
00140       if (!strcasecmp(subkey, suffix))
00141          return 1;
00142    }
00143    return 0;
00144 }
00145 
00146 int ast_db_deltree(const char *family, const char *keytree)
00147 {
00148    char prefix[256];
00149    DBT key, data;
00150    char *keys;
00151    int res;
00152    int pass;
00153    int counter = 0;
00154    
00155    if (family) {
00156       if (keytree) {
00157          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00158       } else {
00159          snprintf(prefix, sizeof(prefix), "/%s", family);
00160       }
00161    } else if (keytree) {
00162       return -1;
00163    } else {
00164       prefix[0] = '\0';
00165    }
00166    
00167    ast_mutex_lock(&dblock);
00168    if (dbinit()) {
00169       ast_mutex_unlock(&dblock);
00170       return -1;
00171    }
00172    
00173    memset(&key, 0, sizeof(key));
00174    memset(&data, 0, sizeof(data));
00175    pass = 0;
00176    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00177       if (key.size) {
00178          keys = key.data;
00179          keys[key.size - 1] = '\0';
00180       } else {
00181          keys = "<bad key>";
00182       }
00183       if (keymatch(keys, prefix)) {
00184          astdb->del(astdb, &key, 0);
00185          counter++;
00186       }
00187    }
00188    db_sync();
00189    ast_mutex_unlock(&dblock);
00190    return counter;
00191 }
00192 
00193 int ast_db_put(const char *family, const char *keys, const char *value)
00194 {
00195    char fullkey[256];
00196    DBT key, data;
00197    int res, fullkeylen;
00198 
00199    ast_mutex_lock(&dblock);
00200    if (dbinit()) {
00201       ast_mutex_unlock(&dblock);
00202       return -1;
00203    }
00204 
00205    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00206    memset(&key, 0, sizeof(key));
00207    memset(&data, 0, sizeof(data));
00208    key.data = fullkey;
00209    key.size = fullkeylen + 1;
00210    data.data = (char *) value;
00211    data.size = strlen(value) + 1;
00212    res = astdb->put(astdb, &key, &data, 0);
00213    db_sync();
00214    ast_mutex_unlock(&dblock);
00215    if (res)
00216       ast_log(LOG_WARNING, "Unable to put value '%s' for key '%s' in family '%s'\n", value, keys, family);
00217    return res;
00218 }
00219 
00220 int ast_db_get(const char *family, const char *keys, char *value, int valuelen)
00221 {
00222    char fullkey[256] = "";
00223    DBT key, data;
00224    int res, fullkeylen;
00225 
00226    ast_mutex_lock(&dblock);
00227    if (dbinit()) {
00228       ast_mutex_unlock(&dblock);
00229       return -1;
00230    }
00231 
00232    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00233    memset(&key, 0, sizeof(key));
00234    memset(&data, 0, sizeof(data));
00235    memset(value, 0, valuelen);
00236    key.data = fullkey;
00237    key.size = fullkeylen + 1;
00238 
00239    res = astdb->get(astdb, &key, &data, 0);
00240 
00241    /* Be sure to NULL terminate our data either way */
00242    if (res) {
00243       ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
00244    } else {
00245 #if 0
00246       printf("Got value of size %d\n", data.size);
00247 #endif
00248       if (data.size) {
00249          ((char *)data.data)[data.size - 1] = '\0';
00250          /* Make sure that we don't write too much to the dst pointer or we don't read too much from the source pointer */
00251          ast_copy_string(value, data.data, (valuelen > data.size) ? data.size : valuelen);
00252       } else {
00253          ast_log(LOG_NOTICE, "Strange, empty value for /%s/%s\n", family, keys);
00254       }
00255    }
00256 
00257    /* Data is not fully isolated for concurrency, so the lock must be extended
00258     * to after the copy to the output buffer. */
00259    ast_mutex_unlock(&dblock);
00260 
00261    return res;
00262 }
00263 
00264 int ast_db_del(const char *family, const char *keys)
00265 {
00266    char fullkey[256];
00267    DBT key;
00268    int res, fullkeylen;
00269 
00270    ast_mutex_lock(&dblock);
00271    if (dbinit()) {
00272       ast_mutex_unlock(&dblock);
00273       return -1;
00274    }
00275    
00276    fullkeylen = snprintf(fullkey, sizeof(fullkey), "/%s/%s", family, keys);
00277    memset(&key, 0, sizeof(key));
00278    key.data = fullkey;
00279    key.size = fullkeylen + 1;
00280    
00281    res = astdb->del(astdb, &key, 0);
00282    db_sync();
00283    
00284    ast_mutex_unlock(&dblock);
00285 
00286    if (res) {
00287       ast_debug(1, "Unable to find key '%s' in family '%s'\n", keys, family);
00288    }
00289    return res;
00290 }
00291 
00292 static char *handle_cli_database_put(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00293 {
00294    int res;
00295 
00296    switch (cmd) {
00297    case CLI_INIT:
00298       e->command = "database put";
00299       e->usage =
00300          "Usage: database put <family> <key> <value>\n"
00301          "       Adds or updates an entry in the Asterisk database for\n"
00302          "       a given family, key, and value.\n";
00303       return NULL;
00304    case CLI_GENERATE:
00305       return NULL;
00306    }
00307 
00308    if (a->argc != 5)
00309       return CLI_SHOWUSAGE;
00310    res = ast_db_put(a->argv[2], a->argv[3], a->argv[4]);
00311    if (res)  {
00312       ast_cli(a->fd, "Failed to update entry\n");
00313    } else {
00314       ast_cli(a->fd, "Updated database successfully\n");
00315    }
00316    return CLI_SUCCESS;
00317 }
00318 
00319 static char *handle_cli_database_get(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00320 {
00321    int res;
00322    char tmp[256];
00323 
00324    switch (cmd) {
00325    case CLI_INIT:
00326       e->command = "database get";
00327       e->usage =
00328          "Usage: database get <family> <key>\n"
00329          "       Retrieves an entry in the Asterisk database for a given\n"
00330          "       family and key.\n";
00331       return NULL;
00332    case CLI_GENERATE:
00333       return NULL;
00334    }
00335 
00336    if (a->argc != 4)
00337       return CLI_SHOWUSAGE;
00338    res = ast_db_get(a->argv[2], a->argv[3], tmp, sizeof(tmp));
00339    if (res) {
00340       ast_cli(a->fd, "Database entry not found.\n");
00341    } else {
00342       ast_cli(a->fd, "Value: %s\n", tmp);
00343    }
00344    return CLI_SUCCESS;
00345 }
00346 
00347 static char *handle_cli_database_del(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00348 {
00349    int res;
00350 
00351    switch (cmd) {
00352    case CLI_INIT:
00353       e->command = "database del";
00354       e->usage =
00355          "Usage: database del <family> <key>\n"
00356          "       Deletes an entry in the Asterisk database for a given\n"
00357          "       family and key.\n";
00358       return NULL;
00359    case CLI_GENERATE:
00360       return NULL;
00361    }
00362 
00363    if (a->argc != 4)
00364       return CLI_SHOWUSAGE;
00365    res = ast_db_del(a->argv[2], a->argv[3]);
00366    if (res) {
00367       ast_cli(a->fd, "Database entry does not exist.\n");
00368    } else {
00369       ast_cli(a->fd, "Database entry removed.\n");
00370    }
00371    return CLI_SUCCESS;
00372 }
00373 
00374 static char *handle_cli_database_deltree(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00375 {
00376    int res;
00377 
00378    switch (cmd) {
00379    case CLI_INIT:
00380       e->command = "database deltree";
00381       e->usage =
00382          "Usage: database deltree <family> [keytree]\n"
00383          "       Deletes a family or specific keytree within a family\n"
00384          "       in the Asterisk database.\n";
00385       return NULL;
00386    case CLI_GENERATE:
00387       return NULL;
00388    }
00389 
00390    if ((a->argc < 3) || (a->argc > 4))
00391       return CLI_SHOWUSAGE;
00392    if (a->argc == 4) {
00393       res = ast_db_deltree(a->argv[2], a->argv[3]);
00394    } else {
00395       res = ast_db_deltree(a->argv[2], NULL);
00396    }
00397    if (res < 0) {
00398       ast_cli(a->fd, "Database entries do not exist.\n");
00399    } else {
00400       ast_cli(a->fd, "%d database entries removed.\n",res);
00401    }
00402    return CLI_SUCCESS;
00403 }
00404 
00405 static char *handle_cli_database_show(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00406 {
00407    char prefix[256];
00408    DBT key, data;
00409    char *keys, *values;
00410    int res;
00411    int pass;
00412    int counter = 0;
00413 
00414    switch (cmd) {
00415    case CLI_INIT:
00416       e->command = "database show";
00417       e->usage =
00418          "Usage: database show [family [keytree]]\n"
00419          "       Shows Asterisk database contents, optionally restricted\n"
00420          "       to a given family, or family and keytree.\n";
00421       return NULL;
00422    case CLI_GENERATE:
00423       return NULL;
00424    }
00425 
00426    if (a->argc == 4) {
00427       /* Family and key tree */
00428       snprintf(prefix, sizeof(prefix), "/%s/%s", a->argv[2], a->argv[3]);
00429    } else if (a->argc == 3) {
00430       /* Family only */
00431       snprintf(prefix, sizeof(prefix), "/%s", a->argv[2]);
00432    } else if (a->argc == 2) {
00433       /* Neither */
00434       prefix[0] = '\0';
00435    } else {
00436       return CLI_SHOWUSAGE;
00437    }
00438    ast_mutex_lock(&dblock);
00439    if (dbinit()) {
00440       ast_mutex_unlock(&dblock);
00441       ast_cli(a->fd, "Database unavailable\n");
00442       return CLI_SUCCESS;  
00443    }
00444    memset(&key, 0, sizeof(key));
00445    memset(&data, 0, sizeof(data));
00446    pass = 0;
00447    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00448       if (key.size) {
00449          keys = key.data;
00450          keys[key.size - 1] = '\0';
00451       } else {
00452          keys = "<bad key>";
00453       }
00454       if (data.size) {
00455          values = data.data;
00456          values[data.size - 1]='\0';
00457       } else {
00458          values = "<bad value>";
00459       }
00460       if (keymatch(keys, prefix)) {
00461          ast_cli(a->fd, "%-50s: %-25s\n", keys, values);
00462          counter++;
00463       }
00464    }
00465    ast_mutex_unlock(&dblock);
00466    ast_cli(a->fd, "%d results found.\n", counter);
00467    return CLI_SUCCESS;  
00468 }
00469 
00470 static char *handle_cli_database_showkey(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
00471 {
00472    char suffix[256];
00473    DBT key, data;
00474    char *keys, *values;
00475    int res;
00476    int pass;
00477    int counter = 0;
00478 
00479    switch (cmd) {
00480    case CLI_INIT:
00481       e->command = "database showkey";
00482       e->usage =
00483          "Usage: database showkey <keytree>\n"
00484          "       Shows Asterisk database contents, restricted to a given key.\n";
00485       return NULL;
00486    case CLI_GENERATE:
00487       return NULL;
00488    }
00489 
00490    if (a->argc == 3) {
00491       /* Key only */
00492       snprintf(suffix, sizeof(suffix), "/%s", a->argv[2]);
00493    } else {
00494       return CLI_SHOWUSAGE;
00495    }
00496    ast_mutex_lock(&dblock);
00497    if (dbinit()) {
00498       ast_mutex_unlock(&dblock);
00499       ast_cli(a->fd, "Database unavailable\n");
00500       return CLI_SUCCESS;  
00501    }
00502    memset(&key, 0, sizeof(key));
00503    memset(&data, 0, sizeof(data));
00504    pass = 0;
00505    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00506       if (key.size) {
00507          keys = key.data;
00508          keys[key.size - 1] = '\0';
00509       } else {
00510          keys = "<bad key>";
00511       }
00512       if (data.size) {
00513          values = data.data;
00514          values[data.size - 1]='\0';
00515       } else {
00516          values = "<bad value>";
00517       }
00518       if (subkeymatch(keys, suffix)) {
00519          ast_cli(a->fd, "%-50s: %-25s\n", keys, values);
00520          counter++;
00521       }
00522    }
00523    ast_mutex_unlock(&dblock);
00524    ast_cli(a->fd, "%d results found.\n", counter);
00525    return CLI_SUCCESS;  
00526 }
00527 
00528 struct ast_db_entry *ast_db_gettree(const char *family, const char *keytree)
00529 {
00530    char prefix[256];
00531    DBT key, data;
00532    char *keys, *values;
00533    int values_len;
00534    int res;
00535    int pass;
00536    struct ast_db_entry *last = NULL;
00537    struct ast_db_entry *cur, *ret=NULL;
00538 
00539    if (!ast_strlen_zero(family)) {
00540       if (!ast_strlen_zero(keytree)) {
00541          /* Family and key tree */
00542          snprintf(prefix, sizeof(prefix), "/%s/%s", family, keytree);
00543       } else {
00544          /* Family only */
00545          snprintf(prefix, sizeof(prefix), "/%s", family);
00546       }
00547    } else {
00548       prefix[0] = '\0';
00549    }
00550    ast_mutex_lock(&dblock);
00551    if (dbinit()) {
00552       ast_mutex_unlock(&dblock);
00553       ast_log(LOG_WARNING, "Database unavailable\n");
00554       return NULL;   
00555    }
00556    memset(&key, 0, sizeof(key));
00557    memset(&data, 0, sizeof(data));
00558    pass = 0;
00559    while (!(res = astdb->seq(astdb, &key, &data, pass++ ? R_NEXT : R_FIRST))) {
00560       if (key.size) {
00561          keys = key.data;
00562          keys[key.size - 1] = '\0';
00563       } else {
00564          keys = "<bad key>";
00565       }
00566       if (data.size) {
00567          values = data.data;
00568          values[data.size - 1] = '\0';
00569       } else {
00570          values = "<bad value>";
00571       }
00572       values_len = strlen(values) + 1;
00573       if (keymatch(keys, prefix) && (cur = ast_malloc(sizeof(*cur) + strlen(keys) + 1 + values_len))) {
00574          cur->next = NULL;
00575          cur->key = cur->data + values_len;
00576          strcpy(cur->data, values);
00577          strcpy(cur->key, keys);
00578          if (last) {
00579             last->next = cur;
00580          } else {
00581             ret = cur;
00582          }
00583          last = cur;
00584       }
00585    }
00586    ast_mutex_unlock(&dblock);
00587    return ret; 
00588 }
00589 
00590 void ast_db_freetree(struct ast_db_entry *dbe)
00591 {
00592    struct ast_db_entry *last;
00593    while (dbe) {
00594       last = dbe;
00595       dbe = dbe->next;
00596       ast_free(last);
00597    }
00598 }
00599 
00600 static struct ast_cli_entry cli_database[] = {
00601    AST_CLI_DEFINE(handle_cli_database_show,    "Shows database contents"),
00602    AST_CLI_DEFINE(handle_cli_database_showkey, "Shows database contents"),
00603    AST_CLI_DEFINE(handle_cli_database_get,     "Gets database value"),
00604    AST_CLI_DEFINE(handle_cli_database_put,     "Adds/updates database value"),
00605    AST_CLI_DEFINE(handle_cli_database_del,     "Removes database key/value"),
00606    AST_CLI_DEFINE(handle_cli_database_deltree, "Removes database keytree/values")
00607 };
00608 
00609 static int manager_dbput(struct mansession *s, const struct message *m)
00610 {
00611    const char *family = astman_get_header(m, "Family");
00612    const char *key = astman_get_header(m, "Key");
00613    const char *val = astman_get_header(m, "Val");
00614    int res;
00615 
00616    if (ast_strlen_zero(family)) {
00617       astman_send_error(s, m, "No family specified");
00618       return 0;
00619    }
00620    if (ast_strlen_zero(key)) {
00621       astman_send_error(s, m, "No key specified");
00622       return 0;
00623    }
00624 
00625    res = ast_db_put(family, key, S_OR(val, ""));
00626    if (res) {
00627       astman_send_error(s, m, "Failed to update entry");
00628    } else {
00629       astman_send_ack(s, m, "Updated database successfully");
00630    }
00631    return 0;
00632 }
00633 
00634 static int manager_dbget(struct mansession *s, const struct message *m)
00635 {
00636    const char *id = astman_get_header(m,"ActionID");
00637    char idText[256] = "";
00638    const char *family = astman_get_header(m, "Family");
00639    const char *key = astman_get_header(m, "Key");
00640    char tmp[256];
00641    int res;
00642 
00643    if (ast_strlen_zero(family)) {
00644       astman_send_error(s, m, "No family specified.");
00645       return 0;
00646    }
00647    if (ast_strlen_zero(key)) {
00648       astman_send_error(s, m, "No key specified.");
00649       return 0;
00650    }
00651 
00652    if (!ast_strlen_zero(id))
00653       snprintf(idText, sizeof(idText) ,"ActionID: %s\r\n", id);
00654 
00655    res = ast_db_get(family, key, tmp, sizeof(tmp));
00656    if (res) {
00657       astman_send_error(s, m, "Database entry not found");
00658    } else {
00659       astman_send_ack(s, m, "Result will follow");
00660       astman_append(s, "Event: DBGetResponse\r\n"
00661             "Family: %s\r\n"
00662             "Key: %s\r\n"
00663             "Val: %s\r\n"
00664             "%s"
00665             "\r\n",
00666             family, key, tmp, idText);
00667       astman_append(s, "Event: DBGetComplete\r\n"
00668             "%s"
00669             "\r\n",
00670             idText);
00671    }
00672    return 0;
00673 }
00674 
00675 static int manager_dbdel(struct mansession *s, const struct message *m)
00676 {
00677    const char *family = astman_get_header(m, "Family");
00678    const char *key = astman_get_header(m, "Key");
00679    int res;
00680 
00681    if (ast_strlen_zero(family)) {
00682       astman_send_error(s, m, "No family specified.");
00683       return 0;
00684    }
00685 
00686    if (ast_strlen_zero(key)) {
00687       astman_send_error(s, m, "No key specified.");
00688       return 0;
00689    }
00690 
00691    res = ast_db_del(family, key);
00692    if (res)
00693       astman_send_error(s, m, "Database entry not found");
00694    else
00695       astman_send_ack(s, m, "Key deleted successfully");
00696 
00697    return 0;
00698 }
00699 
00700 static int manager_dbdeltree(struct mansession *s, const struct message *m)
00701 {
00702    const char *family = astman_get_header(m, "Family");
00703    const char *key = astman_get_header(m, "Key");
00704    int res;
00705 
00706    if (ast_strlen_zero(family)) {
00707       astman_send_error(s, m, "No family specified.");
00708       return 0;
00709    }
00710 
00711    if (!ast_strlen_zero(key))
00712       res = ast_db_deltree(family, key);
00713    else
00714       res = ast_db_deltree(family, NULL);
00715 
00716    if (res < 0)
00717       astman_send_error(s, m, "Database entry not found");
00718    else
00719       astman_send_ack(s, m, "Key tree deleted successfully");
00720    
00721    return 0;
00722 }
00723 
00724 /*!
00725  * \internal
00726  * \brief Signal the astdb sync thread to do its thing.
00727  *
00728  * \note dblock is assumed to be held when calling this function.
00729  */
00730 static void db_sync(void)
00731 {
00732    ast_cond_signal(&dbcond);
00733 }
00734 
00735 /*!
00736  * \internal
00737  * \brief astdb sync thread
00738  *
00739  * This thread is in charge of syncing astdb to disk after a change.
00740  * By pushing it off to this thread to take care of, this I/O bound operation
00741  * will not block other threads from performing other critical processing.
00742  * If changes happen rapidly, this thread will also ensure that the sync
00743  * operations are rate limited.
00744  */
00745 static void *db_sync_thread(void *data)
00746 {
00747    ast_mutex_lock(&dblock);
00748    for (;;) {
00749       ast_cond_wait(&dbcond, &dblock);
00750       ast_mutex_unlock(&dblock);
00751       sleep(1);
00752       ast_mutex_lock(&dblock);
00753       astdb->sync(astdb, 0);
00754    }
00755 
00756    return NULL;
00757 }
00758 
00759 int astdb_init(void)
00760 {
00761    pthread_t dont_care;
00762 
00763    ast_cond_init(&dbcond, NULL);
00764    if (ast_pthread_create_background(&dont_care, NULL, db_sync_thread, NULL)) {
00765       return -1;
00766    }
00767 
00768    dbinit();
00769    ast_cli_register_multiple(cli_database, ARRAY_LEN(cli_database));
00770    ast_manager_register_xml("DBGet", EVENT_FLAG_SYSTEM | EVENT_FLAG_REPORTING, manager_dbget);
00771    ast_manager_register_xml("DBPut", EVENT_FLAG_SYSTEM, manager_dbput);
00772    ast_manager_register_xml("DBDel", EVENT_FLAG_SYSTEM, manager_dbdel);
00773    ast_manager_register_xml("DBDelTree", EVENT_FLAG_SYSTEM, manager_dbdeltree);
00774    return 0;
00775 }

Generated on Wed Apr 6 11:29:44 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7