/* * Copyright (c) 2006 Claus Assmann * * By using this file, you agree to the terms and conditions set * forth in the license/LICENSE.3C file which can be found at the * top level of this source code distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: cdb.c,v 1.6 2006/11/18 15:25:53 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/memops.h" #include "sm/heap.h" #include "sm/fcntl.h" #include "map.h" #include "sm/map.h" #include "sm/maps.h" #include "sm/mapc.h" #include "sm/mapclasses.h" #include "sm/cdb_map.h" #if MTA_USE_TINYCDB /* XXX FIX XXX */ #define CDB_ERR2RET(ret) ret /* ** ToDo: implementation of map for tinycdb. */ /* static sm_map_open_F sm_cdb_open; */ /* static sm_map_close_F sm_cdb_close; */ static sm_map_alloc_F sm_cdb_alloc; static sm_map_free_F sm_cdb_free; #if 0 static sm_map_locate_F sm_cdb_locate; static sm_map_first_F sm_cdb_first; static sm_map_next_F sm_cdb_next; #endif /* 0 */ typedef struct cdb cdb_map_T, *cdb_map_P; typedef struct cdb_make cdb_make_T, *cdb_make_P; typedef union sm_cdbs_U sm_cdbs_T, *sm_cdbs_P; union sm_cdbs_U { cdb_map_T cdbs_cdb_rd; cdb_make_T cdbs_cdb_wr; }; typedef struct sm_cdbmap_S sm_cdbmap_T, *sm_cdbmap_P; struct sm_cdbmap_S { int cdbmap_fd; bool cdbmap_create; sm_cdbs_T cdbmap_map; }; /* ** These are types of databases. */ #define SMDB_TYPE_DEFAULT NULL #define SMDB_TYPE_CDB "cdb" #if 0 /* ** CDB_TYPE2CDB -- Translates database type to CDB type. ** ** Parameters: ** type -- The type to translate. ** ** Returns: ** The CDB type that corresponds to type. */ static DBTYPE cdb_type2cdb2(const sm_cstr_P type) { if (SMDB_TYPE_DEFAULT == type) return DB_CDB; if (strncmp((const char*)sm_cstr_data(type), SMDB_TYPE_CDB, sm_cstr_getlen(type)) == 0) return DB_CDB; return DB_UNKNOWN; } #endif /* 0 */ /* ** SM_CDB_SETOPT -- set options for map ** ** Parameters: ** map -- map ** ap -- options ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_cdb_setopt(sm_map_P map, va_list ap) { sm_ret_T ret; int k; SM_IS_MAP(map); ret = SM_SUCCESS; for (;;) { k = va_arg(ap, int); if (SMPO_END == k) break; switch (k) { default: /* silently ignore bogus options? */ break; } } return ret; } /* ** SM_CDB_GETOPT -- get options for map ** ** Parameters: ** map -- map ** which -- which option? ** valp -- pointer to place where result should be stored ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_cdb_getopt(sm_map_P map, int which, void *valp) { sm_ret_T ret; sm_cdbmap_P cdb; SM_IS_MAP(map); cdb = (sm_cdbmap_P) map->sm_map_db; if (NULL == cdb) return sm_error_perm(SM_EM_MAP, ENOENT); /* ... */ ret = SM_SUCCESS; return ret; } /* ** SM_CDB_CLOSE -- close map ** more parameters??? ** ** Parameters: ** map -- map ** flags -- currently ignored ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_cdb_close(sm_map_P map, uint32_t flags) { sm_ret_T ret; int fd; sm_mapc_P mapc; sm_cdbmap_P sm_cdbmap; SM_IS_MAP(map); mapc = map->sm_map_class; SM_IS_MAPC(mapc); ret = SM_SUCCESS; sm_cdbmap = (sm_cdbmap_P) map->sm_map_db; if (NULL == sm_cdbmap) return sm_error_perm(SM_EM_MAP, ENOENT); if (sm_cdbmap->cdbmap_create) ret = cdb_make_finish(&sm_cdbmap->cdbmap_map.cdbs_cdb_wr); fd = sm_cdbmap->cdbmap_fd; if (fd >= 0) { close(fd); sm_cdbmap->cdbmap_fd = INVALID_FD; } sm_free_size(sm_cdbmap, sizeof(sm_cdbmap)); /* close CDB map */ map->sm_map_db = NULL; return ret; } /* ** SM_CDB_DESTROY -- destroy map ** XXX more parameters... ** ** Parameters: ** map -- map ** flags -- flags for map ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_cdb_destroy(sm_map_P map, uint32_t flags) { sm_ret_T ret; sm_mapc_P mapc; sm_cdbmap_P sm_cdbmap; SM_IS_MAP(map); mapc = map->sm_map_class; SM_IS_MAPC(mapc); ret = SM_SUCCESS; sm_cdbmap = (sm_cdbmap_P) map->sm_map_db; if (NULL == sm_cdbmap) return sm_error_perm(SM_EM_MAP, ENOENT); /* close fd? */ sm_free_size(sm_cdbmap, sizeof(sm_cdbmap)); map->sm_map_db = NULL; return ret; } /* ** SM_CDB_CREATE -- create map ** ** Parameters: ** mapc -- map context ** type -- type of map ** flags -- flags for map ** map -- map ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_cdb_create(sm_mapc_P mapc, const sm_cstr_P type, uint32_t flags, sm_map_P map) { sm_cdbmap_P sm_cdbmap; SM_IS_MAPC(mapc); SM_REQUIRE(map != NULL); sm_cdbmap = (sm_cdbmap_P) sm_zalloc(sizeof(*sm_cdbmap)); if (NULL == sm_cdbmap) return sm_error_temp(SM_EM_MAP, ENOMEM); sm_cdbmap->cdbmap_fd = INVALID_FD; map->sm_map_db = sm_cdbmap; map->sm_map_caps = SMMAP_CAPS_LTALL; return SM_SUCCESS; } #if 0 /* ** CDB_OPEN_FLAGS -- translate external (map) flags into internal flags ** ** Paramters: ** flags -- map flags ** ** Returns: ** Internal flag value matching user selected flags */ static uint32_t cdb_open_flags(uint32_t flags) { uint32_t ret; ret = 0; if (SM_IS_FLAG(flags, SMAP_MODE_RDONLY)) ret |= DB_RDONLY; if (SM_IS_FLAG(flags, SMAP_MODE_CREATE)) ret |= DB_CREATE; return ret; } #endif /* 0 */ /* ** SM_CDB_OPEN -- open map ** ** Parameters: ** mapc -- map context ** type -- type of map ** flags -- flags for opening map ** path -- path of map ** mode -- open mode (currently ignored, DBMMODE is used) ** map -- map ** ap -- additional argument ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_cdb_open(sm_mapc_P mapc, const sm_cstr_P type, uint32_t flags, const char *path, int mode, sm_map_P map, va_list ap) { sm_ret_T ret; int fd; sm_cdbmap_P sm_cdbmap; SM_IS_MAPC(mapc); SM_REQUIRE(map != NULL); SM_REQUIRE(path != NULL); ret = SM_SUCCESS; fd = -1; sm_cdbmap = (sm_cdbmap_P) map->sm_map_db; SM_REQUIRE(sm_cdbmap != NULL); if (SM_IS_FLAG(flags, SMAP_MODE_CREATE)) { sm_cdbmap->cdbmap_create = true; fd = open(path, O_RDWR|O_CREAT|O_TRUNC, 0640); if (fd < 0) return sm_error_perm(SM_EM_MAP, errno); ret = cdb_make_start(&sm_cdbmap->cdbmap_map.cdbs_cdb_wr, fd); } else { fd = open(path, O_RDONLY); if (fd < 0) return sm_error_perm(SM_EM_MAP, errno); ret = cdb_init(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd, fd); } if (ret != 0) { ret = CDB_ERR2RET(ret); goto error; } sm_cdbmap->cdbmap_fd = fd; return ret; error: if (fd >= 0) close(fd); return ret; } /* ** SM_CDB_LOOKUP -- lookup a key in CDB, return data if found ** ** Parameters: ** map -- map context ** flags -- flags ** key -- key ** data -- data (output) ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_cdb_lookup(sm_map_P map, uint32_t flags, sm_map_key_P key, sm_map_data_P data) { sm_ret_T ret; size_t l; sm_mapc_P mapc; sm_cdbmap_P sm_cdbmap; SM_IS_MAP(map); SM_IS_KEY(key); SM_IS_DATA(data); mapc = map->sm_map_class; SM_IS_MAPC(mapc); ret = SM_SUCCESS; sm_cdbmap = (sm_cdbmap_P) map->sm_map_db; if (NULL == sm_cdbmap ) return sm_error_perm(SM_EM_MAP, ENOENT); /* XXX */ SM_ASSERT(!sm_cdbmap->cdbmap_create); if (!SMMAP_IS_FL(map, SMMAP_FL_OPEN)) { /* map closed but can be reopened? */ if (mapc->sm_mapc_reopenf != NULL) ret = mapc->sm_mapc_reopenf(map, 0); else ret = sm_error_perm(SM_EM_MAP, SM_E_CLOSEDMAP); if (sm_is_err(ret)) return ret; } /* XXX WARNING: changes key inplace! */ if (SM_IS_FLAG(flags, SMMAP_FL_LWR_KEY)) sm_str2lower(key); /* need to lock access? single threaded access! */ ret = cdb_find(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd, sm_str_data(key), sm_str_getlen(key)); if (ret > 0) { l = cdb_datalen(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd); if (l > sm_str_getsize(data) && l < sm_str_getmax(data)) { if (!sm_is_err(sm_str_resize_data(data, l))) { ret = cdb_find(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd, sm_str_data(key), sm_str_getlen(key)); l = cdb_datalen(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd); } } if (ret > 0) { SM_ASSERT(l <= sm_str_getsize(data)); ret = cdb_read(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd, sm_str_data(data), l, cdb_datapos(&sm_cdbmap->cdbmap_map.cdbs_cdb_rd)); if (ret < 0) ret = sm_error_temp(SM_EM_MAP, EINVAL); else { SM_STR_SETLEN(data, l); ret = SM_SUCCESS; } } } else ret = SM_MAP_NOTFOUND; return ret; } /* ** SM_CDB_ADD -- add key/data to CDB ** ** Parameters: ** map -- map context ** key -- key ** data -- data ** flags -- flags ** ** Returns: ** usual sm_error code */ static sm_ret_T sm_cdb_add(sm_map_P map, sm_map_key_P key, sm_map_data_P data, uint flags) { sm_ret_T ret; sm_mapc_P mapc; sm_cdbmap_P sm_cdbmap; SM_IS_MAP(map); SM_REQUIRE(key != NULL); SM_REQUIRE(data != NULL); mapc = map->sm_map_class; SM_IS_MAPC(mapc); ret = SM_SUCCESS; sm_cdbmap = (sm_cdbmap_P) map->sm_map_db; if (NULL == sm_cdbmap) return sm_error_perm(SM_EM_MAP, ENOENT); /* XXX */ SM_ASSERT(sm_cdbmap->cdbmap_create); ret = cdb_make_put(&sm_cdbmap->cdbmap_map.cdbs_cdb_wr, sm_str_data(key), sm_str_getlen(key), sm_str_data(data), sm_str_getlen(data), CDB_PUT_INSERT); return ret < 0 ? sm_error_perm(SM_EM_MAP, errno) : SM_SUCCESS; } /* ** SM_CDB_CLASS_CREATE -- create CDB map class ** ** Parameters: ** maps -- map system context ** ** Returns: ** usual sm_error code */ sm_ret_T sm_cdb_class_create(sm_maps_P maps) { sm_ret_T ret; sm_mapc_P mapc; sm_cstr_P htype; #define CDB_TYPE "cdb" ret = SM_SUCCESS; mapc = NULL; htype = sm_cstr_scpyn0((const uchar *)CDB_TYPE, strlen(CDB_TYPE)); if (NULL == htype) goto error; ret = sm_mapc_create(maps, htype, SMMAPC_FL_GEN_REOPEN|SMMAPC_FL_LCK_FULL| SMMAPC_FL_FILE, sm_cdb_create, sm_cdb_open, sm_cdb_close, NULL, sm_cdb_destroy, sm_cdb_add, NULL, sm_cdb_alloc, sm_cdb_free, sm_cdb_lookup, NULL /* sm_cdb_locate */, NULL /* sm_cdb_first */, NULL /* sm_cdb_next */, sm_cdb_setopt, sm_cdb_getopt, &mapc); SM_CSTR_FREE(htype); return ret; error: if (SM_SUCCESS == ret) ret = sm_error_temp(SM_EM_MAP, ENOMEM); /* cleanup mapc? */ return ret; } #endif /* MTA_USE_TINYCDB */