/*
* 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 */
syntax highlighted by Code2HTML, v. 0.9.1