diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-08-01 19:20:54 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2013-08-02 10:48:54 +0300 |
commit | 73f605f76d82aec40a7f1bbd309e2097d9abfd42 (patch) | |
tree | 5820713d17efcb482a8801f4f805b0ae121903f7 | |
parent | d78a58be5fa2385987a3141ccbe942107332e677 (diff) | |
download | vmod-tbf-73f605f76d82aec40a7f1bbd309e2097d9abfd42.tar.gz vmod-tbf-73f605f76d82aec40a7f1bbd309e2097d9abfd42.tar.bz2 |
Switch to CDB environment.
* configure.ac: Version 0.99.91
* src/tbf.c (dbdir): New static.
(tbf_set_db_name): Remove.
(tbf_set_db_dir): New function.
(tbf_open): Rename the parameter and related variables.
Create a CDB environment and the database in it.
(vmod_open): Change semantics of the first argument.
* src/vmod-tbf.3: Update.
* tests/Makefile.am (distclean-local): New rule, instead of
DISTCLEANFILES.
* tests/test00.vtc: Update call to tbf.open.
* tests/test01.vtc: Likewise.
* tests/test02.vtc: Likewise.
* tests/test03.vtc: Likewise.
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | src/tbf.c | 212 | ||||
-rw-r--r-- | src/vmod-tbf.3 | 32 | ||||
-rw-r--r-- | tests/Makefile.am | 4 | ||||
-rw-r--r-- | tests/test00.vtc | 2 | ||||
-rw-r--r-- | tests/test01.vtc | 2 | ||||
-rw-r--r-- | tests/test02.vtc | 2 | ||||
-rw-r--r-- | tests/test03.vtc | 2 |
8 files changed, 175 insertions, 83 deletions
diff --git a/configure.ac b/configure.ac index 9c228f6..4ca4e6f 100644 --- a/configure.ac +++ b/configure.ac @@ -15,5 +15,5 @@ # along with vmod-tbf. If not, see <http://www.gnu.org/licenses/>. AC_PREREQ(2.69) -AC_INIT([vmod-tbf], 0.99.90, [gray@gnu.org]) +AC_INIT([vmod-tbf], 0.99.91, [gray@gnu.org]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_MACRO_DIR([m4]) @@ -21,4 +21,5 @@ #include <syslog.h> #include <inttypes.h> +#include <sys/stat.h> #include <db.h> #include "vrt.h" @@ -42,5 +43,11 @@ debugprt(const char *fmt, ...) #endif +#define DEFDBNAME "tbf.bdb" +#define DEFOPENPARAMS "truncate" +#define DBFILEMODE 0640 + +static char *dbdir; static char *dbname; +static DB_ENV *dbenv; static DB *db; static uint64_t autosync_max; @@ -49,5 +56,4 @@ static int tbf_disabled; static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; -#define DBFILEMODE 0640 @@ -123,33 +129,34 @@ keylock_remove_safe(struct keylock *kp) static void -tbf_set_db_name(const char *file_name) +tbf_set_db_dir(const char *dir) { - if (dbname) - free(dbname); - dbname = strdup(file_name); - if (!dbname) - abort(); + if (dbdir) + free(dbdir); + dbdir = strdup(dir); + AN(dbdir); } -struct mode_kw { - char *mkw_str; - int mkw_len; - int mkw_tok; +struct param_kw { + char *pkw_str; + int pkw_len; + int pkw_tok; }; enum { - MKW_TRUNCATE, - MKW_MODE, - MKW_SYNC, - MKW_DEBUG, + PKW_TRUNCATE, + PKW_MODE, + PKW_SYNC, + PKW_DEBUG, + PKW_DBNAME }; -static struct mode_kw mode_kw_tab[] = { +static struct param_kw param_kw_tab[] = { #define S(s) #s, sizeof(#s)-1 - { S(truncate), MKW_TRUNCATE }, - { S(trunc), MKW_TRUNCATE }, - { S(mode=), MKW_MODE }, - { S(sync=), MKW_SYNC }, - { S(debug=), MKW_DEBUG }, + { S(truncate), PKW_TRUNCATE }, + { S(trunc), PKW_TRUNCATE }, + { S(mode=), PKW_MODE }, + { S(sync=), PKW_SYNC }, + { S(debug=), PKW_DEBUG }, + { S(dbname=), PKW_DBNAME }, { NULL } #undef S @@ -157,105 +164,174 @@ static struct mode_kw mode_kw_tab[] = { static void -tbf_open(const char *mode) +tbf_open(const char *params) { int rc; - int flags = DB_CREATE|DB_THREAD; int filemode = DBFILEMODE; uint64_t n; char *p; + struct stat st; + int truncate = 0; - if (!dbname) - tbf_set_db_name(LOCALSTATEDIR "/tbf.db"); - - rc = db_create(&db, NULL, 0); - if (rc) { - syslog(LOG_DAEMON|LOG_ERR, "cannot create db struct"); - return; + if (!dbdir) { + dbdir = strdup(LOCALSTATEDIR "/vmod-tbf"); + AN(dbdir); } - - while (*mode) { - struct mode_kw *mkw; + if (!dbname) { + dbname = strdup(DEFDBNAME); + AN(dbname); + } + + while (*params) { + struct param_kw *pkw; - for (mkw = mode_kw_tab; mkw->mkw_str; mkw++) { - if (strncmp(mode, mkw->mkw_str, mkw->mkw_len) == 0) + for (pkw = param_kw_tab; pkw->pkw_str; pkw++) { + if (strncmp(params, pkw->pkw_str, pkw->pkw_len) == 0) break; } - if (!mkw->mkw_str) { - syslog(LOG_DAEMON|LOG_ERR, "invalid keyword %s", mode); + if (!pkw->pkw_str) { + syslog(LOG_DAEMON|LOG_ERR, "invalid keyword %s", params); break; } - mode += mkw->mkw_len; + params += pkw->pkw_len; - switch (mkw->mkw_tok) { - case MKW_TRUNCATE: - flags |= DB_TRUNCATE; + switch (pkw->pkw_tok) { + case PKW_TRUNCATE: + truncate = 1; break; - case MKW_MODE: + case PKW_MODE: errno = 0; - n = strtoul(mode, &p, 8); + n = strtoul(params, &p, 8); if (errno || (n & ~0777) || !(*p == 0 || *p == ';')) { syslog(LOG_DAEMON|LOG_ERR, "invalid file mode near %s", p); - mode += strlen(mode); + params += strlen(params); } else { filemode = n; - mode = p; + params = p; } break; - case MKW_SYNC: + case PKW_SYNC: errno = 0; - n = strtoul(mode, &p, 10); + n = strtoul(params, &p, 10); if (errno || !(*p == 0 || *p == ';')) { syslog(LOG_DAEMON|LOG_ERR, "invalid count near %s", p); - mode += strlen(mode); + params += strlen(params); } else { autosync_max = n; autosync_count = 0; - mode = p; + params = p; } break; - case MKW_DEBUG: + case PKW_DEBUG: errno = 0; - n = strtoul(mode, &p, 10); + n = strtoul(params, &p, 10); if (errno || !(*p == 0 || *p == ';')) { syslog(LOG_DAEMON|LOG_ERR, "invalid debug level near %s", p); - mode += strlen(mode); + params += strlen(params); } else { debug_level = n; - mode = p; - } + params = p; + } + break; + + case PKW_DBNAME: + if (dbname) + free(dbname); + n = strcspn(params, ";"); + dbname = malloc(n + 1); + AN(dbname); + memcpy(dbname, params, n); + dbname[n] = 0; + params += n; + break; } - if (*mode == 0) + if (*params == 0) break; - else if (*mode == ';') - mode++; + else if (*params == ';') + params++; else { syslog(LOG_DAEMON|LOG_ERR, - "expected ';' near %s", mode); + "expected ';' near %s", params); break; } } - debug(1, ("opening database %s", dbname)); - rc = db->open(db, NULL, dbname, NULL, DB_HASH, flags, filemode); + debug(1, ("opening database %s/%s", dbdir, dbname)); + + if (rc = db_env_create(&dbenv, 0)) { + syslog(LOG_DAEMON|LOG_ERR, "cannot create db environment: %s", + db_strerror(rc)); + return; + } + + if (stat(dbdir, &st)) { + if (errno == ENOENT) { + if (mkdir(dbdir, + filemode | 0100 | + ((filemode & 0060) ? 0010 : 0) | + ((filemode & 0006) ? 0001 : 0))) { + syslog(LOG_DAEMON|LOG_ERR, + "cannot create db environment directory %s: %m", + dbdir); + } + } else { + syslog(LOG_DAEMON|LOG_ERR, + "cannot stat db environment directory %s: %m", + dbdir); + return; + } + } else if (!S_ISDIR(st.st_mode)) { + syslog(LOG_DAEMON|LOG_ERR, "%s is not a directory", + dbdir); + return; + } + + rc = dbenv->open(dbenv, dbdir, + DB_THREAD | DB_CREATE | DB_INIT_MPOOL | DB_INIT_CDB, + 0); if (rc) { - syslog(LOG_DAEMON|LOG_ERR, "cannot open %s: %s", + syslog(LOG_DAEMON|LOG_ERR, "cannot open db environment %s: %s", + dbdir, db_strerror(rc)); + tbf_disabled = 1; + return; + } + + rc = db_create(&db, dbenv, 0); + if (rc) { + syslog(LOG_DAEMON|LOG_ERR, "cannot create db struct"); + return; + } + + rc = db->open(db, NULL, dbname, NULL, DB_HASH, + DB_THREAD | DB_CREATE, filemode); + if (rc) { + syslog(LOG_DAEMON|LOG_ERR, "cannot open database %s: %s", dbname, db_strerror (rc)); db->close(db, 0); db = NULL; + dbenv->close(dbenv, 0); + dbenv = NULL; tbf_disabled = 1; } + + if (truncate) { + rc = db->truncate(db, NULL, NULL, 0); + if (rc) + syslog(LOG_DAEMON|LOG_WARNING, + "failed to truncate database %s: %s", + dbname, db_strerror(rc)); + } } static DB * -tbf_open_safe(const char *mode) +tbf_open_safe(const char *params) { if (tbf_disabled) @@ -263,5 +339,5 @@ tbf_open_safe(const char *mode) pthread_mutex_lock(&mutex); if (!db) - tbf_open(mode ? mode : "truncate"); + tbf_open(params ? params : DEFOPENPARAMS); pthread_mutex_unlock(&mutex); return db; @@ -276,5 +352,5 @@ tbf_init(struct vmod_priv *priv, const struct VCL_conf *vclconf) void -vmod_open(struct sess *sp, const char *file_name, const char *mode) +vmod_open(struct sess *sp, const char *dir, const char *params) { if (db) { @@ -282,6 +358,6 @@ vmod_open(struct sess *sp, const char *file_name, const char *mode) return; } - tbf_set_db_name(file_name); - tbf_open_safe(mode); + tbf_set_db_dir(dir); + tbf_open_safe(params); } @@ -289,10 +365,14 @@ void vmod_close(struct sess *sp) { + pthread_mutex_lock(&mutex); if (db) { debug(1, ("closing database %s", dbname)); db->close(db, 0); db = NULL; + dbenv->close(dbenv, 0); + dbenv = NULL; tbf_disabled = 0; } + pthread_mutex_unlock(&mutex); } diff --git a/src/vmod-tbf.3 b/src/vmod-tbf.3 index cf12ea7..bd7b233 100644 --- a/src/vmod-tbf.3 +++ b/src/vmod-tbf.3 @@ -14,5 +14,5 @@ .\" You should have received a copy of the GNU General Public License .\" along with vmod-tbf. If not, see <http://www.gnu.org/licenses/>. -.TH VMOD-TBF 1 "July 23, 2013" "VMOD-TBF" "User Reference" +.TH VMOD-TBF 1 "August 2, 2013" "VMOD-TBF" "User Reference" .SH NAME vmod-tbf \- token bucket filtering for Varnish @@ -20,5 +20,5 @@ vmod-tbf \- token bucket filtering for Varnish .B import tbf; -.BI "VOID tbf.open(STRING " dbfile ", STRING " params ");" +.BI "VOID tbf.open(STRING " dbdir ", STRING " params ");" .B VOID tbf.close(); @@ -109,11 +109,15 @@ sub vcl_recv { .SS Storage .PP -Buckets are kept in a Berkeley DB file. The \fBtbf.open\fR function -controls its location and permissions. The \fBdbfile\fR argument -supplies the full pathname to the file. The \fBparams\fR argument is -a semicolon separated list of the following parameters: +Buckets are kept in a Berkeley database file. The \fBtbf.open\fR function +controls its location and permissions. The \fBdbdir\fR argument +supplies the full pathname to the directory where the database is +located. The \fBparams\fR argument is a semicolon separated list of +the following parameters: +.TP +.BI dbname= NAME +Sets the name of the database file. Default is \fBtbf.bdb\fR. .TP .BR truncate " or " trunc -Truncate the file if it already exists. +Truncate the database if it already exists. .TP .BI mode= OCT @@ -142,8 +146,14 @@ writable for the user \fBVarnish\fR runs as. .PP Unless the \fBtbf.open\fR function was called, both \fBtbf.rate\fR and -\fBtbf.check\fR will attempt to use the file \fIlocalstatedir\fB/tbf.db\fR, -where \fIlocalstatedir\fR is the directory for modifiable -single-machine data, which is set when configuring the package -(e.g. \fB/var/run/tbf\fR or the like). +\fBtbf.check\fR will attempt to use the database located in +\fIlocalstatedir\fB/vmod-tbf\fR, where \fIlocalstatedir\fR is the +directory for modifiable single-machine data, which is set when +configuring the package (e.g. \fB/var/run\fR or the like). +.PP +If the database directory does not exist, \fBtbf.open\fR will attempt +to create it, deducing its mode from the database file mode (see the +\fBmode=\fR parameter above) by setting executable +bit in each triplet that has read or write bit set (e.g. \fB640\fR +will become \fB750\fR). .PP The \fBtbf.close\fR function flushes the data and closes the database. diff --git a/tests/Makefile.am b/tests/Makefile.am index 383f18a..4790115 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -7,5 +7,7 @@ VMOD_TESTS = \ EXTRA_DIST=$(VMOD_TESTS) -DISTCLEANFILES=tbf.db +distclean-local: + rm -fr tbf + check: cd $(abs_srcdir); \ diff --git a/tests/test00.vtc b/tests/test00.vtc index 10f99ca..f69f5ed 100644 --- a/tests/test00.vtc +++ b/tests/test00.vtc @@ -9,5 +9,5 @@ varnish v1 -vcl+backend { import tbf from "${vmod_topbuild}/src/.libs/libvmod_tbf.so"; sub vcl_init { - tbf.open("${vmod_topbuild}/tests/tbf.db", "truncate"); + tbf.open("${vmod_topbuild}/tests/tbf", "truncate"); } sub vcl_fini { diff --git a/tests/test01.vtc b/tests/test01.vtc index ad6f7d1..39eb4c3 100644 --- a/tests/test01.vtc +++ b/tests/test01.vtc @@ -9,5 +9,5 @@ varnish v1 -vcl+backend { import tbf from "${vmod_topbuild}/src/.libs/libvmod_tbf.so"; sub vcl_init { - tbf.open("${vmod_topbuild}/tests/tbf.db", "trunc"); + tbf.open("${vmod_topbuild}/tests/tbf", "trunc"); } sub vcl_fini { diff --git a/tests/test02.vtc b/tests/test02.vtc index b957181..8df6730 100644 --- a/tests/test02.vtc +++ b/tests/test02.vtc @@ -9,5 +9,5 @@ varnish v1 -vcl+backend { import tbf from "${vmod_topbuild}/src/.libs/libvmod_tbf.so"; sub vcl_init { - tbf.open("${vmod_topbuild}/tests/tbf.db", "truncate"); + tbf.open("${vmod_topbuild}/tests/tbf", "truncate"); } sub vcl_fini { diff --git a/tests/test03.vtc b/tests/test03.vtc index 5ffba9a..aa23da4 100644 --- a/tests/test03.vtc +++ b/tests/test03.vtc @@ -9,5 +9,5 @@ varnish v1 -vcl+backend { import tbf from "${vmod_topbuild}/src/.libs/libvmod_tbf.so"; sub vcl_init { - tbf.open("${vmod_topbuild}/tests/tbf.db", "trunc"); + tbf.open("${vmod_topbuild}/tests/tbf", "trunc"); } sub vcl_fini { |