diff options
Diffstat (limited to 'src/btree/bt_method.c')
-rw-r--r-- | src/btree/bt_method.c | 745 |
1 files changed, 745 insertions, 0 deletions
diff --git a/src/btree/bt_method.c b/src/btree/bt_method.c new file mode 100644 index 00000000..5cf93d2e --- /dev/null +++ b/src/btree/bt_method.c @@ -0,0 +1,745 @@ +/*- + * See the file LICENSE for redistribution information. + * + * Copyright (c) 1999, 2012 Oracle and/or its affiliates. All rights reserved. + * + * $Id$ + */ + +#include "db_config.h" + +#include "db_int.h" +#include "dbinc/db_page.h" +#include "dbinc/btree.h" +#include "dbinc/qam.h" + +static int __bam_set_bt_minkey __P((DB *, u_int32_t)); +static int __bam_get_bt_compare + __P((DB *, int (**)(DB *, const DBT *, const DBT *))); +static int __bam_get_bt_prefix + __P((DB *, size_t(**)(DB *, const DBT *, const DBT *))); +static int __bam_set_bt_prefix + __P((DB *, size_t(*)(DB *, const DBT *, const DBT *))); +static int __bam_get_bt_compress __P((DB *, + int (**)(DB *, const DBT *, const DBT *, const DBT *, const DBT *, DBT *), + int (**)(DB *, const DBT *, const DBT *, DBT *, DBT *, DBT *))); +static int __ram_get_re_delim __P((DB *, int *)); +static int __ram_set_re_delim __P((DB *, int)); +static int __ram_set_re_len __P((DB *, u_int32_t)); +static int __ram_set_re_pad __P((DB *, int)); +static int __ram_get_re_source __P((DB *, const char **)); +static int __ram_set_re_source __P((DB *, const char *)); + +/* + * __bam_db_create -- + * Btree specific initialization of the DB structure. + * + * PUBLIC: int __bam_db_create __P((DB *)); + */ +int +__bam_db_create(dbp) + DB *dbp; +{ + BTREE *t; + int ret; + + /* Allocate and initialize the private btree structure. */ + if ((ret = __os_calloc(dbp->env, 1, sizeof(BTREE), &t)) != 0) + return (ret); + dbp->bt_internal = t; + + t->bt_minkey = DEFMINKEYPAGE; /* Btree */ + t->bt_compare = __bam_defcmp; + t->bt_prefix = __bam_defpfx; +#ifdef HAVE_COMPRESSION + t->bt_compress = NULL; + t->bt_decompress = NULL; + t->compress_dup_compare = NULL; + + /* + * DB_AM_COMPRESS may have been set in __bam_metachk before the + * bt_internal structure existed. + */ + if (F_ISSET(dbp, DB_AM_COMPRESS) && + (ret = __bam_set_bt_compress(dbp, NULL, NULL)) != 0) + return (ret); +#endif + + dbp->get_bt_compare = __bam_get_bt_compare; + dbp->set_bt_compare = __bam_set_bt_compare; + dbp->get_bt_minkey = __bam_get_bt_minkey; + dbp->set_bt_minkey = __bam_set_bt_minkey; + dbp->get_bt_prefix = __bam_get_bt_prefix; + dbp->set_bt_prefix = __bam_set_bt_prefix; + dbp->get_bt_compress = __bam_get_bt_compress; + dbp->set_bt_compress = __bam_set_bt_compress; + + t->re_pad = ' '; /* Recno */ + t->re_delim = '\n'; + t->re_eof = 1; + + dbp->get_re_delim = __ram_get_re_delim; + dbp->set_re_delim = __ram_set_re_delim; + dbp->get_re_len = __ram_get_re_len; + dbp->set_re_len = __ram_set_re_len; + dbp->get_re_pad = __ram_get_re_pad; + dbp->set_re_pad = __ram_set_re_pad; + dbp->get_re_source = __ram_get_re_source; + dbp->set_re_source = __ram_set_re_source; + + return (0); +} + +/* + * __bam_db_close -- + * Btree specific discard of the DB structure. + * + * PUBLIC: int __bam_db_close __P((DB *)); + */ +int +__bam_db_close(dbp) + DB *dbp; +{ + BTREE *t; + + if ((t = dbp->bt_internal) == NULL) + return (0); + /* Recno */ + /* Close any backing source file descriptor. */ + if (t->re_fp != NULL) + (void)fclose(t->re_fp); + + /* Free any backing source file name. */ + if (t->re_source != NULL) + __os_free(dbp->env, t->re_source); + + __os_free(dbp->env, t); + dbp->bt_internal = NULL; + + return (0); +} + +/* + * __bam_map_flags -- + * Map Btree specific flags from public to the internal values. + * + * PUBLIC: void __bam_map_flags __P((DB *, u_int32_t *, u_int32_t *)); + */ +void +__bam_map_flags(dbp, inflagsp, outflagsp) + DB *dbp; + u_int32_t *inflagsp, *outflagsp; +{ + COMPQUIET(dbp, NULL); + + if (FLD_ISSET(*inflagsp, DB_DUP)) { + FLD_SET(*outflagsp, DB_AM_DUP); + FLD_CLR(*inflagsp, DB_DUP); + } + if (FLD_ISSET(*inflagsp, DB_DUPSORT)) { + FLD_SET(*outflagsp, DB_AM_DUP | DB_AM_DUPSORT); + FLD_CLR(*inflagsp, DB_DUPSORT); + } + if (FLD_ISSET(*inflagsp, DB_RECNUM)) { + FLD_SET(*outflagsp, DB_AM_RECNUM); + FLD_CLR(*inflagsp, DB_RECNUM); + } + if (FLD_ISSET(*inflagsp, DB_REVSPLITOFF)) { + FLD_SET(*outflagsp, DB_AM_REVSPLITOFF); + FLD_CLR(*inflagsp, DB_REVSPLITOFF); + } +} + +/* + * __bam_set_flags -- + * Set Btree specific flags. + * + * PUBLIC: int __bam_set_flags __P((DB *, u_int32_t *flagsp)); + */ +int +__bam_set_flags(dbp, flagsp) + DB *dbp; + u_int32_t *flagsp; +{ + BTREE *t; + u_int32_t flags; + + t = dbp->bt_internal; + + flags = *flagsp; + if (LF_ISSET(DB_DUP | DB_DUPSORT | DB_RECNUM | DB_REVSPLITOFF)) + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags"); + + /* + * The DB_DUP and DB_DUPSORT flags are shared by the Hash + * and Btree access methods. + */ + if (LF_ISSET(DB_DUP | DB_DUPSORT)) + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH); + + if (LF_ISSET(DB_RECNUM | DB_REVSPLITOFF)) + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE | DB_OK_HASH); + + /* DB_DUP/DB_DUPSORT is incompatible with DB_RECNUM. */ + if (LF_ISSET(DB_DUP | DB_DUPSORT) && F_ISSET(dbp, DB_AM_RECNUM)) + goto incompat; + + /* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */ + if (LF_ISSET(DB_RECNUM) && F_ISSET(dbp, DB_AM_DUP)) + goto incompat; + + /* DB_RECNUM is incompatible with DB_DUP/DB_DUPSORT. */ + if (LF_ISSET(DB_RECNUM) && LF_ISSET(DB_DUP | DB_DUPSORT)) + goto incompat; + +#ifdef HAVE_COMPRESSION + /* DB_RECNUM is incompatible with compression */ + if (LF_ISSET(DB_RECNUM) && DB_IS_COMPRESSED(dbp)) { + __db_errx(dbp->env, DB_STR("1024", + "DB_RECNUM cannot be used with compression")); + return (EINVAL); + } + + /* DB_DUP without DB_DUPSORT is incompatible with compression */ + if (LF_ISSET(DB_DUP) && !LF_ISSET(DB_DUPSORT) && + !F_ISSET(dbp, DB_AM_DUPSORT) && DB_IS_COMPRESSED(dbp)) { + __db_errx(dbp->env, DB_STR("1025", + "DB_DUP cannot be used with compression without DB_DUPSORT")); + return (EINVAL); + } +#endif + + if (LF_ISSET(DB_DUPSORT) && dbp->dup_compare == NULL) { +#ifdef HAVE_COMPRESSION + if (DB_IS_COMPRESSED(dbp)) { + dbp->dup_compare = __bam_compress_dupcmp; + t->compress_dup_compare = __bam_defcmp; + } else +#endif + dbp->dup_compare = __bam_defcmp; + } + + __bam_map_flags(dbp, flagsp, &dbp->flags); + return (0); + +incompat: + return (__db_ferr(dbp->env, "DB->set_flags", 1)); +} + +/* + * __bam_get_bt_compare -- + * Get the comparison function. + */ +static int +__bam_get_bt_compare(dbp, funcp) + DB *dbp; + int (**funcp) __P((DB *, const DBT *, const DBT *)); +{ + BTREE *t; + + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + if (funcp != NULL) + *funcp = t->bt_compare; + + return (0); +} + +/* + * __bam_set_bt_compare -- + * Set the comparison function. + * + * PUBLIC: int __bam_set_bt_compare + * PUBLIC: __P((DB *, int (*)(DB *, const DBT *, const DBT *))); + */ +int +__bam_set_bt_compare(dbp, func) + DB *dbp; + int (*func) __P((DB *, const DBT *, const DBT *)); +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_compare"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + /* + * Can't default the prefix routine if the user supplies a comparison + * routine; shortening the keys can break their comparison algorithm. + */ + t->bt_compare = func; + if (t->bt_prefix == __bam_defpfx) + t->bt_prefix = NULL; + + return (0); +} + +/* + * __bam_get_bt_compress -- + * Get the compression functions. + */ +static int +__bam_get_bt_compress(dbp, compressp, decompressp) + DB *dbp; + int (**compressp) __P((DB *, const DBT *, const DBT *, const DBT *, + const DBT *, DBT *)); + int (**decompressp) __P((DB *, const DBT *, const DBT *, DBT *, DBT *, + DBT *)); +{ +#ifdef HAVE_COMPRESSION + BTREE *t; + + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + if (compressp != NULL) + *compressp = t->bt_compress; + if (decompressp != NULL) + *decompressp = t->bt_decompress; + + return (0); +#else + COMPQUIET(compressp, NULL); + COMPQUIET(decompressp, NULL); + + __db_errx(dbp->env, DB_STR("1026", + "compression support has not been compiled in")); + return (EINVAL); +#endif +} + +/* + * __bam_set_bt_compress -- + * Set the compression functions. + * + * PUBLIC: int __bam_set_bt_compress __P((DB *, + * PUBLIC: int (*)(DB *, const DBT *, const DBT *, + * PUBLIC: const DBT *, const DBT *, DBT *), + * PUBLIC: int (*)(DB *, const DBT *, const DBT *, DBT *, DBT *, DBT *))); + */ +int +__bam_set_bt_compress(dbp, compress, decompress) + DB *dbp; + int (*compress) __P((DB *, const DBT *, const DBT *, const DBT *, + const DBT *, DBT *)); + int (*decompress) __P((DB *, const DBT *, const DBT *, DBT *, DBT *, + DBT *)); +{ +#ifdef HAVE_COMPRESSION + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_compress"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + /* compression is incompatible with DB_RECNUM */ + if (F_ISSET(dbp, DB_AM_RECNUM)) { + __db_errx(dbp->env, DB_STR("1027", + "compression cannot be used with DB_RECNUM")); + return (EINVAL); + } + + /* compression is incompatible with DB_DUP without DB_DUPSORT */ + if (F_ISSET(dbp, DB_AM_DUP) && !F_ISSET(dbp, DB_AM_DUPSORT)) { + __db_errx(dbp->env, DB_STR("1028", + "compression cannot be used with DB_DUP without DB_DUPSORT")); + return (EINVAL); + } + + if (compress != 0 && decompress != 0) { + t->bt_compress = compress; + t->bt_decompress = decompress; + } else if (compress == 0 && decompress == 0) { + t->bt_compress = __bam_defcompress; + t->bt_decompress = __bam_defdecompress; + } else { + __db_errx(dbp->env, DB_STR("1029", + "to enable compression you need to supply both function arguments")); + return (EINVAL); + } + F_SET(dbp, DB_AM_COMPRESS); + + /* Copy dup_compare to compress_dup_compare, and use the compression + duplicate compare */ + if (F_ISSET(dbp, DB_AM_DUPSORT)) { + t->compress_dup_compare = dbp->dup_compare; + dbp->dup_compare = __bam_compress_dupcmp; + } + + return (0); +#else + COMPQUIET(compress, NULL); + COMPQUIET(decompress, NULL); + + __db_errx(dbp->env, DB_STR("1030", + "compression support has not been compiled in")); + return (EINVAL); +#endif +} + +/* + * __db_get_bt_minkey -- + * Get the minimum keys per page. + * + * PUBLIC: int __bam_get_bt_minkey __P((DB *, u_int32_t *)); + */ +int +__bam_get_bt_minkey(dbp, bt_minkeyp) + DB *dbp; + u_int32_t *bt_minkeyp; +{ + BTREE *t; + + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + *bt_minkeyp = t->bt_minkey; + return (0); +} + +/* + * __bam_set_bt_minkey -- + * Set the minimum keys per page. + */ +static int +__bam_set_bt_minkey(dbp, bt_minkey) + DB *dbp; + u_int32_t bt_minkey; +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_minkey"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + if (bt_minkey < 2) { + __db_errx(dbp->env, DB_STR("1031", + "minimum bt_minkey value is 2")); + return (EINVAL); + } + + t->bt_minkey = bt_minkey; + return (0); +} + +/* + * __bam_get_bt_prefix -- + * Get the prefix function. + */ +static int +__bam_get_bt_prefix(dbp, funcp) + DB *dbp; + size_t (**funcp) __P((DB *, const DBT *, const DBT *)); +{ + BTREE *t; + + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + if (funcp != NULL) + *funcp = t->bt_prefix; + return (0); +} + +/* + * __bam_set_bt_prefix -- + * Set the prefix function. + */ +static int +__bam_set_bt_prefix(dbp, func) + DB *dbp; + size_t (*func) __P((DB *, const DBT *, const DBT *)); +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_bt_prefix"); + DB_ILLEGAL_METHOD(dbp, DB_OK_BTREE); + + t = dbp->bt_internal; + + t->bt_prefix = func; + return (0); +} + +/* + * __bam_copy_config + * Copy the configuration of one DB handle to another. + * PUBLIC: void __bam_copy_config __P((DB *, DB*, u_int32_t)); + */ +void +__bam_copy_config(src, dst, nparts) + DB *src, *dst; + u_int32_t nparts; +{ + BTREE *s, *d; + + COMPQUIET(nparts, 0); + + s = src->bt_internal; + d = dst->bt_internal; + d->bt_compare = s->bt_compare; + d->bt_minkey = s->bt_minkey; + d->bt_minkey = s->bt_minkey; + d->bt_prefix = s->bt_prefix; +#ifdef HAVE_COMPRESSION + d->bt_compress = s->bt_compress; + d->bt_decompress = s->bt_decompress; + d->compress_dup_compare = s->compress_dup_compare; +#endif +} + +/* + * __ram_map_flags -- + * Map Recno specific flags from public to the internal values. + * + * PUBLIC: void __ram_map_flags __P((DB *, u_int32_t *, u_int32_t *)); + */ +void +__ram_map_flags(dbp, inflagsp, outflagsp) + DB *dbp; + u_int32_t *inflagsp, *outflagsp; +{ + COMPQUIET(dbp, NULL); + + if (FLD_ISSET(*inflagsp, DB_RENUMBER)) { + FLD_SET(*outflagsp, DB_AM_RENUMBER); + FLD_CLR(*inflagsp, DB_RENUMBER); + } + if (FLD_ISSET(*inflagsp, DB_SNAPSHOT)) { + FLD_SET(*outflagsp, DB_AM_SNAPSHOT); + FLD_CLR(*inflagsp, DB_SNAPSHOT); + } +} + +/* + * __ram_set_flags -- + * Set Recno specific flags. + * + * PUBLIC: int __ram_set_flags __P((DB *, u_int32_t *flagsp)); + */ +int +__ram_set_flags(dbp, flagsp) + DB *dbp; + u_int32_t *flagsp; +{ + u_int32_t flags; + + flags = *flagsp; + if (LF_ISSET(DB_RENUMBER | DB_SNAPSHOT)) { + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_flags"); + DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); + } + + __ram_map_flags(dbp, flagsp, &dbp->flags); + return (0); +} + +/* + * __db_get_re_delim -- + * Get the variable-length input record delimiter. + */ +static int +__ram_get_re_delim(dbp, re_delimp) + DB *dbp; + int *re_delimp; +{ + BTREE *t; + + DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); + t = dbp->bt_internal; + *re_delimp = t->re_delim; + return (0); +} + +/* + * __ram_set_re_delim -- + * Set the variable-length input record delimiter. + */ +static int +__ram_set_re_delim(dbp, re_delim) + DB *dbp; + int re_delim; +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_delim"); + DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); + + t = dbp->bt_internal; + + t->re_delim = re_delim; + F_SET(dbp, DB_AM_DELIMITER); + + return (0); +} + +/* + * __db_get_re_len -- + * Get the variable-length input record length. + * + * PUBLIC: int __ram_get_re_len __P((DB *, u_int32_t *)); + */ +int +__ram_get_re_len(dbp, re_lenp) + DB *dbp; + u_int32_t *re_lenp; +{ + BTREE *t; + QUEUE *q; + + DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); + + /* + * This has to work for all access methods, before or after opening the + * database. When the record length is set with __ram_set_re_len, the + * value in both the BTREE and QUEUE structs will be correct. + * Otherwise, this only makes sense after the database in opened, in + * which case we know the type. + */ + if (dbp->type == DB_QUEUE) { + q = dbp->q_internal; + *re_lenp = q->re_len; + } else { + t = dbp->bt_internal; + *re_lenp = t->re_len; + } + + return (0); +} + +/* + * __ram_set_re_len -- + * Set the variable-length input record length. + */ +static int +__ram_set_re_len(dbp, re_len) + DB *dbp; + u_int32_t re_len; +{ + BTREE *t; +#ifdef HAVE_QUEUE + QUEUE *q; +#endif + + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_len"); + DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); + + t = dbp->bt_internal; + t->re_len = re_len; + +#ifdef HAVE_QUEUE + q = dbp->q_internal; + q->re_len = re_len; +#endif + + F_SET(dbp, DB_AM_FIXEDLEN); + + return (0); +} + +/* + * __db_get_re_pad -- + * Get the fixed-length record pad character. + * + * PUBLIC: int __ram_get_re_pad __P((DB *, int *)); + */ +int +__ram_get_re_pad(dbp, re_padp) + DB *dbp; + int *re_padp; +{ + BTREE *t; + QUEUE *q; + + DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); + + /* + * This has to work for all access methods, before or after opening the + * database. When the record length is set with __ram_set_re_pad, the + * value in both the BTREE and QUEUE structs will be correct. + * Otherwise, this only makes sense after the database in opened, in + * which case we know the type. + */ + if (dbp->type == DB_QUEUE) { + q = dbp->q_internal; + *re_padp = q->re_pad; + } else { + t = dbp->bt_internal; + *re_padp = t->re_pad; + } + + return (0); +} + +/* + * __ram_set_re_pad -- + * Set the fixed-length record pad character. + */ +static int +__ram_set_re_pad(dbp, re_pad) + DB *dbp; + int re_pad; +{ + BTREE *t; +#ifdef HAVE_QUEUE + QUEUE *q; +#endif + + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_pad"); + DB_ILLEGAL_METHOD(dbp, DB_OK_QUEUE | DB_OK_RECNO); + + t = dbp->bt_internal; + t->re_pad = re_pad; + +#ifdef HAVE_QUEUE + q = dbp->q_internal; + q->re_pad = re_pad; +#endif + + F_SET(dbp, DB_AM_PAD); + + return (0); +} + +/* + * __db_get_re_source -- + * Get the backing source file name. + */ +static int +__ram_get_re_source(dbp, re_sourcep) + DB *dbp; + const char **re_sourcep; +{ + BTREE *t; + + DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); + + t = dbp->bt_internal; + *re_sourcep = t->re_source; + return (0); +} + +/* + * __ram_set_re_source -- + * Set the backing source file name. + */ +static int +__ram_set_re_source(dbp, re_source) + DB *dbp; + const char *re_source; +{ + BTREE *t; + + DB_ILLEGAL_AFTER_OPEN(dbp, "DB->set_re_source"); + DB_ILLEGAL_METHOD(dbp, DB_OK_RECNO); + + t = dbp->bt_internal; + + return (__os_strdup(dbp->env, re_source, &t->re_source)); +} |