1/*
2 * This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 *
6 * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V.
7 */
8
9/*
10 * (author) M.L. Kersten
11 */
12#include "monetdb_config.h"
13#include "mal_type.h"
14#include "mal_namespace.h"
15#include "mal_exception.h"
16#include "mal_private.h"
17
18#define MAXIDENTIFIERS 4096
19#define HASHMASK 4095
20
21MT_Lock mal_namespaceLock = MT_LOCK_INITIALIZER("mal_namespaceLk");
22
23/* taken from gdk_atoms */
24#define NME_HASH(_key,y,K) \
25 do { \
26 size_t _i; \
27 for (_i = y = 0; _i < K && _key[_i]; _i++) { \
28 y += _key[_i]; \
29 y += (y << 10); \
30 y ^= (y >> 6); \
31 } \
32 y += (y << 3); \
33 y ^= (y >> 11); \
34 y += (y << 15); \
35 y = y & HASHMASK; \
36 } while (0)
37
38typedef struct NAME{
39 struct NAME *next;
40 char nme[IDLENGTH + 1];
41 unsigned short length;
42} *NamePtr;
43
44static NamePtr hash[MAXIDENTIFIERS];
45
46static struct namespace {
47 struct namespace *next;
48 int count;
49 struct NAME data[4096];
50} *namespace;
51
52void initNamespace(void) {
53 namespace = NULL;
54}
55
56void mal_namespace_reset(void) {
57 struct namespace *ns;
58
59 /* assume we are at the end of the server session */
60 MT_lock_set(&mal_namespaceLock);
61 memset(hash, 0, sizeof(hash));
62 while (namespace) {
63 ns = namespace->next;
64 GDKfree(namespace);
65 namespace = ns;
66 }
67 MT_lock_unset(&mal_namespaceLock);
68}
69
70/*
71 * Before a name is being stored we should check for its occurrence first.
72 * The administration is initialized incrementally.
73 * Beware, the routine getName relies on data structure maintenance that
74 * is conflict free.
75 */
76
77static str findName(const char *nme, size_t len, int allocate)
78{
79 NamePtr *n, m;
80 size_t key;
81
82 assert(len == 0 || nme != NULL);
83 if (len == 0 || nme == NULL)
84 return NULL;
85 if (len > IDLENGTH) {
86 len = IDLENGTH;
87 }
88 NME_HASH(nme, key, len);
89 MT_lock_set(&mal_namespaceLock);
90 for (n = &hash[key]; *n; n = &(*n)->next) {
91#ifdef KEEP_SORTED
92 /* keep each list sorted on length, then name */
93 if (len < (*n)->length)
94 continue;
95 if (len == (*n)->length) {
96 int c;
97 if ((c = strncmp(nme, (*n)->nme, len)) < 0)
98 continue;
99 if (c == 0) {
100 MT_lock_unset(&mal_namespaceLock);
101 return (*n)->nme;
102 }
103 break;
104 }
105 break;
106#else
107 /* append entries to list */
108 if (len == (*n)->length && strncmp(nme, (*n)->nme, len) == 0) {
109 MT_lock_unset(&mal_namespaceLock);
110 return (*n)->nme;
111 }
112#endif
113 }
114 /* item not found */
115 if (!allocate) {
116 MT_lock_unset(&mal_namespaceLock);
117 return NULL;
118 }
119 if (namespace == NULL || namespace->count == 4096) {
120 struct namespace *ns = GDKmalloc(sizeof(struct namespace));
121 if (ns == NULL) {
122 /* error we cannot recover from */
123 fprintf(stderr, "!findName" SQLSTATE(HY001) MAL_MALLOC_FAIL);
124 mal_exit(1);
125 }
126 ns->next = namespace;
127 ns->count = 0;
128 namespace = ns;
129 }
130 m = &namespace->data[namespace->count++];
131 strncpy(m->nme, nme, len);
132 m->nme[len] = 0;
133 m->length = (unsigned short) len;
134 m->next = *n;
135 *n = m;
136 MT_lock_unset(&mal_namespaceLock);
137 return (*n)->nme;
138}
139
140str getName(const char *nme) {
141 return findName(nme, strlen(nme), 0);
142}
143
144str getNameLen(const char *nme, size_t len)
145{
146 return findName(nme, len, 0);
147}
148/*
149 * Name deletion from the namespace is tricky, because there may
150 * be multiple threads active on the structure. Moreover, the
151 * symbol may be picked up by a concurrent thread and stored
152 * somewhere.
153 * To avoid all these problems, the namespace should become
154 * private to each Client, but this would mean expensive look ups
155 * deep into the kernel to access the context.
156 */
157void delName(const char *nme, size_t len){
158 str n;
159 n= getNameLen(nme,len);
160 if( nme[0]==0 || n == 0) return ;
161 /*Namespace garbage collection not available yet */
162}
163
164str putName(const char *nme) {
165 return findName(nme, strlen(nme), 1);
166}
167
168str putNameLen(const char *nme, size_t len)
169{
170 return findName(nme, len, 1);
171}
172