зеркало из https://github.com/mozilla/gecko-dev.git
433 строки
10 KiB
C
433 строки
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_log.c 10.13 (Sleepycat) 4/10/98";
|
|
#endif /* not lint */
|
|
|
|
/*
|
|
* This file is divided up into 5 sets of functions:
|
|
* 1. The log command and its support functions.
|
|
* 2. The logunlink command.
|
|
* 3. The log manager widget commands.
|
|
*/
|
|
#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"
|
|
|
|
/* Internal functions */
|
|
static int get_lsn __P((Tcl_Interp *, char *, DB_LSN *));
|
|
static int log_compare_cmd __P((Tcl_Interp *interp, int, char *argv[]));
|
|
static int log_file_cmd __P((DB_LOG *, Tcl_Interp *interp, int, char *argv[]));
|
|
static int log_flush_cmd __P((DB_LOG *, Tcl_Interp *interp, int, char *argv[]));
|
|
static int log_get_cmd __P((DB_LOG *, Tcl_Interp *interp, int, char *argv[]));
|
|
static int log_put_cmd __P((DB_LOG *, Tcl_Interp *interp, int, char *argv[]));
|
|
static int log_reg_cmd __P((DB_LOG *, Tcl_Interp *interp, int, char *argv[]));
|
|
|
|
/*
|
|
* log_cmd --
|
|
* Implements log_open for dbtest. Log_open creates a log manager
|
|
* and all the necessary files in the file system. It then creates
|
|
* a command that implements the other log functions.
|
|
*/
|
|
|
|
#define LOG_USAGE "log path flags mode [options]\n\toptions:\n"
|
|
|
|
typedef struct _log_data {
|
|
DB_LOG *logp;
|
|
DB_ENV *env;
|
|
} log_data;
|
|
|
|
int
|
|
log_cmd(notused, interp, argc, argv)
|
|
ClientData notused;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
static int log_number = 0;
|
|
DB_LOG *lp;
|
|
DB_ENV *env;
|
|
log_data *ld;
|
|
u_int32_t flags;
|
|
int mode, tclint;
|
|
char logname[50];
|
|
|
|
notused = NULL;
|
|
|
|
debug_check();
|
|
|
|
/* Check number of arguments. */
|
|
USAGE_GE(argc, 4, LOG_USAGE, DO_ENV);
|
|
if (Tcl_GetInt(interp, argv[2], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
flags = (u_int32_t)tclint;
|
|
|
|
if (Tcl_GetInt(interp, argv[3], &mode) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
|
|
if (process_env_options(interp, argc, argv, &env))
|
|
return (TCL_ERROR);
|
|
|
|
if (F_ISSET(env, DB_ENV_STANDALONE))
|
|
lp = env->lg_info;
|
|
else if (log_open(argv[1], flags, mode, env, &lp) != 0) {
|
|
Tcl_SetResult(interp, "NULL", TCL_STATIC);
|
|
return (TCL_OK);
|
|
} else
|
|
env->lg_info = lp;
|
|
|
|
if ((ld = (log_data *)malloc(sizeof(log_data))) == 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, "lock_open: ", TCL_STATIC);
|
|
errno = ENOMEM;
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
|
return (TCL_ERROR);
|
|
}
|
|
ld->logp = lp;
|
|
ld->env = env;
|
|
|
|
/* Create new command name. */
|
|
sprintf(&logname[0], "log%d", log_number);
|
|
log_number++;
|
|
|
|
/* Create widget command. */
|
|
Tcl_CreateCommand(interp, logname, logwidget_cmd, (int *)ld, NULL);
|
|
Tcl_SetResult(interp, logname, TCL_VOLATILE);
|
|
return (TCL_OK);
|
|
}
|
|
|
|
/*
|
|
* logunlink_cmd --
|
|
* Implements txn_unlink for dbtest.
|
|
*/
|
|
|
|
#define LOGUNLINK_USAGE "log_unlink path force"
|
|
|
|
int
|
|
logunlink_cmd(notused, interp, argc, argv)
|
|
ClientData notused;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
int force;
|
|
|
|
notused = NULL;
|
|
|
|
debug_check();
|
|
|
|
USAGE_GE(argc, 3, LOGUNLINK_USAGE, 0);
|
|
|
|
if (Tcl_GetInt(interp, argv[2], &force) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
|
|
if (log_unlink(argv[1], force, NULL) != 0)
|
|
Tcl_SetResult(interp, "-1", TCL_STATIC);
|
|
else
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
|
|
|
return (TCL_OK);
|
|
}
|
|
|
|
/*
|
|
* logwidget --
|
|
* This is that command that implements the log widget. If we
|
|
* ever add new "methods" we add new widget commands here.
|
|
*/
|
|
#define LOGWIDGET_USAGE "logN option ?arg arg ...?"
|
|
#define LOGCLOSE_USAGE "logN close"
|
|
#define LOGFLUSH_USAGE "logN flush lsn"
|
|
#define LOGGET_USAGE "logN get lsn flags"
|
|
#define LOGCMP_USAGE "logN compare lsn1 lsn2"
|
|
#define LOGFILE_USAGE "logN file lsn"
|
|
#define LOGLAST_USAGE "logN last"
|
|
#define LOGPUT_USAGE "logN put record flags"
|
|
#define LOGREG_USAGE "logN register db name type"
|
|
#define LOG_UNREG "logN unregister id"
|
|
|
|
int
|
|
logwidget_cmd(cd_lp, interp, argc, argv)
|
|
ClientData cd_lp;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
DB_LOG *lp;
|
|
DB_ENV *env;
|
|
DB_LSN lsn;
|
|
DBT rec;
|
|
int id, ret;
|
|
char fstr[16], dstr[16];
|
|
|
|
debug_check();
|
|
|
|
lp = ((log_data *)cd_lp)->logp;
|
|
|
|
USAGE_GE(argc, 2, LOGWIDGET_USAGE, 0);
|
|
|
|
if (strcmp(argv[1], "close") == 0) {
|
|
USAGE(argc, 2, LOGCLOSE_USAGE, 0);
|
|
env = ((log_data *)cd_lp)->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]);
|
|
} else if (strcmp(argv[1], "flush") == 0) {
|
|
ret = log_flush_cmd(lp, interp, argc, argv);
|
|
} else if (strcmp(argv[1], "get") == 0) {
|
|
return (log_get_cmd(lp, interp, argc, argv));
|
|
} else if (strcmp(argv[1], "last") == 0) {
|
|
memset(&rec, 0, sizeof(rec));
|
|
ret = log_get(lp, &lsn, &rec, DB_LAST);
|
|
if (ret == 0) {
|
|
sprintf(fstr, "%lu", (u_long)lsn.file);
|
|
sprintf(dstr, "%lu", (u_long)lsn.offset);
|
|
Tcl_ResetResult(interp);
|
|
Tcl_AppendResult(interp, fstr, " ", dstr, 0);
|
|
return (TCL_OK);
|
|
}
|
|
} else if (strcmp(argv[1], "compare") == 0) {
|
|
return (log_compare_cmd(interp, argc, argv));
|
|
} else if (strcmp(argv[1], "file") == 0) {
|
|
return (log_file_cmd(lp, interp, argc, argv));
|
|
} else if (strcmp(argv[1], "put") == 0) {
|
|
return (log_put_cmd(lp, interp, argc, argv));
|
|
} else if (strcmp(argv[1], "register") == 0) {
|
|
return (log_reg_cmd(lp, interp, argc, argv));
|
|
} else if (strcmp(argv[1], "unregister") == 0) {
|
|
if (Tcl_GetInt(interp, argv[2], &id) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
ret = log_unregister(lp, id);
|
|
} else {
|
|
Tcl_SetResult(interp, LOGWIDGET_USAGE, TCL_STATIC);
|
|
return (TCL_ERROR);
|
|
}
|
|
|
|
if (ret != 0) {
|
|
Tcl_SetResult(interp, "log_cmd: ", TCL_STATIC);
|
|
errno = ret;
|
|
Tcl_AppendResult(interp, argv[2], " ",
|
|
Tcl_PosixError(interp), 0);
|
|
} else
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
|
return (TCL_OK);
|
|
}
|
|
|
|
/*
|
|
* Implementation of all the individual widget commands.
|
|
*/
|
|
static int
|
|
log_compare_cmd(interp, argc, argv)
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
DB_LSN lsn1, lsn2;
|
|
char resbuf[32];
|
|
int cmp;
|
|
|
|
USAGE(argc, 4, LOGCMP_USAGE, 0);
|
|
if (get_lsn(interp, argv[2], &lsn1) != TCL_OK ||
|
|
get_lsn(interp, argv[3], &lsn2) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
|
|
cmp = log_compare(&lsn1, &lsn2);
|
|
sprintf(resbuf, "%d", cmp);
|
|
Tcl_SetResult(interp, resbuf, TCL_VOLATILE);
|
|
return (TCL_OK);
|
|
}
|
|
|
|
static int
|
|
log_flush_cmd(lp, interp, argc, argv)
|
|
DB_LOG *lp;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
DB_LSN lsn;
|
|
int ret;
|
|
|
|
USAGE(argc, 3, LOGFLUSH_USAGE, 0);
|
|
if (get_lsn(interp, argv[2], &lsn) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
if (lsn.file == 0 && lsn.offset == 0)
|
|
ret = log_flush(lp, NULL);
|
|
else
|
|
ret = log_flush(lp, &lsn);
|
|
if (ret != 0)
|
|
return (TCL_ERROR);
|
|
|
|
Tcl_SetResult(interp, "0", TCL_STATIC);
|
|
return (TCL_OK);
|
|
}
|
|
|
|
static int
|
|
log_file_cmd(lp, interp, argc, argv)
|
|
DB_LOG *lp;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
DB_LSN lsn;
|
|
int ret;
|
|
char name[1024];
|
|
|
|
USAGE(argc, 3, LOGFILE_USAGE, 0);
|
|
if (get_lsn(interp, argv[2], &lsn) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
if ((ret = log_file(lp, &lsn, name, sizeof(name))) != 0) {
|
|
Tcl_SetResult(interp, "log_file: ", TCL_STATIC);
|
|
errno = ret;
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
|
return (TCL_OK);
|
|
}
|
|
Tcl_SetResult(interp, name, TCL_VOLATILE);
|
|
return (TCL_OK);
|
|
}
|
|
|
|
static int
|
|
log_get_cmd(lp, interp, argc, argv)
|
|
DB_LOG *lp;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
DB_LSN lsn;
|
|
DBT data;
|
|
u_int32_t flags;
|
|
int ret, tclint;
|
|
|
|
USAGE(argc, 4, LOGGET_USAGE, 0);
|
|
if (get_lsn(interp, argv[2], &lsn) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
flags = (u_int32_t)tclint;
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
switch (ret = log_get(lp, &lsn, &data, flags)) {
|
|
case 0: Tcl_SetResult(interp, data.data, TCL_VOLATILE);
|
|
break;
|
|
case DB_NOTFOUND: Tcl_ResetResult(interp);
|
|
break;
|
|
default:
|
|
Tcl_SetResult(interp, "log get: ", TCL_STATIC);
|
|
errno = ret;
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), 0);
|
|
break;
|
|
}
|
|
return (TCL_OK);
|
|
}
|
|
|
|
static int
|
|
log_put_cmd(lp, interp, argc, argv)
|
|
DB_LOG *lp;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
DB_LSN lsn;
|
|
DBT data;
|
|
u_int32_t flags;
|
|
int ret, tclint;
|
|
char resbuf[64];
|
|
|
|
USAGE(argc, 4, LOGPUT_USAGE, 0);
|
|
|
|
if (Tcl_GetInt(interp, argv[3], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
flags = (u_int32_t)tclint;
|
|
|
|
memset(&data, 0, sizeof(data));
|
|
data.data = argv[2];
|
|
data.size = strlen(argv[2]) + 1;
|
|
if ((ret = log_put(lp, &lsn, &data, flags)) != 0) {
|
|
errno = ret;
|
|
Tcl_SetResult(interp, "ERROR: ", TCL_STATIC);
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL);
|
|
return (TCL_ERROR);
|
|
}
|
|
|
|
sprintf(resbuf, "%lu %lu", (unsigned long)lsn.offset,
|
|
(unsigned long)lsn.file);
|
|
Tcl_SetResult(interp, resbuf, TCL_VOLATILE);
|
|
return (TCL_OK);
|
|
}
|
|
|
|
static int
|
|
log_reg_cmd(lp, interp, argc, argv)
|
|
DB_LOG *lp;
|
|
Tcl_Interp *interp;
|
|
int argc;
|
|
char *argv[];
|
|
{
|
|
DB *dbp;
|
|
DBTYPE type;
|
|
Tcl_CmdInfo cmd_info;
|
|
u_int32_t regid;
|
|
int ret, tclint;
|
|
|
|
USAGE(argc, 5, LOGREG_USAGE, 0);
|
|
if (Tcl_GetInt(interp, argv[4], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
type = (DBTYPE)tclint;
|
|
|
|
if (Tcl_GetCommandInfo(interp, argv[2], &cmd_info) != TCL_OK)
|
|
dbp = NULL;
|
|
else
|
|
dbp = (DB *)cmd_info.clientData;
|
|
ret = log_register(lp, dbp, argv[3], type, ®id);
|
|
if (ret != 0) {
|
|
errno = ret;
|
|
Tcl_SetResult(interp, "ERROR: ", TCL_STATIC);
|
|
Tcl_AppendResult(interp, Tcl_PosixError(interp), NULL);
|
|
return (TCL_ERROR);
|
|
}
|
|
sprintf(interp->result, "%lu", (unsigned long)regid);
|
|
return (TCL_OK);
|
|
}
|
|
|
|
static int
|
|
get_lsn(interp, str, lsnp)
|
|
Tcl_Interp *interp;
|
|
char *str;
|
|
DB_LSN *lsnp;
|
|
{
|
|
int largc, tclint;
|
|
char **largv;
|
|
|
|
if (Tcl_SplitList(interp, str, &largc, &largv) != TCL_OK || largc != 2)
|
|
return (TCL_ERROR);
|
|
if (Tcl_GetInt(interp, largv[0], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
lsnp->offset = (u_int32_t)tclint;
|
|
if (Tcl_GetInt(interp, largv[1], &tclint) != TCL_OK)
|
|
return (TCL_ERROR);
|
|
lsnp->file = (u_int32_t)tclint;
|
|
return (TCL_OK);
|
|
}
|