Changeset: 82770f91d174 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/82770f91d174 Modified Files: gdk/gdk_bbp.c gdk/gdk_private.h gdk/gdk_utils.c Branch: multi-cachelock Log Message:
Partition the GDKcacheLock and improve the BBP allocation algorithm diffs (truncated from 333 to 300 lines): diff --git a/gdk/gdk_bbp.c b/gdk/gdk_bbp.c --- a/gdk/gdk_bbp.c +++ b/gdk/gdk_bbp.c @@ -110,8 +110,18 @@ struct BBPfarm_t BBPfarms[MAXFARMS]; static MT_Lock BBPnameLock = MT_LOCK_INITIALIZER(BBPnameLock); static bat *BBP_hash = NULL; /* BBP logical name hash buckets */ static bat BBP_mask = 0; /* number of buckets = & mask */ -static MT_Lock GDKcacheLock = MT_LOCK_INITIALIZER(GDKcacheLock); -static bat BBP_free; +#define BBP_THREADMASK 64 +#if SIZEOF_SIZE_T == 8 +#define threadmask(y) ((int) (mix_lng(y) & BBP_THREADMASK)) +#else +#define threadmask(y) ((int) (mix_int(y) & BBP_THREADMASK)) +#endif +static struct { + MT_Lock cache; + bat free; +} GDKbbpLock[BBP_THREADMASK + 1]; +#define GDKcacheLock(y) GDKbbpLock[y].cache +#define BBP_free(y) GDKbbpLock[y].free static gdk_return BBPfree(BAT *b); static void BBPdestroy(BAT *b); @@ -281,7 +291,8 @@ BBPlock(void) } MT_lock_set(&GDKtmLock); - MT_lock_set(&GDKcacheLock); + for (i = 0; i <= BBP_THREADMASK; i++) + MT_lock_set(&GDKcacheLock(i)); for (i = 0; i <= BBP_BATMASK; i++) MT_lock_set(&GDKswapLock(i)); locked_by = MT_getpid(); @@ -296,14 +307,16 @@ BBPunlock(void) for (i = BBP_BATMASK; i >= 0; i--) MT_lock_unset(&GDKswapLock(i)); - MT_lock_unset(&GDKcacheLock); + for (i = BBP_THREADMASK; i >= 0; i--) + MT_lock_unset(&GDKcacheLock(i)); locked_by = 0; MT_lock_unset(&GDKtmLock); } static gdk_return -BBPinithash(bat size) +BBPinithash(int j, bat size) { + assert(j >= 0 && j <= BBP_THREADMASK); for (BBP_mask = 1; (BBP_mask << 1) <= BBPlimit; BBP_mask <<= 1) ; BBP_hash = (bat *) GDKzalloc(BBP_mask * sizeof(bat)); @@ -320,8 +333,10 @@ BBPinithash(bat size) BBP_insert(size); } } else { - BBP_next(size) = BBP_free; - BBP_free = size; + BBP_next(size) = BBP_free(j); + BBP_free(j) = size; + if (++j > BBP_THREADMASK) + j = 0; } } return GDK_SUCCEED; @@ -355,7 +370,7 @@ BBPselectfarm(role_t role, int type, enu } static gdk_return -BBPextend(bool buildhash, bat newsize) +BBPextend(int idx, bool buildhash, bat newsize) { if (newsize >= N_BBPINIT * BBPINIT) { GDKerror("trying to extend BAT pool beyond the " @@ -380,10 +395,12 @@ BBPextend(bool buildhash, bat newsize) } if (buildhash) { + int i; GDKfree(BBP_hash); BBP_hash = NULL; - BBP_free = 0; - if (BBPinithash(newsize) != GDK_SUCCEED) + for (i = 0; i <= BBP_THREADMASK; i++) + BBP_free(i) = 0; + if (BBPinithash(idx, newsize) != GDK_SUCCEED) return GDK_FAIL; } return GDK_SUCCEED; @@ -774,7 +791,7 @@ BBPreadEntries(FILE *fp, unsigned bbpver if (b.batCacheid >= (bat) ATOMIC_GET(&BBPsize)) { if ((bat) ATOMIC_GET(&BBPsize) + 1 >= BBPlimit && - BBPextend(false, b.batCacheid + 1) != GDK_SUCCEED) + BBPextend(0, false, b.batCacheid + 1) != GDK_SUCCEED) goto bailout; ATOMIC_SET(&BBPsize, b.batCacheid + 1); } @@ -1520,7 +1537,7 @@ BBPmanager(void *dummy) static MT_Id manager; gdk_return -BBPinit(void) +BBPinit(bool first) { FILE *fp = NULL; struct stat st; @@ -1545,6 +1562,15 @@ BBPinit(void) * array */ static_assert((uint64_t) N_BBPINIT * BBPINIT < (UINT64_C(1) << (3 * (sizeof(BBP[0][0].bak) - 5))), "\"bak\" array in BBPrec is too small"); + if (first) { + for (i = 0; i <= BBP_THREADMASK; i++) { + char name[MT_NAME_LEN]; + snprintf(name, sizeof(name), "GDKcacheLock%d", i); + MT_lock_init(&GDKbbpLock[i].cache, name); + GDKbbpLock[i].free = 0; + } + } + if (!GDKinmemory(0)) { str bbpdirstr, backupbbpdirstr; @@ -1662,7 +1688,7 @@ BBPinit(void) } /* allocate BBP records */ - if (BBPextend(false, bbpsize) != GDK_SUCCEED) { + if (BBPextend(0, false, bbpsize) != GDK_SUCCEED) { GDKdebug = dbg; return GDK_FAIL; } @@ -1681,7 +1707,7 @@ BBPinit(void) } MT_lock_set(&BBPnameLock); - if (BBPinithash((bat) ATOMIC_GET(&BBPsize)) != GDK_SUCCEED) { + if (BBPinithash(0, (bat) ATOMIC_GET(&BBPsize)) != GDK_SUCCEED) { TRC_CRITICAL(GDK, "BBPinithash failed"); MT_lock_unset(&BBPnameLock); #ifdef GDKLIBRARY_HASHASH @@ -2354,26 +2380,49 @@ BBPgetsubdir(str s, bat i) *s = 0; } -/* The free list is empty. We create a new entry by either just - * increasing BBPsize (up to BBPlimit) or extending the BBP (which - * increases BBPlimit). - * - * Note that this is the only place in normal, multi-threaded operation - * where BBPsize is assigned a value (never decreasing), that the - * assignment happens after any necessary memory was allocated and - * initialized, and that this happens when the BBPnameLock is held. */ +/* + * Extends the bpp list of some thread by reserving from the common pool, + * increasing the common pool if it runs out of space. + */ static gdk_return -maybeextend(void) -{ +extendThreadBbpList(int idx) { + /* release the current gdkcachelock first to avoid dealocks when extending the common pool */ + MT_lock_unset(&GDKcacheLock(idx)); + MT_lock_set(&BBPnameLock); + MT_lock_set(&GDKcacheLock(idx)); + + /* thread list was already extended by another concurrent transaction */ + if (BBP_free(idx) > 0) { + MT_lock_unset(&BBPnameLock); + return GDK_SUCCEED; + } + bat size = (bat) ATOMIC_GET(&BBPsize); - if (size >= BBPlimit && - BBPextend(true, size + 1) != GDK_SUCCEED) { - /* nothing available */ - return GDK_FAIL; - } else { - ATOMIC_SET(&BBPsize, size + 1); - BBP_free = size; + /* if the common pool has no more space, extend it */ + if (size >= BBPlimit) { + /* acquire all gdkcachelocks in the same order */ + for (int i = 0; i <= BBP_THREADMASK; i++) { + if (i != idx) { + MT_lock_set(&GDKcacheLock(i)); + } + } + /* extend the common pool */ + gdk_return r = BBPextend(idx, true, size + 1); + /* release all gdkcachelocks */ + for (int i = BBP_THREADMASK; i >= 0; i--) { + if (i != idx) { + MT_lock_unset(&GDKcacheLock(i)); + } + } + if (r != GDK_SUCCEED) { + return GDK_FAIL; + } } + ATOMIC_SET(&BBPsize, size + 1); + + /* extend the thread list */ + BBP_free(idx) = size; + MT_lock_unset(&BBPnameLock); return GDK_SUCCEED; } @@ -2386,36 +2435,28 @@ BBPinsert(BAT *bn) char dirname[24]; bat i; int len = 0; + int idx = threadmask(pid); /* critical section: get a new BBP entry */ if (lock) { - MT_lock_set(&GDKcacheLock); + MT_lock_set(&GDKcacheLock(idx)); } - /* find an empty slot */ - if (BBP_free <= 0) { - /* we need to extend the BBP */ - gdk_return r = GDK_SUCCEED; - MT_lock_set(&BBPnameLock); - /* check again in case some other thread extended - * while we were waiting */ - if (BBP_free <= 0) { - r = maybeextend(); - } - MT_lock_unset(&BBPnameLock); + if (BBP_free(idx) <= 0) { + /* does not have free ids, get from the common pool */ + gdk_return r = extendThreadBbpList(idx); if (r != GDK_SUCCEED) { - if (lock) { - MT_lock_unset(&GDKcacheLock); - } + GDKerror("Extend BBplist failed.\n"); return 0; } } - i = BBP_free; + + i = BBP_free(idx); assert(i > 0); - BBP_free = BBP_next(i); + BBP_free(idx) = BBP_next(i); if (lock) { - MT_lock_unset(&GDKcacheLock); + MT_lock_unset(&GDKcacheLock(idx)); } /* rest of the work outside the lock */ @@ -2523,13 +2564,13 @@ BBPuncacheit(bat i, bool unloaddesc) * BBPclear removes a BAT from the BBP directory forever. */ static inline void -bbpclear(bat i, bool lock) +bbpclear(bat i, int idx, bool lock) { TRC_DEBUG(BAT_, "clear %d (%s)\n", (int) i, BBP_logical(i)); BBPuncacheit(i, true); TRC_DEBUG(BAT_, "set to unloading %d\n", i); if (lock) { - MT_lock_set(&GDKcacheLock); + MT_lock_set(&GDKcacheLock(idx)); MT_lock_set(&GDKswapLock(i)); } @@ -2547,19 +2588,20 @@ bbpclear(bat i, bool lock) GDKfree(BBP_logical(i)); BBP_status_set(i, 0); BBP_logical(i) = NULL; - BBP_next(i) = BBP_free; - BBP_free = i; + BBP_next(i) = BBP_free(idx); + BBP_free(idx) = i; BBP_pid(i) = ~(MT_Id)0; /* not zero, not a valid thread id */ if (lock) - MT_lock_unset(&GDKcacheLock); + MT_lock_unset(&GDKcacheLock(idx)); } void BBPclear(bat i, bool lock) { - lock &= locked_by == 0 || locked_by != MT_getpid(); + MT_Id pid = MT_getpid(); + lock &= locked_by == 0 || locked_by != pid; if (BBPcheck(i)) { - bbpclear(i, lock); + bbpclear(i, threadmask(pid), lock); } } @@ -4381,7 +4423,9 @@ gdk_bbp_reset(void) { _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org