]> git.saurik.com Git - apple/libc.git/blobdiff - db/btree/bt_overflow.c
Libc-262.tar.gz
[apple/libc.git] / db / btree / bt_overflow.c
diff --git a/db/btree/bt_overflow.c b/db/btree/bt_overflow.c
new file mode 100644 (file)
index 0000000..dc73942
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License").  You may not use this file except in compliance with the
+ * License.  Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ * 
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+/*
+ * Copyright (c) 1990, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Mike Olson.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+
+#include <sys/param.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <db.h>
+#include "btree.h"
+
+/*
+ * Big key/data code.
+ *
+ * Big key and data entries are stored on linked lists of pages.  The initial
+ * reference is byte string stored with the key or data and is the page number
+ * and size.  The actual record is stored in a chain of pages linked by the
+ * nextpg field of the PAGE header.
+ *
+ * The first page of the chain has a special property.  If the record is used
+ * by an internal page, it cannot be deleted and the P_PRESERVE bit will be set
+ * in the header.
+ *
+ * XXX
+ * A single DBT is written to each chain, so a lot of space on the last page
+ * is wasted.  This is a fairly major bug for some data sets.
+ */
+
+/*
+ * __OVFL_GET -- Get an overflow key/data item.
+ *
+ * Parameters:
+ *     t:      tree
+ *     p:      pointer to { pgno_t, size_t }
+ *     buf:    storage address
+ *     bufsz:  storage size
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_get(t, p, ssz, buf, bufsz)
+       BTREE *t;
+       void *p;
+       size_t *ssz;
+       char **buf;
+       size_t *bufsz;
+{
+       PAGE *h;
+       pgno_t pg;
+       size_t nb, plen, sz;
+
+       memmove(&pg, p, sizeof(pgno_t));
+       memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(size_t));
+       *ssz = sz;
+
+#ifdef DEBUG
+       if (pg == P_INVALID || sz == 0)
+               abort();
+#endif
+       /* Make the buffer bigger as necessary. */
+       if (*bufsz < sz) {
+               if ((*buf = (char *)realloc(*buf, sz)) == NULL)
+                       return (RET_ERROR);
+               *bufsz = sz;
+       }
+
+       /*
+        * Step through the linked list of pages, copying the data on each one
+        * into the buffer.  Never copy more than the data's length.
+        */
+       plen = t->bt_psize - BTDATAOFF;
+       for (p = *buf;; p = (char *)p + nb, pg = h->nextpg) {
+               if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                       return (RET_ERROR);
+
+               nb = MIN(sz, plen);
+               memmove(p, (char *)h + BTDATAOFF, nb);
+               mpool_put(t->bt_mp, h, 0);
+
+               if ((sz -= nb) == 0)
+                       break;
+       }
+       return (RET_SUCCESS);
+}
+
+/*
+ * __OVFL_PUT -- Store an overflow key/data item.
+ *
+ * Parameters:
+ *     t:      tree
+ *     data:   DBT to store
+ *     pgno:   storage page number
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_put(t, dbt, pg)
+       BTREE *t;
+       const DBT *dbt;
+       pgno_t *pg;
+{
+       PAGE *h, *last;
+       void *p;
+       pgno_t npg;
+       size_t nb, plen, sz;
+
+       /*
+        * Allocate pages and copy the key/data record into them.  Store the
+        * number of the first page in the chain.
+        */
+       plen = t->bt_psize - BTDATAOFF;
+       for (last = NULL, p = dbt->data, sz = dbt->size;;
+           p = (char *)p + plen, last = h) {
+               if ((h = __bt_new(t, &npg)) == NULL)
+                       return (RET_ERROR);
+
+               h->pgno = npg;
+               h->nextpg = h->prevpg = P_INVALID;
+               h->flags = P_OVERFLOW;
+               h->lower = h->upper = 0;
+
+               nb = MIN(sz, plen);
+               memmove((char *)h + BTDATAOFF, p, nb);
+
+               if (last) {
+                       last->nextpg = h->pgno;
+                       mpool_put(t->bt_mp, last, MPOOL_DIRTY);
+               } else
+                       *pg = h->pgno;
+
+               if ((sz -= nb) == 0) {
+                       mpool_put(t->bt_mp, h, MPOOL_DIRTY);
+                       break;
+               }
+       }
+       return (RET_SUCCESS);
+}
+
+/*
+ * __OVFL_DELETE -- Delete an overflow chain.
+ *
+ * Parameters:
+ *     t:      tree
+ *     p:      pointer to { pgno_t, size_t }
+ *
+ * Returns:
+ *     RET_ERROR, RET_SUCCESS
+ */
+int
+__ovfl_delete(t, p)
+       BTREE *t;
+       void *p;
+{
+       PAGE *h;
+       pgno_t pg;
+       size_t plen, sz;
+
+       memmove(&pg, p, sizeof(pgno_t));
+       memmove(&sz, (char *)p + sizeof(pgno_t), sizeof(size_t));
+
+#ifdef DEBUG
+       if (pg == P_INVALID || sz == 0)
+               abort();
+#endif
+       if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+               return (RET_ERROR);
+
+       /* Don't delete chains used by internal pages. */
+       if (h->flags & P_PRESERVE) {
+               mpool_put(t->bt_mp, h, 0);
+               return (RET_SUCCESS);
+       }
+
+       /* Step through the chain, calling the free routine for each page. */
+       for (plen = t->bt_psize - BTDATAOFF;; sz -= plen) {
+               pg = h->nextpg;
+               __bt_free(t, h);
+               if (sz <= plen)
+                       break;
+               if ((h = mpool_get(t->bt_mp, pg, 0)) == NULL)
+                       return (RET_ERROR);
+       }
+       return (RET_SUCCESS);
+}