Changeset: 97b4c0bd5bc2 for MonetDB
URL: https://dev.monetdb.org/hg/MonetDB/rev/97b4c0bd5bc2
Modified Files:
        gdk/gdk_hash.c
        gdk/gdk_join.c
        gdk/gdk_private.h
        gdk/gdk_string.c
Branch: ustr
Log Message:

Try to do less double work when inserting into a ustr column.


diffs (truncated from 355 to 300 lines):

diff --git a/gdk/gdk_hash.c b/gdk/gdk_hash.c
--- a/gdk/gdk_hash.c
+++ b/gdk/gdk_hash.c
@@ -732,7 +732,7 @@ BAThashsave(BAT *b, bool dosync)
  * values in the tvheap that they point to. */
 Hash *
 BAThash_impl(BATiter *restrict bi, struct canditer *restrict ci,
-            bool offsets, const char *restrict ext)
+            bool offsets, const char *restrict ext, uint8_t width)
 {
        BAT *b = bi->b;
        lng t0 = 0;
@@ -752,6 +752,7 @@ BAThash_impl(BATiter *restrict bi, struc
        assert(strcmp(ext, "thash") != 0 || !hascand);
        assert(bi->type != TYPE_msk);
        assert(bi->type != TYPE_void);
+       assert((width & (width - 1)) == 0 && (size_t) width <= sizeof(var_t));
 
        MT_thread_setalgorithm(hascand ? "create hash with candidates" : 
"create hash");
        TRC_DEBUG_IF(ACCELERATOR) t0 = GDKusec();
@@ -764,7 +765,7 @@ BAThash_impl(BATiter *restrict bi, struc
                GDKfree(h);
                return NULL;
        }
-       h->width = HASHwidth(BATcapacity(b));
+       h->width = width <= 1 ? HASHwidth(BATcapacity(b)) : width;
        h->offsets = offsets;
        h->heaplink.dirty = true;
        h->heapbckt.dirty = true;
@@ -1099,7 +1100,7 @@ BAThash(BAT *b)
                struct canditer ci;
                BATiter bi = bat_iterator(b);;
                canditer_init(&ci, b, NULL);
-               b->thash = BAThash_impl(&bi, &ci, b->ustr != 0, "thash");
+               b->thash = BAThash_impl(&bi, &ci, b->ustr != 0, "thash", 0);
                bat_iterator_end(&bi);
                if (b->thash == NULL) {
                        MT_rwlock_wrunlock(&b->thashlock);
@@ -1155,7 +1156,7 @@ HASHprobe(const Hash *h, const void *v)
 }
 
 void
-HASHappend_locked(BATiter *bi, BUN i, const void *v)
+HASHappend_locked_hashval(BATiter *bi, BUN i, const void *v, BUN hsh)
 {
        BAT *b = bi->b;
        Hash *h = b->thash;
@@ -1200,34 +1201,56 @@ HASHappend_locked(BATiter *bi, BUN i, co
                return;
        }
        h->Link = h->heaplink.base;
-       BUN c = HASHprobe(h, v);
+       BUN c = HASHbucket(h, hsh);
        h->heaplink.free += h->width;
        BUN hb = HASHget(h, c);
-       BUN hb2;
-       if (h->offsets) {
-               for (hb2 = hb;
-                    hb2 != BUN_NONE;
-                    hb2 = HASHgetlink(h, hb2)) {
-                       if (*(var_t *) v == VarHeapVal(bi->base, hb2, 
bi->width))
-                               break;
+       if (!b->tvkey) {
+               BUN hb2;
+               if (h->offsets) {
+                       for (hb2 = hb;
+                            hb2 != BUN_NONE;
+                            hb2 = HASHgetlink(h, hb2)) {
+                               if (*(var_t *) v == VarHeapVal(bi->base, hb2, 
bi->width))
+                                       break;
+                       }
+               } else {
+                       bool (*atomeq)(const void *, const void *) = 
ATOMequal(h->type);
+                       for (hb2 = hb;
+                            hb2 != BUN_NONE;
+                            hb2 = HASHgetlink(h, hb2)) {
+                               if (atomeq(v, BUNtail(bi, hb2)))
+                                       break;
+                       }
                }
+               h->nunique += hb2 == BUN_NONE;
        } else {
-               bool (*atomeq)(const void *, const void *) = ATOMequal(h->type);
-               for (hb2 = hb;
-                    hb2 != BUN_NONE;
-                    hb2 = HASHgetlink(h, hb2)) {
-                       if (atomeq(v, BUNtail(bi, hb2)))
-                               break;
-               }
+               h->nunique++;
        }
        h->nheads += hb == BUN_NONE;
-       h->nunique += hb2 == BUN_NONE;
        HASHputlink(h, i, hb);
        HASHput(h, c, i);
        h->heapbckt.dirty = true;
        h->heaplink.dirty = true;
 }
 
+void
+HASHappend_locked(BATiter *bi, BUN i, const void *v)
+{
+       BAT *b = bi->b;
+       Hash *h = b->thash;
+       if (h == NULL) {
+               return;
+       }
+       if (h == (Hash *) 1) {
+               b->thash = NULL;
+               doHASHdestroy(b, h);
+               GDKclrerr();
+               return;
+       }
+       BUN hsh = ATOMhash(h->type, v);
+       HASHappend_locked_hashval(bi, i, v, hsh);
+}
+
 BUN
 HASHappend(BAT *b, BUN i, const void *v)
 {
diff --git a/gdk/gdk_join.c b/gdk/gdk_join.c
--- a/gdk/gdk_join.c
+++ b/gdk/gdk_join.c
@@ -2818,7 +2818,7 @@ vkeyjoin(BAT **r1p, BAT **r2p, BAT **r3p
                             (unsigned) MT_getpid()) >= (int) sizeof(ext))
                        return GDK_FAIL;
                BATiter ri = bat_iterator(r);
-               hsh = BAThash_impl(&ri, rci, true, ext);
+               hsh = BAThash_impl(&ri, rci, true, ext, 0);
                bat_iterator_end(&ri);
                if (hsh == NULL)
                        return GDK_FAIL;
@@ -3252,7 +3252,7 @@ hashjoin(BAT **r1p, BAT **r2p, BAT **r3p
                             (unsigned) MT_getpid()) >= (int) sizeof(ext))
                        goto bailout;
                BATiter ri = bat_iterator(r);
-               hsh = BAThash_impl(&ri, rci, false, ext);
+               hsh = BAThash_impl(&ri, rci, false, ext, 0);
                bat_iterator_end(&ri);
                if (hsh == NULL)
                        goto bailout;
diff --git a/gdk/gdk_private.h b/gdk/gdk_private.h
--- a/gdk/gdk_private.h
+++ b/gdk/gdk_private.h
@@ -59,7 +59,7 @@ void BATfree(BAT *b)
 gdk_return BATgroup_internal(BAT **groups, BAT **extents, BAT **histo, BAT *b, 
BAT *s, BAT *g, BAT *e, BAT *h, bool subsorted)
        __attribute__((__warn_unused_result__))
        __attribute__((__visibility__("hidden")));
-Hash *BAThash_impl(BATiter *restrict bi, struct canditer *restrict ci, bool 
offsets, const char *restrict ext)
+Hash *BAThash_impl(BATiter *restrict bi, struct canditer *restrict ci, bool 
offsets, const char *restrict ext, uint8_t width)
        __attribute__((__visibility__("hidden")));
 void BAThashsave(BAT *b, bool dosync)
        __attribute__((__visibility__("hidden")));
@@ -172,6 +172,8 @@ BUN HASHappend(BAT *b, BUN i, const void
        __attribute__((__visibility__("hidden")));
 void HASHappend_locked(BATiter *bi, BUN i, const void *v)
        __attribute__((__visibility__("hidden")));
+void HASHappend_locked_hashval(BATiter *bi, BUN i, const void *v, BUN hsh)
+       __attribute__((__visibility__("hidden")));
 void HASHfree(BAT *b)
        __attribute__((__visibility__("hidden")));
 BUN HASHdelete(BATiter *bi, BUN p, const void *v)
diff --git a/gdk/gdk_string.c b/gdk/gdk_string.c
--- a/gdk/gdk_string.c
+++ b/gdk/gdk_string.c
@@ -189,7 +189,10 @@ ustrPut(BAT *b, var_t *dst, const char *
        MT_rwlock_wrlock(&ustrbat->thashlock);
        MT_lock_set(&ustrbat->theaplock);
        assert(ustrbat->tvkey);
+
+       Heap *h = ustrbat->tvheap;
        BUN p = BUN_NONE;
+       BUN hsh = strHash(v);
        if (ustrbat->batCount != 0) {
                BATiter ui = bat_iterator_nolock(ustrbat);
                if (ustrbat->thash == NULL) {
@@ -201,15 +204,45 @@ ustrPut(BAT *b, var_t *dst, const char *
                                .hseq = ustrbat->hseqbase,
                                .ncand = ustrbat->batCount,
                        };
-                       if ((ustrbat->thash = BAThash_impl(&ui, &cui, false, 
"thash")) == NULL) {
+                       if ((ustrbat->thash = BAThash_impl(
+                                    &ui, &cui, false, "thash",
+                                    sizeof(var_t))) == NULL) {
                                MT_lock_unset(&ustrbat->theaplock);
                                MT_rwlock_wrunlock(&ustrbat->thashlock);
                                return (var_t) -1;
                        }
                }
-               HASHloop_str(&ui, ustrbat->thash, p, v)
-                       break;
+               for (p = HASHget(ustrbat->thash,
+                                HASHbucket(ustrbat->thash, hsh));
+                    p != BUN_NONE;
+                    p = HASHgetlink(ustrbat->thash, p))
+                       if (strcmp(v,
+                                  ui.vh->base + ((var_t *) ui.base)[p]) == 0)
+                               break;
+#if SIZEOF_VAR_T == 8
+       } else if (GDKupgradevarheap(ustrbat, (var_t) 1 << 33,
+                                   ustrbat->batCapacity, 0) != GDK_SUCCEED) {
+               MT_lock_unset(&ustrbat->theaplock);
+               MT_rwlock_wrunlock(&ustrbat->thashlock);
+               return (var_t) -1;
+#endif
+       } else {
+               if (h->size < GDK_STRHASHSIZE + BATTINY * GDK_VARALIGN) {
+                       if (HEAPgrow(&b->tvheap, GDK_STRHASHSIZE + BATTINY * 
GDK_VARALIGN, true) != GDK_SUCCEED) {
+                               return (var_t) -1;
+                       }
+                       h = b->tvheap;
+               }
+               h->free = GDK_STRHASHSIZE;
+#ifdef NDEBUG
+               memset(h->base, 0, h->free);
+#else
+               /* fill should solve initialization problems within valgrind */
+               memset(h->base, 0, h->size);
+#endif
+               h->dirty = true;
        }
+
        if (p == BUN_NONE) {
                /* string does not yet occur in ustrbat */
                p = ustrbat->batCount;
@@ -221,34 +254,107 @@ ustrPut(BAT *b, var_t *dst, const char *
                        }
                        ustrbat->batCapacity = (BUN) (ustrbat->theap->size >> 
ustrbat->tshift);
                }
-               if (tfastins_nochecknolockVAR(ustrbat, p, v) != GDK_SUCCEED) {
-                       MT_lock_unset(&ustrbat->theaplock);
-                       MT_rwlock_wrunlock(&ustrbat->thashlock);
+
+#ifndef NDEBUG
+               if (!checkUTF8(v)) {
+                       GDKerror("incorrectly encoded UTF-8\n");
                        return (var_t) -1;
                }
+#endif
+
+               size_t pad;
+               size_t len = strlen(v) + 1;
+
+               if (GDK_ELIMBASE(h->free) != 0) {
+                       /* no extra padding needed when no hash links needed
+                        * (but only when padding doesn't cross duplicate
+                        * elimination boundary) */
+                       pad = 0;
+               } else {
+                       pad = GDK_VARALIGN - (h->free & (GDK_VARALIGN - 1));
+                       if (GDK_ELIMBASE(h->free + pad) == 0) {
+                               /* i.e. h->free+pad < GDK_ELIMLIMIT */
+                               if (pad < sizeof(stridx_t)) {
+                                       /* make room for hash link */
+                                       pad += GDK_VARALIGN;
+                               }
+                       }
+               }
+
+               /* check heap for space */
+               if (h->free + pad + len >= h->size) {
+                       size_t newsize = MAX(h->size, 4096);
+
+                       /* double the heap size until we have enough space */
+                       do {
+                               if (newsize < 4 * 1024 * 1024)
+                                       newsize <<= 1;
+                               else
+                                       newsize += 4 * 1024 * 1024;
+                       } while (newsize <= h->free + pad + len);
+
+                       assert(newsize);
+
+                       if (h->free + pad + len >= (size_t) VAR_MAX) {
+                               GDKerror("string heap gets larger than %zuGiB.",
+                                        (size_t) VAR_MAX >> 30);
+                               return (var_t) -1;
+                       }
+                       TRC_DEBUG(HEAP, "HEAPextend in strPut %s %zu %zu\n",
+                                 h->filename, h->size, newsize);
+                       if (HEAPgrow(&ustrbat->tvheap, newsize, true) != 
GDK_SUCCEED)
+                               return (var_t) -1;
+                       h = ustrbat->tvheap;
+               }
+
+               /* insert string */
+               size_t pos = h->free + pad;
+               if (pad > 0)
+                       memset(h->base + h->free, 0, pad);
+               memcpy(h->base + pos, v, len);
+               h->free += pad + len;
+               h->dirty = true;
+               if (ustrbat->tascii) {
+                       for (const uint8_t *s = (const uint8_t *) v; *s; s++) {
+                               if (*s & 0x80) {
+                                       ustrbat->tascii = false;
+                                       b->tascii = false;
+                                       break;
+                               }
+                       }
_______________________________________________
checkin-list mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to