00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "db_config.h"
00011
00012 #ifndef NO_SYSTEM_INCLUDES
00013 #include <sys/types.h>
00014
00015 #include <stdlib.h>
00016 #include <string.h>
00017 #include <tcl.h>
00018 #endif
00019
00020 #include "db_int.h"
00021 #include "dbinc/log.h"
00022 #include "dbinc/tcl_db.h"
00023 #include "dbinc/txn.h"
00024
00025 #ifdef CONFIG_TEST
00026 static int tcl_LogcGet __P((Tcl_Interp *, int, Tcl_Obj * CONST*, DB_LOGC *));
00027
00028
00029
00030
00031
00032
00033
00034 int
00035 tcl_LogArchive(interp, objc, objv, envp)
00036 Tcl_Interp *interp;
00037 int objc;
00038 Tcl_Obj *CONST objv[];
00039 DB_ENV *envp;
00040 {
00041 static const char *archopts[] = {
00042 "-arch_abs", "-arch_data", "-arch_log", "-arch_remove",
00043 NULL
00044 };
00045 enum archopts {
00046 ARCH_ABS, ARCH_DATA, ARCH_LOG, ARCH_REMOVE
00047 };
00048 Tcl_Obj *fileobj, *res;
00049 u_int32_t flag;
00050 int i, optindex, result, ret;
00051 char **file, **list;
00052
00053 result = TCL_OK;
00054 flag = 0;
00055
00056
00057
00058
00059 i = 2;
00060 while (i < objc) {
00061 if (Tcl_GetIndexFromObj(interp, objv[i],
00062 archopts, "option", TCL_EXACT, &optindex) != TCL_OK)
00063 return (IS_HELP(objv[i]));
00064 i++;
00065 switch ((enum archopts)optindex) {
00066 case ARCH_ABS:
00067 flag |= DB_ARCH_ABS;
00068 break;
00069 case ARCH_DATA:
00070 flag |= DB_ARCH_DATA;
00071 break;
00072 case ARCH_LOG:
00073 flag |= DB_ARCH_LOG;
00074 break;
00075 case ARCH_REMOVE:
00076 flag |= DB_ARCH_REMOVE;
00077 break;
00078 }
00079 }
00080 _debug_check();
00081 list = NULL;
00082 ret = envp->log_archive(envp, &list, flag);
00083 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log archive");
00084 if (result == TCL_OK) {
00085 res = Tcl_NewListObj(0, NULL);
00086 for (file = list; file != NULL && *file != NULL; file++) {
00087 fileobj = NewStringObj(*file, strlen(*file));
00088 result = Tcl_ListObjAppendElement(interp, res, fileobj);
00089 if (result != TCL_OK)
00090 break;
00091 }
00092 Tcl_SetObjResult(interp, res);
00093 }
00094 if (list != NULL)
00095 __os_ufree(envp, list);
00096 return (result);
00097 }
00098
00099
00100
00101
00102
00103
00104
00105 int
00106 tcl_LogCompare(interp, objc, objv)
00107 Tcl_Interp *interp;
00108 int objc;
00109 Tcl_Obj *CONST objv[];
00110 {
00111 DB_LSN lsn0, lsn1;
00112 Tcl_Obj *res;
00113 int result, ret;
00114
00115 result = TCL_OK;
00116
00117
00118
00119 if (objc != 4) {
00120 Tcl_WrongNumArgs(interp, 2, objv, "lsn1 lsn2");
00121 return (TCL_ERROR);
00122 }
00123
00124 result = _GetLsn(interp, objv[2], &lsn0);
00125 if (result == TCL_ERROR)
00126 return (result);
00127 result = _GetLsn(interp, objv[3], &lsn1);
00128 if (result == TCL_ERROR)
00129 return (result);
00130
00131 _debug_check();
00132 ret = log_compare(&lsn0, &lsn1);
00133 res = Tcl_NewIntObj(ret);
00134 Tcl_SetObjResult(interp, res);
00135 return (result);
00136 }
00137
00138
00139
00140
00141
00142
00143
00144 int
00145 tcl_LogFile(interp, objc, objv, envp)
00146 Tcl_Interp *interp;
00147 int objc;
00148 Tcl_Obj *CONST objv[];
00149 DB_ENV *envp;
00150 {
00151 DB_LSN lsn;
00152 Tcl_Obj *res;
00153 size_t len;
00154 int result, ret;
00155 char *name;
00156
00157 result = TCL_OK;
00158
00159
00160
00161 if (objc != 3) {
00162 Tcl_WrongNumArgs(interp, 2, objv, "lsn");
00163 return (TCL_ERROR);
00164 }
00165
00166 result = _GetLsn(interp, objv[2], &lsn);
00167 if (result == TCL_ERROR)
00168 return (result);
00169
00170 len = MSG_SIZE;
00171 ret = ENOMEM;
00172 name = NULL;
00173 while (ret == ENOMEM) {
00174 if (name != NULL)
00175 __os_free(envp, name);
00176 ret = __os_malloc(envp, len, &name);
00177 if (ret != 0) {
00178 Tcl_SetResult(interp, db_strerror(ret), TCL_STATIC);
00179 break;
00180 }
00181 _debug_check();
00182 ret = envp->log_file(envp, &lsn, name, len);
00183 len *= 2;
00184 }
00185 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log_file");
00186 if (ret == 0) {
00187 res = NewStringObj(name, strlen(name));
00188 Tcl_SetObjResult(interp, res);
00189 }
00190
00191 if (name != NULL)
00192 __os_free(envp, name);
00193
00194 return (result);
00195 }
00196
00197
00198
00199
00200
00201
00202
00203 int
00204 tcl_LogFlush(interp, objc, objv, envp)
00205 Tcl_Interp *interp;
00206 int objc;
00207 Tcl_Obj *CONST objv[];
00208 DB_ENV *envp;
00209 {
00210 DB_LSN lsn, *lsnp;
00211 int result, ret;
00212
00213 result = TCL_OK;
00214
00215
00216
00217 if (objc > 3) {
00218 Tcl_WrongNumArgs(interp, 2, objv, "?lsn?");
00219 return (TCL_ERROR);
00220 }
00221
00222 if (objc == 3) {
00223 lsnp = &lsn;
00224 result = _GetLsn(interp, objv[2], &lsn);
00225 if (result == TCL_ERROR)
00226 return (result);
00227 } else
00228 lsnp = NULL;
00229
00230 _debug_check();
00231 ret = envp->log_flush(envp, lsnp);
00232 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log_flush");
00233 return (result);
00234 }
00235
00236
00237
00238
00239
00240
00241
00242 int
00243 tcl_LogGet(interp, objc, objv, envp)
00244 Tcl_Interp *interp;
00245 int objc;
00246 Tcl_Obj *CONST objv[];
00247 DB_ENV *envp;
00248 {
00249
00250 COMPQUIET(objv, NULL);
00251 COMPQUIET(objc, 0);
00252 COMPQUIET(envp, NULL);
00253
00254 Tcl_SetResult(interp, "FAIL: log_get deprecated\n", TCL_STATIC);
00255 return (TCL_ERROR);
00256 }
00257
00258
00259
00260
00261
00262
00263
00264 int
00265 tcl_LogPut(interp, objc, objv, envp)
00266 Tcl_Interp *interp;
00267 int objc;
00268 Tcl_Obj *CONST objv[];
00269 DB_ENV *envp;
00270 {
00271 static const char *logputopts[] = {
00272 "-flush",
00273 NULL
00274 };
00275 enum logputopts {
00276 LOGPUT_FLUSH
00277 };
00278 DB_LSN lsn;
00279 DBT data;
00280 Tcl_Obj *intobj, *res;
00281 void *dtmp;
00282 u_int32_t flag;
00283 int freedata, optindex, result, ret;
00284
00285 result = TCL_OK;
00286 flag = 0;
00287 freedata = 0;
00288 if (objc < 3) {
00289 Tcl_WrongNumArgs(interp, 2, objv, "?-args? record");
00290 return (TCL_ERROR);
00291 }
00292
00293
00294
00295
00296 memset(&data, 0, sizeof(data));
00297 ret = _CopyObjBytes(interp, objv[objc-1], &dtmp,
00298 &data.size, &freedata);
00299 if (ret != 0) {
00300 result = _ReturnSetup(interp, ret,
00301 DB_RETOK_STD(ret), "log put");
00302 return (result);
00303 }
00304 data.data = dtmp;
00305
00306
00307
00308
00309
00310 if (objc == 4) {
00311 if (Tcl_GetIndexFromObj(interp, objv[2],
00312 logputopts, "option", TCL_EXACT, &optindex) != TCL_OK) {
00313 return (IS_HELP(objv[2]));
00314 }
00315 switch ((enum logputopts)optindex) {
00316 case LOGPUT_FLUSH:
00317 flag = DB_FLUSH;
00318 break;
00319 }
00320 }
00321
00322 if (result == TCL_ERROR)
00323 return (result);
00324
00325 _debug_check();
00326 ret = envp->log_put(envp, &lsn, &data, flag);
00327 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log_put");
00328 if (result == TCL_ERROR)
00329 return (result);
00330 res = Tcl_NewListObj(0, NULL);
00331 intobj = Tcl_NewWideIntObj((Tcl_WideInt)lsn.file);
00332 result = Tcl_ListObjAppendElement(interp, res, intobj);
00333 intobj = Tcl_NewWideIntObj((Tcl_WideInt)lsn.offset);
00334 result = Tcl_ListObjAppendElement(interp, res, intobj);
00335 Tcl_SetObjResult(interp, res);
00336 if (freedata)
00337 __os_free(NULL, dtmp);
00338 return (result);
00339 }
00340
00341
00342
00343
00344
00345
00346 int
00347 tcl_LogStat(interp, objc, objv, envp)
00348 Tcl_Interp *interp;
00349 int objc;
00350 Tcl_Obj *CONST objv[];
00351 DB_ENV *envp;
00352 {
00353 DB_LOG_STAT *sp;
00354 Tcl_Obj *res;
00355 int result, ret;
00356
00357 result = TCL_OK;
00358
00359
00360
00361 if (objc != 2) {
00362 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00363 return (TCL_ERROR);
00364 }
00365 _debug_check();
00366 ret = envp->log_stat(envp, &sp, 0);
00367 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret), "log stat");
00368 if (result == TCL_ERROR)
00369 return (result);
00370
00371
00372
00373
00374
00375 res = Tcl_NewObj();
00376
00377
00378
00379 MAKE_STAT_LIST("Magic", sp->st_magic);
00380 MAKE_STAT_LIST("Log file Version", sp->st_version);
00381 MAKE_STAT_LIST("Region size", sp->st_regsize);
00382 MAKE_STAT_LIST("Log file mode", sp->st_mode);
00383 MAKE_STAT_LIST("Log record cache size", sp->st_lg_bsize);
00384 MAKE_STAT_LIST("Current log file size", sp->st_lg_size);
00385 MAKE_STAT_LIST("Log file records written", sp->st_record);
00386 MAKE_STAT_LIST("Mbytes written", sp->st_w_mbytes);
00387 MAKE_STAT_LIST("Bytes written (over Mb)", sp->st_w_bytes);
00388 MAKE_STAT_LIST("Mbytes written since checkpoint", sp->st_wc_mbytes);
00389 MAKE_STAT_LIST("Bytes written (over Mb) since checkpoint",
00390 sp->st_wc_bytes);
00391 MAKE_STAT_LIST("Times log written", sp->st_wcount);
00392 MAKE_STAT_LIST("Times log written because cache filled up",
00393 sp->st_wcount_fill);
00394 MAKE_STAT_LIST("Times log read from disk", sp->st_rcount);
00395 MAKE_STAT_LIST("Times log flushed to disk", sp->st_scount);
00396 MAKE_STAT_LIST("Current log file number", sp->st_cur_file);
00397 MAKE_STAT_LIST("Current log file offset", sp->st_cur_offset);
00398 MAKE_STAT_LIST("On-disk log file number", sp->st_disk_file);
00399 MAKE_STAT_LIST("On-disk log file offset", sp->st_disk_offset);
00400 MAKE_STAT_LIST("Max commits in a log flush", sp->st_maxcommitperflush);
00401 MAKE_STAT_LIST("Min commits in a log flush", sp->st_mincommitperflush);
00402 MAKE_STAT_LIST("Number of region lock waits", sp->st_region_wait);
00403 MAKE_STAT_LIST("Number of region lock nowaits", sp->st_region_nowait);
00404 Tcl_SetObjResult(interp, res);
00405 error:
00406 __os_ufree(envp, sp);
00407 return (result);
00408 }
00409
00410
00411
00412
00413
00414
00415
00416 int
00417 logc_Cmd(clientData, interp, objc, objv)
00418 ClientData clientData;
00419 Tcl_Interp *interp;
00420 int objc;
00421 Tcl_Obj *CONST objv[];
00422 {
00423 static const char *logccmds[] = {
00424 "close",
00425 "get",
00426 NULL
00427 };
00428 enum logccmds {
00429 LOGCCLOSE,
00430 LOGCGET
00431 };
00432 DB_LOGC *logc;
00433 DBTCL_INFO *logcip;
00434 int cmdindex, result, ret;
00435
00436 Tcl_ResetResult(interp);
00437 logc = (DB_LOGC *)clientData;
00438 logcip = _PtrToInfo((void *)logc);
00439 result = TCL_OK;
00440
00441 if (objc <= 1) {
00442 Tcl_WrongNumArgs(interp, 1, objv, "command cmdargs");
00443 return (TCL_ERROR);
00444 }
00445 if (logc == NULL) {
00446 Tcl_SetResult(interp, "NULL logc pointer", TCL_STATIC);
00447 return (TCL_ERROR);
00448 }
00449 if (logcip == NULL) {
00450 Tcl_SetResult(interp, "NULL logc info pointer", TCL_STATIC);
00451 return (TCL_ERROR);
00452 }
00453
00454
00455
00456
00457
00458 if (Tcl_GetIndexFromObj(interp, objv[1], logccmds, "command",
00459 TCL_EXACT, &cmdindex) != TCL_OK)
00460 return (IS_HELP(objv[1]));
00461 switch ((enum logccmds)cmdindex) {
00462 case LOGCCLOSE:
00463
00464
00465
00466 if (objc > 2) {
00467 Tcl_WrongNumArgs(interp, 2, objv, NULL);
00468 return (TCL_ERROR);
00469 }
00470 _debug_check();
00471 ret = logc->close(logc, 0);
00472 result = _ReturnSetup(interp, ret, DB_RETOK_STD(ret),
00473 "logc close");
00474 if (result == TCL_OK) {
00475 (void)Tcl_DeleteCommand(interp, logcip->i_name);
00476 _DeleteInfo(logcip);
00477 }
00478 break;
00479 case LOGCGET:
00480 result = tcl_LogcGet(interp, objc, objv, logc);
00481 break;
00482 }
00483 return (result);
00484 }
00485
00486 static int
00487 tcl_LogcGet(interp, objc, objv, logc)
00488 Tcl_Interp *interp;
00489 int objc;
00490 Tcl_Obj * CONST *objv;
00491 DB_LOGC *logc;
00492 {
00493 static const char *logcgetopts[] = {
00494 "-current",
00495 "-first",
00496 "-last",
00497 "-next",
00498 "-prev",
00499 "-set",
00500 NULL
00501 };
00502 enum logcgetopts {
00503 LOGCGET_CURRENT,
00504 LOGCGET_FIRST,
00505 LOGCGET_LAST,
00506 LOGCGET_NEXT,
00507 LOGCGET_PREV,
00508 LOGCGET_SET
00509 };
00510 DB_LSN lsn;
00511 DBT data;
00512 Tcl_Obj *dataobj, *lsnlist, *myobjv[2], *res;
00513 u_int32_t flag;
00514 int i, myobjc, optindex, result, ret;
00515
00516 result = TCL_OK;
00517 res = NULL;
00518 flag = 0;
00519
00520 if (objc < 3) {
00521 Tcl_WrongNumArgs(interp, 2, objv, "?-args? lsn");
00522 return (TCL_ERROR);
00523 }
00524
00525
00526
00527
00528
00529 i = 2;
00530 while (i < objc) {
00531 if (Tcl_GetIndexFromObj(interp, objv[i],
00532 logcgetopts, "option", TCL_EXACT, &optindex) != TCL_OK)
00533 return (IS_HELP(objv[i]));
00534 i++;
00535 switch ((enum logcgetopts)optindex) {
00536 case LOGCGET_CURRENT:
00537 FLAG_CHECK(flag);
00538 flag |= DB_CURRENT;
00539 break;
00540 case LOGCGET_FIRST:
00541 FLAG_CHECK(flag);
00542 flag |= DB_FIRST;
00543 break;
00544 case LOGCGET_LAST:
00545 FLAG_CHECK(flag);
00546 flag |= DB_LAST;
00547 break;
00548 case LOGCGET_NEXT:
00549 FLAG_CHECK(flag);
00550 flag |= DB_NEXT;
00551 break;
00552 case LOGCGET_PREV:
00553 FLAG_CHECK(flag);
00554 flag |= DB_PREV;
00555 break;
00556 case LOGCGET_SET:
00557 FLAG_CHECK(flag);
00558 flag |= DB_SET;
00559 if (i == objc) {
00560 Tcl_WrongNumArgs(interp, 2, objv, "?-set lsn?");
00561 result = TCL_ERROR;
00562 break;
00563 }
00564 result = _GetLsn(interp, objv[i++], &lsn);
00565 break;
00566 }
00567 }
00568
00569 if (result == TCL_ERROR)
00570 return (result);
00571
00572 memset(&data, 0, sizeof(data));
00573
00574 _debug_check();
00575 ret = logc->get(logc, &lsn, &data, flag);
00576
00577 res = Tcl_NewListObj(0, NULL);
00578 if (res == NULL)
00579 goto memerr;
00580
00581 if (ret == 0) {
00582
00583
00584
00585
00586 myobjc = 2;
00587 myobjv[0] = Tcl_NewWideIntObj((Tcl_WideInt)lsn.file);
00588 myobjv[1] = Tcl_NewWideIntObj((Tcl_WideInt)lsn.offset);
00589 lsnlist = Tcl_NewListObj(myobjc, myobjv);
00590 if (lsnlist == NULL)
00591 goto memerr;
00592
00593 result = Tcl_ListObjAppendElement(interp, res, lsnlist);
00594 dataobj = NewStringObj(data.data, data.size);
00595 if (dataobj == NULL) {
00596 goto memerr;
00597 }
00598 result = Tcl_ListObjAppendElement(interp, res, dataobj);
00599 } else
00600 result = _ReturnSetup(interp, ret, DB_RETOK_LGGET(ret),
00601 "DB_LOGC->get");
00602
00603 Tcl_SetObjResult(interp, res);
00604
00605 if (0) {
00606 memerr: if (res != NULL)
00607 Tcl_DecrRefCount(res);
00608 Tcl_SetResult(interp, "allocation failed", TCL_STATIC);
00609 }
00610
00611 return (result);
00612 }
00613 #endif