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