Changeset: d84ad1a28059 for MonetDB URL: http://dev.monetdb.org/hg/MonetDB?cmd=changeset;node=d84ad1a28059 Modified Files: monetdb5/mal/mal_namespace.c Branch: Jun2016 Log Message:
Namespace implementation updated. Get rid of ehash: we can append to a linked list after having searched it without extra cost without the need for an extra pointer. Declare hash as an array instead of a pointer to an array that has to be allocated. Reduce the size of identifiers to IDLENGTH (64) from MAXIDENTLEN (1024). Allocate name records from a big chunk of memory to reduce malloc overhead and potential memory fragmentation. Hopefully all of this reduces the problems described in bug 4009. diffs (230 lines): diff --git a/monetdb5/mal/mal_namespace.c b/monetdb5/mal/mal_namespace.c --- a/monetdb5/mal/mal_namespace.c +++ b/monetdb5/mal/mal_namespace.c @@ -19,38 +19,36 @@ #define HASHMASK 4095 /* taken from gdk_atoms */ -#define NME_HASH(x,y,K) \ - do { \ - const char *_key = (const char *) (x); \ - size_t _i; \ - for (_i = y = 0; K-- && _key[_i]; _i++) { \ - y += _key[_i]; \ - y += (y << 10); \ - y ^= (y >> 6); \ - } \ - y += (y << 3); \ - y ^= (y >> 11); \ - y += (y << 15); \ - y = y & HASHMASK; \ +#define NME_HASH(_key,y,K) \ + do { \ + size_t _i; \ + for (_i = y = 0; _i < K && _key[_i]; _i++) { \ + y += _key[_i]; \ + y += (y << 10); \ + y ^= (y >> 6); \ + } \ + y += (y << 3); \ + y ^= (y >> 11); \ + y += (y << 15); \ + y = y & HASHMASK; \ } while (0) typedef struct NAME{ - size_t length; struct NAME *next; - char nme[FLEXIBLE_ARRAY_MEMBER]; + char nme[IDLENGTH + 1]; + unsigned short length; } *NamePtr; -static NamePtr *hash= NULL, *ehash = NULL; +static NamePtr hash[MAXIDENTIFIERS]; + +static struct namespace { + struct namespace *next; + int count; + struct NAME data[4096]; +} *namespace; void initNamespace(void) { - if(hash == NULL) hash= (NamePtr *) GDKzalloc(sizeof(NamePtr) * MAXIDENTIFIERS); - if(ehash == NULL) ehash= (NamePtr *) GDKzalloc(sizeof(NamePtr) * MAXIDENTIFIERS); - if ( hash == NULL || ehash == NULL){ - /* absolute an error we can not recover from */ - showException(GDKout, MAL,"initNamespace",MAL_MALLOC_FAIL); - mal_exit(); - } } void mal_namespace_reset(void) { @@ -59,17 +57,13 @@ void mal_namespace_reset(void) { /* assume we are at the end of the server session */ MT_lock_set(&mal_namespaceLock); - for ( i =0; i < HASHMASK; i++){ - n = hash[i]; - hash[i] = ehash[i] = 0; - for( ; n; n = m){ + for ( i =0; i < MAXIDENTIFIERS; i++){ + for(n = hash[i]; n; n = m){ m = n->next; GDKfree(n); } + hash[i] = 0; } - GDKfree(hash); - GDKfree(ehash); - hash = ehash = 0; MT_lock_unset(&mal_namespaceLock); } @@ -80,29 +74,76 @@ void mal_namespace_reset(void) { * is conflict free. */ +static str findName(const char *nme, size_t len, int allocate) +{ + NamePtr *n, m; + size_t key; + + assert(len == 0 || nme != NULL); + if (len == 0 || nme == NULL) + return NULL; + if (len > IDLENGTH) { + len = IDLENGTH; + } + NME_HASH(nme, key, len); + MT_lock_set(&mal_namespaceLock); + for (n = &hash[key]; *n; n = &(*n)->next) { +#ifdef KEEP_SORTED + /* keep each list sorted on length, then name */ + if (len < (*n)->length) + continue; + if (len == (*n)->length) { + int c; + if ((c = strncmp(nme, (*n)->nme, len)) < 0) + continue; + if (c == 0) { + MT_lock_unset(&mal_namespaceLock); + return (*n)->nme; + } + break; + } + break; +#else + /* append entries to list */ + if (len == (*n)->length && strncmp(nme, (*n)->nme, len) == 0) { + MT_lock_unset(&mal_namespaceLock); + return (*n)->nme; + } +#endif + } + /* item not found */ + if (!allocate) { + MT_lock_unset(&mal_namespaceLock); + return NULL; + } + if (namespace == NULL || namespace->count == 4096) { + struct namespace *ns = GDKmalloc(sizeof(struct namespace)); + if (ns == NULL) { + /* error we cannot recover from */ + showException(GDKout, MAL, "findName", MAL_MALLOC_FAIL); + mal_exit(); + } + ns->next = namespace; + ns->count = 0; + namespace = ns; + } + m = &namespace->data[namespace->count++]; + strncpy(m->nme, nme, len); + m->nme[len] = 0; + m->length = (unsigned short) len; + m->next = *n; + *n = m; + MT_lock_unset(&mal_namespaceLock); + return (*n)->nme; +} + str getName(const char *nme) { - return getNameLen(nme, strlen(nme)); + return findName(nme, strlen(nme), 0); } str getNameLen(const char *nme, size_t len) { - NamePtr n; - size_t l = len, key; - - if(len == 0 || nme== NULL || *nme==0) - return NULL; - if(len>=MAXIDENTLEN) - len = MAXIDENTLEN - 1; - NME_HASH(nme, key, l); - if ( ( n = hash[(int)key]) == 0) - return NULL; - - do { - if (len == n->length && strncmp(nme,n->nme,len)==0) - return n->nme; - n = n->next; - } while (n); - return NULL; + return findName(nme, len, 0); } /* * Name deletion from the namespace is tricky, because there may @@ -121,48 +162,10 @@ void delName(const char *nme, size_t len } str putName(const char *nme) { - return putNameLen(nme, strlen(nme)); + return findName(nme, strlen(nme), 1); } str putNameLen(const char *nme, size_t len) { - size_t l,k; - int key; - str fnd; - NamePtr n; - - fnd = getNameLen(nme,len); - if ( fnd ) - return fnd; - - if( nme == NULL || len == 0) - return NULL; - - /* construct a new entry */ - if(len>=MAXIDENTLEN) - len = MAXIDENTLEN - 1; - n = GDKmalloc(offsetof(struct NAME, nme) + len + 1); - if ( n == NULL) { - /* absolute an error we can not recover from */ - showException(GDKout, MAL,"initNamespace",MAL_MALLOC_FAIL); - mal_exit(); - } - memcpy(n->nme, nme, len); - n->nme[len]=0; - n->length = len; - n->next = NULL; - l = len; - NME_HASH(nme, k, l); - key = (int) k; - - MT_lock_set(&mal_namespaceLock); - /* add new elements to the end of the list */ - if ( ehash[key] == 0) - hash[key] = ehash[key] = n; - else { - ehash[key]->next = n; - ehash[key] = n; - } - MT_lock_unset(&mal_namespaceLock); - return putNameLen(nme, len); /* just to be sure */ + return findName(nme, len, 1); } _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list