📄 db_load.c
字号:
/*- * See the file LICENSE for redistribution information. * * Copyright (c) 1996,2007 Oracle. All rights reserved. * * $Id: db_load.c,v 12.23 2007/05/17 17:17:42 bostic Exp $ */#include "db_config.h"#include "db_int.h"#include "dbinc/db_page.h"#include "dbinc/db_am.h"#ifndef lintstatic const char copyright[] = "Copyright (c) 1996,2007 Oracle. All rights reserved.\n";#endiftypedef struct { /* XXX: Globals. */ const char *progname; /* Program name. */ char *hdrbuf; /* Input file header. */ u_long lineno; /* Input file line number. */ u_long origline; /* Original file line number. */ int endodata; /* Reached the end of a database. */ int endofile; /* Reached the end of the input. */ int version; /* Input version. */ char *home; /* Env home. */ char *passwd; /* Env passwd. */ int private; /* Private env. */ u_int32_t cache; /* Env cache size. */} LDG;int db_load_badend __P((DB_ENV *));void db_load_badnum __P((DB_ENV *));int db_load_configure __P((DB_ENV *, DB *, char **, char **, int *));int db_load_convprintable __P((DB_ENV *, char *, char **));int db_load_db_init __P((DB_ENV *, char *, u_int32_t, int *));int db_load_dbt_rdump __P((DB_ENV *, DBT *));int db_load_dbt_rprint __P((DB_ENV *, DBT *));int db_load_dbt_rrecno __P((DB_ENV *, DBT *, int));int db_load_dbt_to_recno __P((DB_ENV *, DBT *, db_recno_t *));int db_load_env_create __P((DB_ENV **, LDG *));int db_load_load __P((DB_ENV *, char *, DBTYPE, char **, u_int, LDG *, int *));int db_load_main __P((int, char *[]));int db_load_rheader __P((DB_ENV *, DB *, DBTYPE *, char **, int *, int *));int db_load_usage __P((void));int db_load_version_check __P((void));const char *progname;#define G(f) ((LDG *)dbenv->app_private)->f /* Flags to the load function. */#define LDF_NOHEADER 0x01 /* No dump header. */#define LDF_NOOVERWRITE 0x02 /* Don't overwrite existing rows. */#define LDF_PASSWORD 0x04 /* Encrypt created databases. */intdb_load(args) char *args;{ int argc; char **argv; __db_util_arg("db_load", args, &argc, &argv); return (db_load_main(argc, argv) ? EXIT_FAILURE : EXIT_SUCCESS);}#include <stdio.h>#define ERROR_RETURN ERRORintdb_load_main(argc, argv) int argc; char *argv[];{ enum { NOTSET, FILEID_RESET, LSN_RESET, STANDARD_LOAD } mode; extern char *optarg; extern int optind, __db_getopt_reset; DBTYPE dbtype; DB_ENV *dbenv; LDG ldg; u_int ldf; int ch, existed, exitval, ret; char **clist, **clp; if ((progname = __db_rpath(argv[0])) == NULL) progname = argv[0]; else ++progname; if ((ret = db_load_version_check()) != 0) return (ret); ldg.progname = progname; ldg.lineno = 0; ldg.endodata = ldg.endofile = 0; ldg.version = 1; ldg.cache = MEGABYTE; ldg.hdrbuf = NULL; ldg.home = NULL; ldg.passwd = NULL; mode = NOTSET; ldf = 0; exitval = existed = 0; dbtype = DB_UNKNOWN; /* Allocate enough room for configuration arguments. */ if ((clp = clist = (char **)calloc((size_t)argc + 1, sizeof(char *))) == NULL) { fprintf(stderr, "%s: %s\n", ldg.progname, strerror(ENOMEM)); return (EXIT_FAILURE); } /* * There are two modes for db_load: -r and everything else. The -r * option zeroes out the database LSN's or resets the file ID, it * doesn't really "load" a new database. The functionality is in * db_load because we don't have a better place to put it, and we * don't want to create a new utility for just that functionality. */ __db_getopt_reset = 1; while ((ch = getopt(argc, argv, "c:f:h:nP:r:Tt:V")) != EOF) switch (ch) { case 'c': if (mode != NOTSET && mode != STANDARD_LOAD) return (db_load_usage()); mode = STANDARD_LOAD; *clp++ = optarg; break; case 'f': if (mode != NOTSET && mode != STANDARD_LOAD) return (db_load_usage()); mode = STANDARD_LOAD; if (freopen(optarg, "r", stdin) == NULL) { fprintf(stderr, "%s: %s: reopen: %s\n", ldg.progname, optarg, strerror(errno)); return (EXIT_FAILURE); } break; case 'h': ldg.home = optarg; break; case 'n': if (mode != NOTSET && mode != STANDARD_LOAD) return (db_load_usage()); mode = STANDARD_LOAD; ldf |= LDF_NOOVERWRITE; break; case 'P': ldg.passwd = strdup(optarg); memset(optarg, 0, strlen(optarg)); if (ldg.passwd == NULL) { fprintf(stderr, "%s: strdup: %s\n", ldg.progname, strerror(errno)); return (EXIT_FAILURE); } ldf |= LDF_PASSWORD; break; case 'r': if (mode == STANDARD_LOAD) return (db_load_usage()); if (strcmp(optarg, "lsn") == 0) mode = LSN_RESET; else if (strcmp(optarg, "fileid") == 0) mode = FILEID_RESET; else return (db_load_usage()); break; case 'T': if (mode != NOTSET && mode != STANDARD_LOAD) return (db_load_usage()); mode = STANDARD_LOAD; ldf |= LDF_NOHEADER; break; case 't': if (mode != NOTSET && mode != STANDARD_LOAD) return (db_load_usage()); mode = STANDARD_LOAD; if (strcmp(optarg, "btree") == 0) { dbtype = DB_BTREE; break; } if (strcmp(optarg, "hash") == 0) { dbtype = DB_HASH; break; } if (strcmp(optarg, "recno") == 0) { dbtype = DB_RECNO; break; } if (strcmp(optarg, "queue") == 0) { dbtype = DB_QUEUE; break; } return (db_load_usage()); case 'V': printf("%s\n", db_version(NULL, NULL, NULL)); return (EXIT_SUCCESS); case '?': default: return (db_load_usage()); } argc -= optind; argv += optind; if (argc != 1) return (db_load_usage()); /* Handle possible interruptions. */ __db_util_siginit(); /* * Create an environment object initialized for error reporting, and * then open it. */ if (db_load_env_create(&dbenv, &ldg) != 0) goto shutdown; /* If we're resetting the LSNs, that's an entirely separate path. */ switch (mode) { case FILEID_RESET: exitval = dbenv->fileid_reset( dbenv, argv[0], ldf & LDF_PASSWORD ? DB_ENCRYPT : 0); break; case LSN_RESET: exitval = dbenv->lsn_reset( dbenv, argv[0], ldf & LDF_PASSWORD ? DB_ENCRYPT : 0); break; case NOTSET: case STANDARD_LOAD: while (!ldg.endofile) if (db_load_load(dbenv, argv[0], dbtype, clist, ldf, &ldg, &existed) != 0) goto shutdown; break; } if (0) {shutdown: exitval = 1; } if ((ret = dbenv->close(dbenv, 0)) != 0) { exitval = 1; fprintf(stderr, "%s: dbenv->close: %s\n", ldg.progname, db_strerror(ret)); } /* Resend any caught signal. */ __db_util_sigresend(); free(clist); if (ldg.passwd != NULL) free(ldg.passwd); /* * Return 0 on success, 1 if keys existed already, and 2 on failure. * * Technically, this is wrong, because exit of anything other than * 0 is implementation-defined by the ANSI C standard. I don't see * any good solutions that don't involve API changes. */ return (exitval == 0 ? (existed == 0 ? 0 : 1) : 2);}/* * load -- * Load a database. */intdb_load_load(dbenv, name, argtype, clist, flags, ldg, existedp) DB_ENV *dbenv; char *name, **clist; DBTYPE argtype; u_int flags; LDG *ldg; int *existedp;{ DB *dbp; DBT key, rkey, data, *readp, *writep; DBTYPE dbtype; DB_TXN *ctxn, *txn; db_recno_t recno, datarecno; u_int32_t put_flags; int ascii_recno, checkprint, hexkeys, keyflag, keys, resize, ret, rval; char *subdb; put_flags = LF_ISSET(LDF_NOOVERWRITE) ? DB_NOOVERWRITE : 0; G(endodata) = 0; subdb = NULL; ctxn = txn = NULL; memset(&key, 0, sizeof(DBT)); memset(&data, 0, sizeof(DBT)); memset(&rkey, 0, sizeof(DBT));retry_db: dbtype = DB_UNKNOWN; keys = -1; hexkeys = -1; keyflag = -1; /* Create the DB object. */ if ((ret = db_create(&dbp, dbenv, 0)) != 0) { dbenv->err(dbenv, ret, "db_create"); goto err; } /* Read the header -- if there's no header, we expect flat text. */ if (LF_ISSET(LDF_NOHEADER)) { checkprint = 1; dbtype = argtype; } else { if (db_load_rheader(dbenv, dbp, &dbtype, &subdb, &checkprint, &keys) != 0) goto err; if (G(endofile)) goto done; } /* * Apply command-line configuration changes. (We apply command-line * configuration changes to all databases that are loaded, e.g., all * subdatabases.) */ if (db_load_configure(dbenv, dbp, clist, &subdb, &keyflag)) goto err; if (keys != 1) { if (keyflag == 1) { dbp->err(dbp, EINVAL, "No keys specified in file"); goto err; } } else if (keyflag == 0) { dbp->err(dbp, EINVAL, "Keys specified in file"); goto err; } else keyflag = 1; if (dbtype == DB_BTREE || dbtype == DB_HASH) { if (keyflag == 0) dbp->err(dbp, EINVAL, "Btree and Hash must specify keys"); else keyflag = 1; } if (argtype != DB_UNKNOWN) { if (dbtype == DB_RECNO || dbtype == DB_QUEUE) if (keyflag != 1 && argtype != DB_RECNO && argtype != DB_QUEUE) { dbenv->errx(dbenv, "improper database type conversion specified"); goto err; } dbtype = argtype; } if (dbtype == DB_UNKNOWN) { dbenv->errx(dbenv, "no database type specified"); goto err; } if (keyflag == -1) keyflag = 0; /* * Recno keys have only been printed in hexadecimal starting * with db_dump format version 3 (DB 3.2). * * !!! * Note that version is set in db_load_rheader(), which must be called before * this assignment. */ hexkeys = (G(version) >= 3 && keyflag == 1 && checkprint == 0); if (keyflag == 1 && (dbtype == DB_RECNO || dbtype == DB_QUEUE)) ascii_recno = 1; else ascii_recno = 0; /* If configured with a password, encrypt databases we create. */ if (LF_ISSET(LDF_PASSWORD) && (ret = dbp->set_flags(dbp, DB_ENCRYPT)) != 0) { dbp->err(dbp, ret, "DB->set_flags: DB_ENCRYPT"); goto err; }#if 0 Set application-specific btree comparison or hash functions here. For example: if ((ret = dbp->set_bt_compare(dbp, local_comparison_func)) != 0) { dbp->err(dbp, ret, "DB->set_bt_compare"); goto err; } if ((ret = dbp->set_h_hash(dbp, local_hash_func)) != 0) { dbp->err(dbp, ret, "DB->set_h_hash"); goto err; }#endif /* Open the DB file. */ if ((ret = dbp->open(dbp, NULL, name, subdb, dbtype, DB_CREATE | (TXN_ON(dbenv) ? DB_AUTO_COMMIT : 0), __db_omode("rw-rw-rw-"))) != 0) { dbp->err(dbp, ret, "DB->open: %s", name); goto err; } if (ldg->private != 0) { if ((ret = __db_util_cache(dbp, &ldg->cache, &resize)) != 0) goto err; if (resize) { if ((ret = dbp->close(dbp, 0)) != 0) goto err; dbp = NULL; if ((ret = dbenv->close(dbenv, 0)) != 0) goto err; if ((ret = db_load_env_create(&dbenv, ldg)) != 0) goto err; goto retry_db; } } /* Initialize the key/data pair. */ readp = writep = &key; if (dbtype == DB_RECNO || dbtype == DB_QUEUE) { key.size = sizeof(recno); if (keyflag) { key.data = &datarecno; if (checkprint) { readp = &rkey; goto key_data; } } else key.data = &recno; } elsekey_data: if ((readp->data = malloc(readp->ulen = 1024)) == NULL) { dbenv->err(dbenv, ENOMEM, NULL); goto err; } if ((data.data = malloc(data.ulen = 1024)) == NULL) { dbenv->err(dbenv, ENOMEM, NULL); goto err; } if (TXN_ON(dbenv) && (ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0) goto err; /* Get each key/data pair and add them to the database. */ for (recno = 1; !__db_util_interrupted(); ++recno) { if (!keyflag) { if (checkprint) { if (db_load_dbt_rprint(dbenv, &data)) goto err; } else { if (db_load_dbt_rdump(dbenv, &data)) goto err; } } else { if (checkprint) { if (db_load_dbt_rprint(dbenv, readp)) goto err; if (ascii_recno && db_load_dbt_to_recno(dbenv, readp, &datarecno) != 0) goto err; if (!G(endodata) && db_load_dbt_rprint(dbenv, &data)) goto odd_count; } else { if (ascii_recno) { if (db_load_dbt_rrecno(dbenv, readp, hexkeys)) goto err; } else if (db_load_dbt_rdump(dbenv, readp)) goto err; if (!G(endodata) && db_load_dbt_rdump(dbenv, &data)) {odd_count: dbenv->errx(dbenv, "odd number of key/data pairs"); goto err; } } } if (G(endodata)) break;retry: if (txn != NULL) if ((ret = dbenv->txn_begin(dbenv, txn, &ctxn, 0)) != 0) goto err; switch (ret = dbp->put(dbp, ctxn, writep, &data, put_flags)) { case 0: if (ctxn != NULL) { if ((ret = ctxn->commit(ctxn, DB_TXN_NOSYNC)) != 0) goto err; ctxn = NULL; } break; case DB_KEYEXIST: *existedp = 1; dbenv->errx(dbenv, "%s: line %d: key already exists, not loaded:", name, !keyflag ? recno : recno * 2 - 1); (void)dbenv->prdbt(&key, checkprint, 0, stderr, __db_pr_callback, 0); break; case DB_LOCK_DEADLOCK: /* If we have a child txn, retry--else it's fatal. */ if (ctxn != NULL) { if ((ret = ctxn->abort(ctxn)) != 0) goto err; ctxn = NULL; goto retry; } /* FALLTHROUGH */ default: dbenv->err(dbenv, ret, NULL); if (ctxn != NULL) { (void)ctxn->abort(ctxn); ctxn = NULL; } goto err; } if (ctxn != NULL) { if ((ret = ctxn->abort(ctxn)) != 0) goto err; ctxn = NULL; } }done: rval = 0; DB_ASSERT(dbenv, ctxn == NULL); if (txn != NULL && (ret = txn->commit(txn, 0)) != 0) { txn = NULL; goto err; } if (0) {err: rval = 1; DB_ASSERT(dbenv, ctxn == NULL); if (txn != NULL) (void)txn->abort(txn); } /* Close the database. */ if (dbp != NULL && (ret = dbp->close(dbp, 0)) != 0) { dbenv->err(dbenv, ret, "DB->close"); rval = 1; } if (G(hdrbuf) != NULL) free(G(hdrbuf)); G(hdrbuf) = NULL; /* Free allocated memory. */ if (subdb != NULL) free(subdb); if (dbtype != DB_RECNO && dbtype != DB_QUEUE && key.data != NULL) free(key.data); if (rkey.data != NULL) free(rkey.data); free(data.data); return (rval);}/* * env_create -- * Create the environment and initialize it for error reporting. */intdb_load_env_create(dbenvp, ldg) DB_ENV **dbenvp; LDG *ldg;{ DB_ENV *dbenv; int ret; if ((ret = db_env_create(dbenvp, 0)) != 0) { fprintf(stderr, "%s: db_env_create: %s\n", ldg->progname, db_strerror(ret)); return (ret); } dbenv = *dbenvp; dbenv->set_errfile(dbenv, stderr); dbenv->set_errpfx(dbenv, ldg->progname); if (ldg->passwd != NULL && (ret = dbenv->set_encrypt(dbenv, ldg->passwd, DB_ENCRYPT_AES)) != 0) { dbenv->err(dbenv, ret, "set_passwd"); return (ret); } if ((ret = db_load_db_init(dbenv, ldg->home, ldg->cache, &ldg->private)) != 0) return (ret); dbenv->app_private = ldg; return (0);}/* * db_init -- * Initialize the environment. */intdb_load_db_init(dbenv, home, cache, is_private) DB_ENV *dbenv; char *home; u_int32_t cache; int *is_private;{ u_int32_t flags; int ret; *is_private = 0; /* We may be loading into a live environment. Try and join. */ flags = DB_USE_ENVIRON | DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_MPOOL | DB_INIT_TXN; if ((ret = dbenv->open(dbenv, home, flags, 0)) == 0) return (0); if (ret == DB_VERSION_MISMATCH) goto err; /* * We're trying to load a database. * * An environment is required because we may be trying to look at * databases in directories other than the current one. We could * avoid using an environment iff the -h option wasn't specified, * but that seems like more work than it's worth. * * No environment exists (or, at least no environment that includes * an mpool region exists). Create one, but make it private so that * no files are actually created. */ LF_CLR(DB_INIT_LOCK | DB_INIT_LOG | DB_INIT_TXN); LF_SET(DB_CREATE | DB_PRIVATE); *is_private = 1; if ((ret = dbenv->set_cachesize(dbenv, 0, cache, 1)) != 0) { dbenv->err(dbenv, ret, "set_cachesize"); return (1); } if ((ret = dbenv->open(dbenv, home, flags, 0)) == 0) return (0); /* An environment is required. */err: dbenv->err(dbenv, ret, "DB_ENV->open"); return (1);}#define FLAG(name, value, keyword, flag) \ if (strcmp(name, keyword) == 0) { \ switch (*value) { \
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -