mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-31 14:15:30 +00:00
429 lines
10 KiB
C
429 lines
10 KiB
C
/*-
|
|
* See the file LICENSE for redistribution information.
|
|
*
|
|
* Copyright (c) 1996, 1997, 1998
|
|
* Sleepycat Software. All rights reserved.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#ifndef lint
|
|
static const char sccsid[] = "@(#)tcl_mpool.c 10.15 (Sleepycat) 5/4/98";
|
|
#endif /* not lint */
|
|
|
|
/*
|
|
* This file is divided up into 5 sets of functions:
|
|
* 1. The memp command and its support functions.
|
|
* 2. The memp_unlink command.
|
|
* 3. The memp widget commands.
|
|
* 4. The mool file commands.
|
|
* 5. The memp support functions (e.g. get, put, sync)
|
|
*/
|
|
#ifndef NO_SYSTEM_INCLUDES
|
|
#include <sys/types.h>
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#endif
|
|
#include <tcl.h>
|
|
|
|
#include "db_int.h"
|
|
#include "dbtest.h"
|
|
#include "test_ext.h"
|
|
|
|
typedef struct _mp_data {
|
|
DB_MPOOL *mp;
|
|
DB_ENV *env;
|
|
} mp_data;
|
|
|
|
typedef struct _mpfinfo {
|
|
DB_MPOOLFILE *mpf;
|
|
size_t pgsize;
|
|
} mpfinfo;
|
|
|
|
typedef struct _pginfo {
|
|
void *addr;
|
|
db_pgno_t pgno;
|
|
size_t pgsize;
|
|
DB_MPOOLFILE *mpf;
|
|
} pginfo;
|
|
|
|
/*
|
|
* memp_cmd --
|
|
* Implements memp_open for dbtest. Mpool_open creates an memp
|
|
* and creates an memp widget and command.
|
|
*/
|
|
|
|
#define MPOOL_USAGE "memp path mode flags options [options]\n\toptions:\n"
|
|
|
|
int
|
|
memp_cmd(notused, interp, argc, argv)
|
|
ClientData notused;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
static int mp_number = 0;
|
|
DB_ENV *env;
|
|
DB_MPOOL *mp;
|
|
mp_data *md;
|
|
u_int32_t flags;
|
|
int mode, tclint;
|
|
char mpname[50];
|
|
|
|
notused = NULL;
|
|
debug_check();
|
|
|
|
/* Check number of arguments. */
|
|
USAGE_GE(argc, 4, MPOOL_USAGE, DO_ENV);
|
|
|
|
if (Tcl_GetInt(interp, argv[2], &mode) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
flags = (u_int32_t)tclint;
|
|
|
|
/* Call memp_open. */
|
|
if (process_env_options(interp, argc, argv, &env) != TCL_OK) {
|
|
/*
|
|
* Special case an EINVAL return which we want to pass
|
|
* back to the caller.
|
|
*/
|
|
if (strcmp(interp->result, "EINVAL") != 0)
|
|
Tcl_SetResult(interp, "NULL", TCL_STATIC);
|
|
return (TCL_OK);
|
|
}
|
|
if (F_ISSET(env, DB_ENV_STANDALONE))
|
|
mp = env->mp_info;
|
|
else if (memp_open(argv[1], flags, mode, env, &mp) != 0) {
|
|
Tcl_SetResult(interp, "NULL", TCL_STATIC);
|
|
return (TCL_OK);
|
|
} else
|
|
env->mp_info = mp;
|
|
|
|
md = (mp_data *)malloc(sizeof(mp_data));
|
|
if (md == NULL) {
|
|
if (!F_ISSET(env, DB_ENV_STANDALONE)) {
|
|
(void)db_appexit(env);
|
|
if (env->lk_conflicts)
|
|
free(env->lk_conflicts);
|
|
free(env);
|
|
}
|
|
Tcl_SetResult(interp, "mp_open: ", TCL_STATIC);
|
|
errno = ENOMEM;
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
|
return (TCL_ERROR);
|
|
}
|
|
md->mp = mp;
|
|
md->env = env;
|
|
/* Create new command name. */
|
|
sprintf(&mpname[0], "mp%d", mp_number);
|
|
mp_number++;
|
|
|
|
/* Create widget command. */
|
|
Tcl_CreateCommand(interp, mpname, mpwidget_cmd, (int *)md, NULL);
|
|
Tcl_SetResult(interp, mpname, TCL_VOLATILE);
|
|
return (TCL_OK);
|
|
}
|
|
|
|
/*
|
|
* mempunlink_cmd --
|
|
* Implements memp_unlink for dbtest.
|
|
*/
|
|
|
|
#define MPOOLUNLINK_USAGE "memp_unlink path force"
|
|
|
|
int
|
|
mempunlink_cmd(notused, interp, argc, argv)
|
|
ClientData notused;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
u_int32_t flags;
|
|
int ret, tclint;
|
|
|
|
notused = NULL;
|
|
debug_check();
|
|
|
|
USAGE_GE(argc, 3, MPOOLUNLINK_USAGE, 0);
|
|
|
|
if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
flags = (u_int32_t)tclint;
|
|
|
|
if ((ret = memp_unlink(argv[1], flags, NULL)) != 0) {
|
|
Tcl_SetResult(interp, "memp_unlink: ", TCL_STATIC);
|
|
errno = ret;
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
|
} else
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
|
return (TCL_OK);
|
|
}
|
|
|
|
/*
|
|
* mpwidget --
|
|
* This is that command that implements the memp widget. If we
|
|
* ever add new "methods" we add new widget commands here.
|
|
*/
|
|
#define MPWIDGET_USAGE "mpN option ?arg arg ...?"
|
|
#define MPCLOSE_USAGE "mpN close"
|
|
#define MPFOPEN_USAGE "mpN open path pagesize flags mode options"
|
|
#define MPSTAT_USAGE "mpN stat"
|
|
|
|
int
|
|
mpwidget_cmd(cd_mp, interp, argc, argv)
|
|
ClientData cd_mp;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
static int mpf_id = 0;
|
|
DB_ENV *env;
|
|
DB_MPOOL *mp;
|
|
DB_MPOOLFILE *mpf;
|
|
mpfinfo *mfi;
|
|
size_t pagesize;
|
|
u_int32_t flags;
|
|
int mode, ret, tclint;
|
|
char mpfname[128];
|
|
|
|
debug_check();
|
|
|
|
mp = ((mp_data *)cd_mp)->mp;
|
|
|
|
USAGE_GE(argc, 2, MPWIDGET_USAGE, 0);
|
|
|
|
if (strcmp(argv[1], "close") == 0) {
|
|
USAGE(argc, 2, MPCLOSE_USAGE, 0);
|
|
env = ((mp_data *)cd_mp)->env;
|
|
if (!F_ISSET(env, DB_ENV_STANDALONE)) {
|
|
(void)db_appexit(env);
|
|
if (env->lk_conflicts)
|
|
free(env->lk_conflicts);
|
|
free(env);
|
|
}
|
|
ret = Tcl_DeleteCommand(interp, argv[0]);
|
|
if (ret)
|
|
Tcl_SetResult(interp, "-1", TCL_STATIC);
|
|
else
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
|
return (ret);
|
|
} else if (strcmp(argv[1], "open") == 0) {
|
|
USAGE(argc, 6, MPFOPEN_USAGE, 0);
|
|
|
|
if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
pagesize = (size_t)tclint;
|
|
if (Tcl_GetInt(interp, argv[4], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
flags = (u_int32_t)tclint;
|
|
if (Tcl_GetInt(interp, argv[5], &mode) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
|
|
if ((ret = memp_fopen(mp,
|
|
argv[2], flags, mode, pagesize, NULL, &mpf)) != 0) {
|
|
errno = ret;
|
|
Tcl_SetResult(interp,
|
|
Tcl_PosixError(interp), TCL_STATIC);
|
|
}
|
|
|
|
sprintf(&mpfname[0], "%s.mpf%d", argv[0], mpf_id);
|
|
if ((mfi = (mpfinfo *)malloc(sizeof(mpfinfo))) == NULL) {
|
|
Tcl_SetResult(interp, "mp open: ", TCL_STATIC);
|
|
errno = ENOMEM;
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
|
return (TCL_ERROR);
|
|
}
|
|
mfi->mpf = mpf;
|
|
mfi->pgsize = pagesize;
|
|
|
|
mpf_id++;
|
|
Tcl_CreateCommand(interp, mpfname, mpf_cmd, (int *)mfi, NULL);
|
|
Tcl_SetResult(interp, mpfname, TCL_VOLATILE);
|
|
return (TCL_OK);
|
|
} else if (strcmp(argv[1], "stat") == 0) {
|
|
/*
|
|
* XXX
|
|
* THIS DOESN'T CURRENTLY WORK.
|
|
memp_stat(mp, stdout);
|
|
*/
|
|
return (TCL_OK);
|
|
} else {
|
|
Tcl_SetResult(interp, MPWIDGET_USAGE, TCL_STATIC);
|
|
return (TCL_ERROR);
|
|
}
|
|
}
|
|
|
|
#define MPF_USAGE "mpN.mpfM cmd ?arg arg ...?"
|
|
#define MPFCLOSE_USAGE "mpN.mpfM close"
|
|
#define MPFGET_USAGE "mpN.mpfM get pgno flags"
|
|
#define MPFSYNC_USAGE "mpN.mpfM sync"
|
|
int
|
|
mpf_cmd(cd_mfi, interp, argc, argv)
|
|
ClientData cd_mfi;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
static int pg_id = 0;
|
|
DB_MPOOLFILE *mpf;
|
|
db_pgno_t pgno;
|
|
pginfo *pinfo;
|
|
void *paddr;
|
|
u_int32_t flags;
|
|
int ret, tclint;
|
|
char pgname[128];
|
|
|
|
debug_check();
|
|
|
|
USAGE_GE(argc, 2, MPF_USAGE, 0);
|
|
|
|
mpf = ((mpfinfo *)cd_mfi)->mpf;
|
|
if (strcmp(argv[1], "close") == 0) {
|
|
USAGE(argc, 2, MPFCLOSE_USAGE, 0);
|
|
(void)free(cd_mfi);
|
|
ret = memp_fclose(mpf);
|
|
if (ret == 0)
|
|
ret = Tcl_DeleteCommand(interp, argv[0]);
|
|
if (ret)
|
|
Tcl_SetResult(interp, "-1", TCL_STATIC);
|
|
else
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
|
return (ret);
|
|
} else if (strcmp(argv[1], "get") == 0) {
|
|
USAGE(argc, 4, MPFGET_USAGE, 0);
|
|
if (Tcl_GetInt(interp, argv[2], (int *)&pgno) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
flags = (u_int32_t)tclint;
|
|
ret = memp_fget(mpf, &pgno, flags, &paddr);
|
|
if (ret != 0 ||
|
|
(pinfo = (pginfo *)malloc(sizeof(pginfo))) == NULL) {
|
|
Tcl_SetResult(interp, "mpf_cmd: ", TCL_STATIC);
|
|
if (ret != 0)
|
|
errno = ret;
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
|
return (TCL_ERROR);
|
|
}
|
|
|
|
/* Now create page widget. */
|
|
pinfo->addr = paddr;
|
|
pinfo->pgno = pgno;
|
|
pinfo->pgsize = ((mpfinfo *)cd_mfi)->pgsize;
|
|
pinfo->mpf = ((mpfinfo *)cd_mfi)->mpf;
|
|
sprintf(&pgname[0], "page%d", pg_id);
|
|
pg_id++;
|
|
Tcl_CreateCommand(interp, pgname, pgwidget_cmd, (int *)pinfo,
|
|
NULL);
|
|
Tcl_SetResult(interp, &pgname[0], TCL_VOLATILE);
|
|
return (TCL_OK);
|
|
|
|
} else if (strcmp(argv[1], "sync") == 0) {
|
|
USAGE(argc, 2, MPFSYNC_USAGE, 0);
|
|
if ((ret = memp_fsync(mpf)) == 0)
|
|
return (TCL_OK);
|
|
else {
|
|
Tcl_SetResult(interp, "mpf sync: ", TCL_STATIC);
|
|
errno = ret;
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
|
return (TCL_ERROR);
|
|
}
|
|
} else {
|
|
Tcl_SetResult(interp, MPF_USAGE, TCL_STATIC);
|
|
return (TCL_ERROR);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* pagewidget --
|
|
* This is that command that implements the memp page widget. This
|
|
* is returned from the get function of an mpf.
|
|
*/
|
|
#define PAGE_USAGE "pageN option ?arg arg ...?"
|
|
#define PAGEPUT_USAGE "pageN put flags"
|
|
#define PAGEINIT_USAGE "pageN init str"
|
|
#define PAGECHECK_USAGE "pageN check str"
|
|
#define PAGEGET_USAGE "pageN get"
|
|
|
|
int
|
|
pgwidget_cmd(cd_page, interp, argc, argv)
|
|
ClientData cd_page;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
pginfo *pinfo;
|
|
size_t i, len;
|
|
u_int32_t flags;
|
|
int *ip, ret, tclint;
|
|
char *p, intbuf[50];
|
|
|
|
debug_check();
|
|
|
|
pinfo = (pginfo *)cd_page;
|
|
if (strcmp(argv[1], "put") == 0) {
|
|
USAGE(argc, 3, PAGEPUT_USAGE, 0);
|
|
if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
flags = (u_int32_t)tclint;
|
|
if ((ret = memp_fput(pinfo->mpf, pinfo->addr, flags)) != 0) {
|
|
Tcl_SetResult(interp, "page put: ", TCL_STATIC);
|
|
errno = ret;
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
|
return (TCL_ERROR);
|
|
}
|
|
free (cd_page);
|
|
Tcl_DeleteCommand(interp, argv[0]);
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
|
return (TCL_OK);
|
|
} else if (strcmp(argv[1], "init") == 0) {
|
|
USAGE(argc, 3, PAGEINIT_USAGE, 0);
|
|
len = strlen(argv[2]);
|
|
for (p = (char *)pinfo->addr,
|
|
i = 0; i < pinfo->pgsize; i += len, p += len) {
|
|
if (i + len > pinfo->pgsize)
|
|
len = pinfo->pgsize - i;
|
|
memcpy(p, argv[2], len);
|
|
}
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
|
return (TCL_OK);
|
|
} else if (strcmp(argv[1], "check") == 0) {
|
|
USAGE(argc, 3, PAGECHECK_USAGE, 0);
|
|
len = strlen(argv[2]);
|
|
|
|
/* Special case, 0'd pages. */
|
|
ret = 0;
|
|
if (strcmp(argv[2], "nul") == 0) {
|
|
for (ip = (int *)pinfo->addr,
|
|
i = 0; i < pinfo->pgsize; i += sizeof(int), ip++)
|
|
if ((ret = (*ip != 0)) != 0)
|
|
break;
|
|
} else {
|
|
for (p = (char *)pinfo->addr,
|
|
i = 0; i < pinfo->pgsize; i += len, p += len) {
|
|
if (i + len > pinfo->pgsize)
|
|
len = pinfo->pgsize - i;
|
|
if ((ret = memcmp(p, argv[2], len)) != 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ret) /* MISMATCH */
|
|
Tcl_SetResult(interp, "1", TCL_STATIC);
|
|
else
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
|
return (TCL_OK);
|
|
} else if (strcmp(argv[1], "get") == 0) {
|
|
USAGE(argc, 2, PAGEGET_USAGE, 0);
|
|
sprintf(intbuf, "%lu", (unsigned long)pinfo->pgno);
|
|
Tcl_SetResult(interp, intbuf, TCL_VOLATILE);
|
|
return (TCL_OK);
|
|
} else {
|
|
Tcl_SetResult(interp, PAGE_USAGE, TCL_STATIC);
|
|
return (TCL_ERROR);
|
|
}
|
|
}
|