Updated to current mtstdopen interface.
[statserve.git] / dbsrc.c
... / ...
CommitLineData
1#include <stdlib.h>
2#include <stdio.h>
3#include <db.h>
4#include <string.h>
5#include <ashd/utils.h>
6#include <ashd/log.h>
7#include <time.h>
8
9#include "statserve.h"
10
11struct dbsrc {
12 char *envnm;
13 DB_ENV *env;
14 DB *db;
15 time_t lastcp, lastar;
16};
17
18int dbpagesize = 0;
19
20static struct fileinfo dbserve(struct source *src, char *nm)
21{
22 struct dbsrc *d = src->pdata;
23 int i, ret, ver;
24 DBT k, v;
25 size_t sz;
26 void *hp, *p;
27 struct fileinfo retf;
28
29 memset(&k, 0, sizeof(k));
30 memset(&v, 0, sizeof(v));
31 k.size = strlen(k.data = nm);
32 v.flags = DB_DBT_MALLOC;
33 do {
34 ret = d->db->get(d->db, NULL, &k, &v, 0);
35 } while(ret == DB_LOCK_DEADLOCK);
36 if(ret == 0) {
37 hp = v.data;
38 sz = v.size;
39 if(sz < 1)
40 goto corrupt;
41 ver = *(uint8_t *)hp;
42 hp++; sz--;
43 if(ver == 1) {
44 if(sz < 8)
45 goto corrupt;
46 memset(&retf, 0, sizeof(retf));
47 for(i = 0, retf.mtime = 0; i < 8; i++) {
48 retf.mtime = (retf.mtime << 8) | (*(uint8_t *)hp);
49 hp++; sz--;
50 }
51 if(retf.mtime < 0)
52 goto corrupt;
53 if((p = memchr(hp, 0, sz)) == NULL)
54 goto corrupt;
55 p++;
56 if(p - hp > 64)
57 goto corrupt;
58 strcpy(retf.ctype, hp);
59 sz -= p - hp; hp = p;
60 retf.data = memcpy(smalloc(retf.sz = sz), hp, sz);
61 free(v.data);
62 return(retf);
63 } else {
64 goto corrupt;
65 }
66 } else if(ret == DB_NOTFOUND) {
67 return((struct fileinfo){});
68 } else {
69 flog(LOG_ERR, "could not read value of %s in %s: %s", nm, d->envnm, db_strerror(ret));
70 return((struct fileinfo){});
71 }
72 goto out;
73
74corrupt:
75 flog(LOG_ERR, "entry for %s in %s is corrupted", nm, d->envnm);
76 free(v.data);
77 return((struct fileinfo){});
78out:;
79}
80
81static void dbidle(struct source *src)
82{
83 struct dbsrc *d = src->pdata;
84 time_t now;
85 int ret;
86 char **files;
87
88 now = time(NULL);
89 if(now - d->lastcp > 1800) {
90 d->lastcp = now;
91 if((ret = d->env->txn_checkpoint(d->env, 5000, 0, 0)) != 0) {
92 flog(LOG_ERR, "could not make db checkpoint in %s: %s", d->envnm, db_strerror(ret));
93 }
94 }
95 if(now - d->lastar > 7200) {
96 d->lastar = now;
97 files = NULL;
98 if((ret = d->env->log_archive(d->env, &files, DB_ARCH_REMOVE)) != 0) {
99 flog(LOG_ERR, "could not archive log files in %s: %s", d->envnm, db_strerror(ret));
100 }
101 if(files != NULL)
102 free(files);
103 }
104}
105
106static void dbclose(struct source *src)
107{
108 struct dbsrc *d = src->pdata;
109
110 d->db->close(d->db, 0);
111 d->env->close(d->env, 0);
112}
113
114static void enverror(const DB_ENV *env, const char *prefix, const char *msg)
115{
116 flog(LOG_ERR, "dbsource: environment error: %s", msg);
117}
118
119struct source *mkdbsrc(char *path, char *envpath)
120{
121 struct source *src;
122 struct dbsrc *d;
123 char *p;
124 int ret;
125
126 omalloc(src);
127 src->serve = dbserve;
128 src->idle = dbidle;
129 src->close = dbclose;
130 src->pdata = omalloc(d);
131 if((ret = db_env_create(&d->env, 0)) != 0) {
132 flog(LOG_ERR, "could not create bdb environment: %s", db_strerror(ret));
133 goto fail;
134 }
135 if(envpath) {
136 d->envnm = sstrdup(envpath);
137 } else {
138 d->envnm = sstrdup(path);
139 if((p = strrchr(d->envnm, '/')) == NULL) {
140 free(d->envnm);
141 d->envnm = sstrdup(".");
142 } else {
143 *p = 0;
144 }
145 }
146 if((ret = d->env->open(d->env, d->envnm, DB_CREATE | DB_INIT_MPOOL | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN, 0666)) != 0) {
147 flog(LOG_ERR, "could not open bdb environment: %s", db_strerror(ret));
148 goto fail;
149 }
150 d->env->set_lk_detect(d->env, DB_LOCK_RANDOM);
151 d->env->set_errcall(d->env, enverror);
152 if((ret = db_create(&d->db, d->env, 0)) != 0) {
153 flog(LOG_ERR, "could not create bdb database: %s", db_strerror(ret));
154 goto fail;
155 }
156 if(dbpagesize) {
157 if((ret = d->db->set_pagesize(d->db, dbpagesize)) != 0) {
158 flog(LOG_ERR, "could not set bdb page size (to %i): %s", dbpagesize, db_strerror(ret));
159 goto fail;
160 }
161 }
162 if((ret = d->db->open(d->db, NULL, path, NULL, DB_HASH, DB_AUTO_COMMIT | DB_CREATE, 0666)) != 0) {
163 flog(LOG_ERR, "could not open bdb database: %s", db_strerror(ret));
164 goto fail;
165 }
166 return(src);
167
168fail:
169 if(d->db)
170 d->db->close(d->db, 0);
171 if(d->env)
172 d->env->close(d->env, 0);
173 free(d);
174 free(src);
175 return(NULL);
176}