diff options
Diffstat (limited to 'src/db/db_overflow.c')
-rw-r--r-- | src/db/db_overflow.c | 187 |
1 files changed, 131 insertions, 56 deletions
diff --git a/src/db/db_overflow.c b/src/db/db_overflow.c index d992ec0d..22f349ed 100644 --- a/src/db/db_overflow.c +++ b/src/db/db_overflow.c @@ -1,7 +1,7 @@ /*- * See the file LICENSE for redistribution information. * - * Copyright (c) 1996, 2012 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1996, 2015 Oracle and/or its affiliates. All rights reserved. */ /* * Copyright (c) 1990, 1993, 1994, 1995, 1996 @@ -58,39 +58,26 @@ */ /* - * __db_goff -- - * Get an offpage item. + * __db_alloc_dbt * - * PUBLIC: int __db_goff __P((DBC *, - * PUBLIC: DBT *, u_int32_t, db_pgno_t, void **, u_int32_t *)); + * Allocate enough space in the dbt to hold the data. Also used by the + * blob file API. + * + * PUBLIC: int __db_alloc_dbt __P((ENV *, DBT *, u_int32_t, u_int32_t *, + * PUBLIC: u_int32_t *, void **, u_int32_t *)); */ int -__db_goff(dbc, dbt, tlen, pgno, bpp, bpsz) - DBC *dbc; +__db_alloc_dbt(env, dbt, tlen, nd, st, bpp, bpsz) + ENV *env; DBT *dbt; u_int32_t tlen; - db_pgno_t pgno; + u_int32_t *nd; + u_int32_t *st; void **bpp; u_int32_t *bpsz; { - DB *dbp; - DB_MPOOLFILE *mpf; - DB_TXN *txn; - DBC_INTERNAL *cp; - ENV *env; - PAGE *h; - DB_THREAD_INFO *ip; - db_indx_t bytes; - u_int32_t curoff, needed, start; - u_int8_t *p, *src; int ret; - - dbp = dbc->dbp; - cp = dbc->internal; - env = dbp->env; - ip = dbc->thread_info; - mpf = dbp->mpf; - txn = dbc->txn; + u_int32_t needed, start; /* * Check if the buffer is big enough; if it is not and we are @@ -110,6 +97,8 @@ __db_goff(dbc, dbt, tlen, pgno, bpp, bpsz) start = 0; needed = tlen; } + *nd = needed; + *st = start; /* * If the caller has not requested any data, return success. This @@ -123,7 +112,7 @@ __db_goff(dbc, dbt, tlen, pgno, bpp, bpsz) } if (F_ISSET(dbt, DB_DBT_USERCOPY)) - goto skip_alloc; + return (0); /* Allocate any necessary memory. */ if (F_ISSET(dbt, DB_DBT_USERMEM)) { @@ -152,7 +141,48 @@ __db_goff(dbc, dbt, tlen, pgno, bpp, bpsz) return (DB_BUFFER_SMALL); } -skip_alloc: + return (0); +} + +/* + * __db_goff -- + * Get an offpage item. + * + * PUBLIC: int __db_goff __P((DBC *, + * PUBLIC: DBT *, u_int32_t, db_pgno_t, void **, u_int32_t *)); + */ +int +__db_goff(dbc, dbt, tlen, pgno, bpp, bpsz) + DBC *dbc; + DBT *dbt; + u_int32_t tlen; + db_pgno_t pgno; + void **bpp; + u_int32_t *bpsz; +{ + DB *dbp; + DB_MPOOLFILE *mpf; + DB_TXN *txn; + DBC_INTERNAL *cp; + ENV *env; + PAGE *h; + DB_THREAD_INFO *ip; + db_indx_t bytes; + u_int32_t curoff, needed, start; + u_int8_t *p, *src; + int ret; + + dbp = dbc->dbp; + cp = dbc->internal; + env = dbp->env; + ip = dbc->thread_info; + mpf = dbp->mpf; + txn = dbc->txn; + + if (((ret = __db_alloc_dbt( + env, dbt, tlen, &needed, &start, bpp, bpsz)) != 0) || needed == 0) + return (ret); + /* Set up a start page in the overflow chain if streaming. */ if (cp->stream_start_pgno != PGNO_INVALID && pgno == cp->stream_start_pgno && start >= cp->stream_off && @@ -485,28 +515,33 @@ __db_doff(dbc, pgno) /* * __db_moff -- - * Match on overflow pages. + * Match on overflow pages from a specific offset. * - * Given a starting page number and a key, return <0, 0, >0 to indicate if the - * key on the page is less than, equal to or greater than the key specified. - * We optimize this by doing chunk at a time comparison unless the user has - * specified a comparison function. In this case, we need to materialize - * the entire object and call their comparison routine. + * Given a starting page number and a key, store <0, 0, >0 in 'cmpp' to indicate + * if the key on the page is less than, equal to or greater than the key + * specified. We optimize this by doing a chunk at a time comparison unless the + * user has specified a comparison function. In this case, we need to + * materialize the entire object and call their comparison routine. + * + * We start the comparison at an offset and update the offset with the + * longest matching count after the comparison. * * __db_moff and __db_coff are generic functions useful in searching and * ordering off page items. __db_moff matches an overflow DBT with an offpage * item. __db_coff compares two offpage items for lexicographic sort order. * * PUBLIC: int __db_moff __P((DBC *, const DBT *, db_pgno_t, u_int32_t, - * PUBLIC: int (*)(DB *, const DBT *, const DBT *), int *)); + * PUBLIC: int (*)(DB *, const DBT *, const DBT *, size_t *), + * PUBLIC: int *, size_t *)); */ int -__db_moff(dbc, dbt, pgno, tlen, cmpfunc, cmpp) +__db_moff(dbc, dbt, pgno, tlen, cmpfunc, cmpp, locp) DBC *dbc; const DBT *dbt; db_pgno_t pgno; u_int32_t tlen; - int (*cmpfunc) __P((DB *, const DBT *, const DBT *)), *cmpp; + int (*cmpfunc) __P((DB *, const DBT *, const DBT *, size_t *)), *cmpp; + size_t *locp; { DB *dbp; DBT local_dbt; @@ -517,6 +552,7 @@ __db_moff(dbc, dbt, pgno, tlen, cmpfunc, cmpp) u_int32_t bufsize, cmp_bytes, key_left; u_int8_t *p1, *p2; int ret; + size_t pos, start; dbp = dbc->dbp; ip = dbc->thread_info; @@ -535,39 +571,76 @@ __db_moff(dbc, dbt, pgno, tlen, cmpfunc, cmpp) &local_dbt, tlen, pgno, &buf, &bufsize)) != 0) return (ret); /* Pass the key as the first argument */ - *cmpp = cmpfunc(dbp, dbt, &local_dbt); + *cmpp = cmpfunc(dbp, dbt, &local_dbt, NULL); __os_free(dbp->env, buf); return (0); } + /* + * We start the comparison from the location of 'locp' and store the + * last matching location into 'locp'. + */ + start = (locp == NULL ? 0 : *locp); + pos = 0; + + /* Subtract prefix length from lengths. */ + tlen -= (u_int32_t)start; + key_left = dbt->size - (u_int32_t)start; + p1 = (u_int8_t *)dbt->data + start; + /* While there are both keys to compare. */ - for (*cmpp = 0, p1 = dbt->data, - key_left = dbt->size; key_left > 0 && pgno != PGNO_INVALID;) { + for (*cmpp = 0; key_left > 0 && + tlen > 0 && pgno != PGNO_INVALID;) { if ((ret = __memp_fget(mpf, &pgno, ip, dbc->txn, 0, &pagep)) != 0) return (ret); - cmp_bytes = OV_LEN(pagep) < key_left ? OV_LEN(pagep) : key_left; - tlen -= cmp_bytes; - key_left -= cmp_bytes; - for (p2 = (u_int8_t *)pagep + P_OVERHEAD(dbp); - cmp_bytes-- > 0; ++p1, ++p2) - if (*p1 != *p2) { - *cmpp = (long)*p1 - (long)*p2; - break; + /* + * Figure out where to start comparison, and how many + * bytes to compare. + */ + if (pos >= start) { + p2 = (u_int8_t *)pagep + P_OVERHEAD(dbp); + cmp_bytes = OV_LEN(pagep); + } else if (pos + OV_LEN(pagep) > start) { + p2 = (u_int8_t *)pagep + + P_OVERHEAD(dbp) + (start - pos); + cmp_bytes = OV_LEN(pagep) - (u_int32_t)(start - pos); + } else { + p2 = NULL; + cmp_bytes = 0; + } + + pos += OV_LEN(pagep); + + if (cmp_bytes != 0) { + if (cmp_bytes > key_left) + cmp_bytes = key_left; + tlen -= cmp_bytes; + key_left -= cmp_bytes; + for (;cmp_bytes-- > 0; ++p1, ++p2) { + if (*p1 != *p2) { + *cmpp = (long)*p1 - (long)*p2; + break; + } + if (locp != NULL) + ++(*locp); } + + } pgno = NEXT_PGNO(pagep); if ((ret = __memp_fput(mpf, ip, pagep, dbp->priority)) != 0) return (ret); if (*cmpp != 0) return (0); } - if (key_left > 0) /* DBT is longer than the page key. */ - *cmpp = 1; - else if (tlen > 0) /* DBT is shorter than the page key. */ - *cmpp = -1; - else - *cmpp = 0; + + if (*cmpp == 0) { + if (key_left > 0) /* DBT is longer than the page key. */ + *cmpp = 1; + else if (tlen > 0) /* DBT is shorter than the page key. */ + *cmpp = -1; + } return (0); } @@ -587,13 +660,13 @@ __db_moff(dbc, dbt, pgno, tlen, cmpfunc, cmpp) * DBT type. * * PUBLIC: int __db_coff __P((DBC *, const DBT *, const DBT *, - * PUBLIC: int (*)(DB *, const DBT *, const DBT *), int *)); + * PUBLIC: int (*)(DB *, const DBT *, const DBT *, size_t *), int *)); */ int __db_coff(dbc, dbt, match, cmpfunc, cmpp) DBC *dbc; const DBT *dbt, *match; - int (*cmpfunc) __P((DB *, const DBT *, const DBT *)), *cmpp; + int (*cmpfunc) __P((DB *, const DBT *, const DBT *, size_t *)), *cmpp; { DB *dbp; DB_THREAD_INFO *ip; @@ -643,7 +716,7 @@ __db_coff(dbc, dbt, match, cmpfunc, cmpp) match_pgno, &match_buf, &match_bufsz)) != 0) goto err1; /* The key needs to be the first argument for sort order */ - *cmpp = cmpfunc(dbp, &local_key, &local_match); + *cmpp = cmpfunc(dbp, &local_key, &local_match, NULL); err1: if (dbt_buf != NULL) __os_free(dbp->env, dbt_buf); @@ -657,6 +730,7 @@ err1: if (dbt_buf != NULL) if ((ret = __memp_fget(mpf, &dbt_pgno, ip, txn, 0, &dbt_pagep)) != 0) return (ret); + DB_ASSERT(dbc->env, TYPE(dbt_pagep) == P_OVERFLOW); if ((ret = __memp_fget(mpf, &match_pgno, ip, txn, 0, &match_pagep)) != 0) { @@ -664,6 +738,7 @@ err1: if (dbt_buf != NULL) mpf, ip, dbt_pagep, DB_PRIORITY_UNCHANGED); return (ret); } + DB_ASSERT(dbc->env, TYPE(match_pagep) == P_OVERFLOW); cmp_bytes = page_space < max_data ? page_space : max_data; for (p1 = (u_int8_t *)dbt_pagep + P_OVERHEAD(dbp), p2 = (u_int8_t *)match_pagep + P_OVERHEAD(dbp); |