1 #include "common.h"
2 #include "c-icap.h"
3 #include "module.h"
4 #include "lookup_table.h"
5 #include "commands.h"
6 #include "debug.h"
7 #include "util.h"
8 #include BDB_HEADER_PATH(db.h)
9
10
11 int init_bdb_tables(struct ci_server_conf *server_conf);
12 void release_bdb_tables();
13
14 CI_DECLARE_MOD_DATA common_module_t module = {
15 "bdb_tables",
16 init_bdb_tables,
17 NULL,
18 release_bdb_tables,
19 NULL,
20 };
21
22
23
24 void *bdb_table_open(struct ci_lookup_table *table);
25 void bdb_table_close(struct ci_lookup_table *table);
26 void *bdb_table_search(struct ci_lookup_table *table, void *key, void ***vals);
27 void bdb_table_release_result(struct ci_lookup_table *table_data,void **val);
28
29 struct ci_lookup_table_type bdb_table_type = {
30 bdb_table_open,
31 bdb_table_close,
32 bdb_table_search,
33 bdb_table_release_result,
34 NULL,
35 "bdb"
36 };
37
38
init_bdb_tables(struct ci_server_conf * server_conf)39 int init_bdb_tables(struct ci_server_conf *server_conf)
40 {
41 return (ci_lookup_table_type_register(&bdb_table_type) != NULL);
42 }
43
release_bdb_tables()44 void release_bdb_tables()
45 {
46 ci_lookup_table_type_unregister(&bdb_table_type);
47 }
48
49 /***********************************************************/
50 /* bdb_table_type inmplementation */
51
52 struct bdb_data {
53 DB_ENV *env_db;
54 DB *db;
55 };
56
57
bdb_table_do_real_open(struct ci_lookup_table * table)58 int bdb_table_do_real_open(struct ci_lookup_table *table)
59 {
60 int ret, i;
61 char *s,home[CI_MAX_PATH];
62 ci_dyn_array_t *args = NULL;
63 ci_array_item_t *arg = NULL;
64 uint32_t cache_size = 0;
65 int caches_num = 0;
66 long int val;
67 struct bdb_data *dbdata = table->data;
68
69 if (!dbdata) {
70 ci_debug_printf(1, "Db table %s is not initialized?\n", table->path);
71 return 0;
72 }
73 if (dbdata->db || dbdata->env_db) {
74 ci_debug_printf(1, "Db table %s already open?\n", table->path);
75 return 0;
76 }
77
78 strncpy(home,table->path,CI_MAX_PATH);
79 home[CI_MAX_PATH-1] = '\0';
80 s=strrchr(home,'/');
81 if (s)
82 *s = '\0';
83 else /*no path in filename?*/
84 home[0] = '\0';
85
86 if (table->args) {
87 if ((args = ci_parse_key_value_list(table->args, ','))) {
88 for (i = 0; (arg = ci_dyn_array_get_item(args, i)) != NULL; ++i) {
89 if (strcasecmp(arg->name, "cache-size") == 0) {
90 val = ci_atol_ext((char *)arg->value, NULL);
91 if (val > 0 && val < 1*1024*1024*1024)
92 cache_size = (uint32_t)val;
93 else
94 ci_debug_printf(1, "WARNING: wrong cache-size value: %ld, will not set\n", val);
95 }
96 if (strcasecmp(arg->name, "cache-num") == 0) {
97 val = strtol(arg->value, NULL, 10);
98 if (val > 0 && val < 20)
99 caches_num = (uint32_t)val;
100 else
101 ci_debug_printf(1, "WARNING: wrong cache-num value: %ld, will not set\n", val);
102 }
103
104 }
105 }
106 }
107
108 /* * Create an environment and initialize it for additional error * reporting. */
109 if ((ret = db_env_create(&dbdata->env_db, 0)) != 0) {
110 return 0;
111 }
112 ci_debug_printf(5, "bdb_table_open: Environment created OK.\n");
113
114
115 dbdata->env_db->set_data_dir(dbdata->env_db, home);
116 ci_debug_printf(5, "bdb_table_open: Data dir set to %s.\n", home);
117
118 /* Open the environment */
119 if ((ret = dbdata->env_db->open(dbdata->env_db, home,
120 DB_CREATE | DB_INIT_LOCK | DB_INIT_MPOOL|DB_THREAD /*| DB_SYSTEM_MEM*/,
121 0)) != 0) {
122 ci_debug_printf(1, "bdb_table_open: Environment open failed: %s\n", db_strerror(ret));
123 dbdata->env_db->close(dbdata->env_db, 0);
124 dbdata->env_db = NULL;
125 return 0;
126 }
127 ci_debug_printf(5, "bdb_table_open: DB environment setup OK.\n");
128
129
130 if ((ret = db_create(&dbdata->db, dbdata->env_db, 0)) != 0) {
131 ci_debug_printf(1, "db_create: %s\n", db_strerror(ret));
132 dbdata->db = NULL;
133 dbdata->env_db->close(dbdata->env_db, 0);
134 dbdata->env_db = NULL;
135 return 0;
136 }
137
138 if (cache_size > 0 &&
139 (ret = dbdata->db->set_cachesize(dbdata->db, 0, cache_size, caches_num)) != 0) {
140 ci_debug_printf(1, "db_create failed to set cache size: %s\n", db_strerror(ret));
141 }
142
143 #if (DB_VERSION_MAJOR > 4) || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
144 if ((ret = dbdata->db->open( dbdata->db, NULL, table->path, NULL,
145 DB_BTREE, DB_RDONLY|DB_THREAD, 0)) != 0) {
146 #else
147 if ((ret = dbdata->db->open( dbdata->db, table->path, NULL,
148 DB_BTREE, DB_RDONLY, 0)) != 0) {
149 #endif
150 ci_debug_printf(1, "open db %s: %s\n", table->path, db_strerror(ret));
151 dbdata->db->close(dbdata->db, 0);
152 dbdata->db = NULL;
153 dbdata->env_db->close(dbdata->env_db, 0);
154 dbdata->env_db = NULL;
155 return 0;
156 }
157
158 return 1;
159 }
160
161
162 void command_real_open_table(const char *name, int type, void *data)
163 {
164 struct ci_lookup_table *table = data;
165 bdb_table_do_real_open(table);
166 }
167
168 void *bdb_table_open(struct ci_lookup_table *table)
169 {
170 struct bdb_data *dbdata = malloc(sizeof(struct bdb_data));
171 if (!dbdata)
172 return NULL;
173 dbdata->env_db = NULL;
174 dbdata->db = NULL;
175 table->data = dbdata;
176
177 /*We can not fork a Berkeley DB table, so we have to
178 open bdb tables for every child, on childs start-up procedure*/
179 register_command_extend("openBDBtable", CHILD_START_CMD, table,
180 command_real_open_table);
181
182 return table->data;
183 }
184
185 void bdb_table_close(struct ci_lookup_table *table)
186 {
187 struct bdb_data *dbdata;
188 dbdata = table->data;
189 if (dbdata && dbdata->db && dbdata->env_db) {
190
191 dbdata->db->close(dbdata->db,0);
192 dbdata->env_db->close(dbdata->env_db,0);
193 free(table->data);
194 table->data = NULL;
195 } else {
196 ci_debug_printf(3,"table %s is not open?\n", table->path);
197 }
198 }
199
200 #define DATA_SIZE 32768
201 #define BDB_MAX_COLS 1024 /*Shound be: BDB_MAX_COLS*sizeof(void *) < DATA_SIZE */
202
203 void *bdb_table_search(struct ci_lookup_table *table, void *key, void ***vals)
204 {
205 void *store;
206 void **store_index;
207 void *endstore;
208 DBT db_key, db_data;
209 int ret, i, parse_error = 0;
210 struct bdb_data *dbdata = (struct bdb_data *)table->data;
211
212 if (!dbdata) {
213 ci_debug_printf(1,"table %s is not initialized?\n", table->path);
214 return NULL;
215 }
216
217 if (!dbdata->db) {
218 ci_debug_printf(1,"table %s is not open?\n", table->path);
219 return NULL;
220 }
221
222 *vals = NULL;
223 memset(&db_data, 0, sizeof(db_data));
224 memset(&db_key, 0, sizeof(db_key));
225 db_key.data = key;
226 db_key.size = table->key_ops->size(key);
227
228 db_data.flags = DB_DBT_USERMEM;
229 db_data.data = ci_buffer_alloc(DATA_SIZE);
230 db_data.size = DATA_SIZE;
231
232 if ((ret = dbdata->db->get(dbdata->db, NULL, &db_key, &db_data, 0)) != 0) {
233 ci_debug_printf(5, "db_entry_exists does not exists: %s\n", db_strerror(ret));
234 *vals = NULL;
235 return NULL;
236 }
237
238 if (db_data.size) {
239 store = db_data.data;
240 store_index = store;
241 endstore = store+db_data.size;
242 for (i = 0; store_index[i] != NULL && i < BDB_MAX_COLS && !parse_error; i++) {
243 store_index[i] = store+(unsigned long int)store_index[i];
244 if (store_index[i] > endstore)
245 parse_error = 1;
246 }
247 if (!parse_error)
248 *vals = store;
249 else {
250 ci_debug_printf(1, "Error while parsing data in bdb_table_search.Is this a c-icap bdb table?\n");
251 }
252 }
253 return key;
254 }
255
256 void bdb_table_release_result(struct ci_lookup_table *table,void **val)
257 {
258 ci_buffer_free(val);
259 }
260