Initial commit.
[statserve.git] / dbsrc.c
CommitLineData
34d725a5
FT
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
18static struct fileinfo dbserve(struct source *src, char *nm)
19{
20 struct dbsrc *d = src->pdata;
21 int i, ret, ver;
22 DBT k, v;
23 size_t sz;
24 void *hp, *p;
25 struct fileinfo retf;
26
27 memset(&k, 0, sizeof(k));
28 memset(&v, 0, sizeof(v));
29 k.size = strlen(k.data = nm);
30 v.flags = DB_DBT_MALLOC;
31 do {
32 ret = d->db->get(d->db, NULL, &k, &v, 0);
33 } while(ret == DB_LOCK_DEADLOCK);
34 if(ret == 0) {
35 hp = v.data;
36 sz = v.size;
37 if(sz < 1)
38 goto corrupt;
39 ver = *(uint8_t *)hp;
40 hp++; sz--;
41 if(ver == 1) {
42 if(sz < 8)
43 goto corrupt;
44 memset(&retf, 0, sizeof(retf));
45 for(i = 0, retf.mtime = 0; i < 8; i++) {
46 retf.mtime = (retf.mtime << 8) | (*(uint8_t *)hp);
47 hp++; sz--;
48 }
49 if(retf.mtime < 0)
50 goto corrupt;
51 if((p = memchr(hp, 0, sz)) == NULL)
52 goto corrupt;
53 p++;
54 if(p - hp > 64)
55 goto corrupt;
56 strcpy(retf.ctype, hp);
57 sz -= p - hp; hp = p;
58 retf.data = memcpy(smalloc(retf.sz = sz), hp, sz);
59 free(v.data);
60 return(retf);
61 } else {
62 goto corrupt;
63 }
64 } else if(ret == DB_NOTFOUND) {
65 return((struct fileinfo){});
66 } else {
67 flog(LOG_ERR, "could not read value of %s in %s: %s", nm, d->envnm, db_strerror(ret));
68 return((struct fileinfo){});
69 }
70 goto out;
71
72corrupt:
73 flog(LOG_ERR, "entry for %s in %s is corrupted", nm, d->envnm);
74 free(v.data);
75 return((struct fileinfo){});
76out:;
77}
78
79static void dbidle(struct source *src)
80{
81 struct dbsrc *d = src->pdata;
82 time_t now;
83 int ret;
84 char **files;
85
86 now = time(NULL);
87 if(now - d->lastcp > 1800) {
88 d->lastcp = now;
89 if((ret = d->env->txn_checkpoint(d->env, 5000, 0, 0)) != 0) {
90 flog(LOG_ERR, "could not make db checkpoint in %s: %s", d->envnm, db_strerror(ret));
91 }
92 }
93 if(now - d->lastar > 7200) {
94 d->lastar = now;
95 files = NULL;
96 if((ret = d->env->log_archive(d->env, &files, DB_ARCH_REMOVE)) != 0) {
97 flog(LOG_ERR, "could not archive log files in %s: %s", d->envnm, db_strerror(ret));
98 }
99 if(files != NULL)
100 free(files);
101 }
102}
103
104static void enverror(const DB_ENV *env, const char *prefix, const char *msg)
105{
106 flog(LOG_ERR, "dbsource: environment error: %s", msg);
107}
108
109struct source *mkdbsrc(char *path, char *envpath)
110{
111 struct source *src;
112 struct dbsrc *d;
113 char *p;
114 int ret;
115
116 omalloc(src);
117 src->serve = dbserve;
118 src->idle = dbidle;
119 src->pdata = omalloc(d);
120 if((ret = db_env_create(&d->env, 0)) != 0) {
121 flog(LOG_ERR, "could not create bdb environment: %s", db_strerror(ret));
122 exit(1);
123 }
124 if(envpath) {
125 d->envnm = sstrdup(envpath);
126 } else {
127 d->envnm = sstrdup(path);
128 if((p = strrchr(d->envnm, '/')) == NULL) {
129 free(d->envnm);
130 d->envnm = sstrdup(".");
131 } else {
132 *p = 0;
133 }
134 }
135 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) {
136 flog(LOG_ERR, "could not open bdb environment: %s", db_strerror(ret));
137 exit(1);
138 }
139 d->env->set_lk_detect(d->env, DB_LOCK_RANDOM);
140 d->env->set_errcall(d->env, enverror);
141 if((ret = db_create(&d->db, d->env, 0)) != 0) {
142 flog(LOG_ERR, "could not create bdb database: %s", db_strerror(ret));
143 exit(1);
144 }
145 if((ret = d->db->open(d->db, NULL, path, NULL, DB_HASH, DB_AUTO_COMMIT | DB_CREATE, 0666)) != 0) {
146 flog(LOG_ERR, "could not open bdb database: %s", db_strerror(ret));
147 exit(1);
148 }
149 return(src);
150}