ffi-nats-core 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/ffi-nats-core.gemspec +8 -0
- data/lib/ffi/nats/core/version.rb +1 -1
- data/vendor/cnats/CMakeLists.txt +137 -0
- data/vendor/cnats/adapters/libevent.h +220 -0
- data/vendor/cnats/adapters/libuv.h +472 -0
- data/vendor/cnats/examples/CMakeLists.txt +56 -0
- data/vendor/cnats/examples/asynctimeout.c +83 -0
- data/vendor/cnats/examples/examples.h +322 -0
- data/vendor/cnats/examples/libevent-pub.c +136 -0
- data/vendor/cnats/examples/libevent-sub.c +104 -0
- data/vendor/cnats/examples/libuv-pub.c +120 -0
- data/vendor/cnats/examples/libuv-sub.c +114 -0
- data/vendor/cnats/examples/publisher.c +62 -0
- data/vendor/cnats/examples/queuegroup.c +132 -0
- data/vendor/cnats/examples/replier.c +149 -0
- data/vendor/cnats/examples/requestor.c +75 -0
- data/vendor/cnats/examples/subscriber.c +133 -0
- data/vendor/cnats/src/CMakeLists.txt +31 -0
- data/vendor/cnats/src/asynccb.c +66 -0
- data/vendor/cnats/src/asynccb.h +42 -0
- data/vendor/cnats/src/buf.c +246 -0
- data/vendor/cnats/src/buf.h +116 -0
- data/vendor/cnats/src/comsock.c +474 -0
- data/vendor/cnats/src/comsock.h +81 -0
- data/vendor/cnats/src/conn.c +2725 -0
- data/vendor/cnats/src/conn.h +75 -0
- data/vendor/cnats/src/err.h +31 -0
- data/vendor/cnats/src/gc.h +27 -0
- data/vendor/cnats/src/hash.c +725 -0
- data/vendor/cnats/src/hash.h +141 -0
- data/vendor/cnats/src/include/n-unix.h +56 -0
- data/vendor/cnats/src/include/n-win.h +59 -0
- data/vendor/cnats/src/mem.h +20 -0
- data/vendor/cnats/src/msg.c +155 -0
- data/vendor/cnats/src/msg.h +43 -0
- data/vendor/cnats/src/nats.c +1734 -0
- data/vendor/cnats/src/nats.h +2024 -0
- data/vendor/cnats/src/natsp.h +518 -0
- data/vendor/cnats/src/natstime.c +79 -0
- data/vendor/cnats/src/natstime.h +27 -0
- data/vendor/cnats/src/nuid.c +265 -0
- data/vendor/cnats/src/nuid.h +21 -0
- data/vendor/cnats/src/opts.c +1030 -0
- data/vendor/cnats/src/opts.h +19 -0
- data/vendor/cnats/src/parser.c +869 -0
- data/vendor/cnats/src/parser.h +87 -0
- data/vendor/cnats/src/pub.c +293 -0
- data/vendor/cnats/src/srvpool.c +380 -0
- data/vendor/cnats/src/srvpool.h +71 -0
- data/vendor/cnats/src/stats.c +54 -0
- data/vendor/cnats/src/stats.h +21 -0
- data/vendor/cnats/src/status.c +60 -0
- data/vendor/cnats/src/status.h +95 -0
- data/vendor/cnats/src/sub.c +956 -0
- data/vendor/cnats/src/sub.h +34 -0
- data/vendor/cnats/src/timer.c +86 -0
- data/vendor/cnats/src/timer.h +57 -0
- data/vendor/cnats/src/unix/cond.c +103 -0
- data/vendor/cnats/src/unix/mutex.c +107 -0
- data/vendor/cnats/src/unix/sock.c +105 -0
- data/vendor/cnats/src/unix/thread.c +162 -0
- data/vendor/cnats/src/url.c +134 -0
- data/vendor/cnats/src/url.h +24 -0
- data/vendor/cnats/src/util.c +823 -0
- data/vendor/cnats/src/util.h +75 -0
- data/vendor/cnats/src/version.h +29 -0
- data/vendor/cnats/src/version.h.in +29 -0
- data/vendor/cnats/src/win/cond.c +86 -0
- data/vendor/cnats/src/win/mutex.c +54 -0
- data/vendor/cnats/src/win/sock.c +158 -0
- data/vendor/cnats/src/win/strings.c +108 -0
- data/vendor/cnats/src/win/thread.c +180 -0
- data/vendor/cnats/test/CMakeLists.txt +35 -0
- data/vendor/cnats/test/certs/ca.pem +38 -0
- data/vendor/cnats/test/certs/client-cert.pem +30 -0
- data/vendor/cnats/test/certs/client-key.pem +51 -0
- data/vendor/cnats/test/certs/server-cert.pem +31 -0
- data/vendor/cnats/test/certs/server-key.pem +51 -0
- data/vendor/cnats/test/dylib/CMakeLists.txt +10 -0
- data/vendor/cnats/test/dylib/nonats.c +13 -0
- data/vendor/cnats/test/list.txt +125 -0
- data/vendor/cnats/test/test.c +11655 -0
- data/vendor/cnats/test/tls.conf +15 -0
- data/vendor/cnats/test/tlsverify.conf +19 -0
- metadata +83 -1
@@ -0,0 +1,75 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#ifndef CONN_H_
|
4
|
+
#define CONN_H_
|
5
|
+
|
6
|
+
#include "natsp.h"
|
7
|
+
|
8
|
+
#ifdef DEV_MODE
|
9
|
+
// For type safety
|
10
|
+
|
11
|
+
void natsConn_Lock(natsConnection *nc);
|
12
|
+
void natsConn_Unlock(natsConnection *nc);
|
13
|
+
|
14
|
+
#else
|
15
|
+
// We know what we are doing :-)
|
16
|
+
|
17
|
+
#define natsConn_Lock(c) (natsMutex_Lock((c)->mu))
|
18
|
+
#define natsConn_Unlock(c) (natsMutex_Unlock((c)->mu))
|
19
|
+
|
20
|
+
#endif // DEV_MODE
|
21
|
+
|
22
|
+
natsStatus
|
23
|
+
natsConn_create(natsConnection **newConn, natsOptions *options);
|
24
|
+
|
25
|
+
void
|
26
|
+
natsConn_retain(natsConnection *nc);
|
27
|
+
|
28
|
+
void
|
29
|
+
natsConn_release(natsConnection *nc);
|
30
|
+
|
31
|
+
natsStatus
|
32
|
+
natsConn_bufferWrite(natsConnection *nc, const char *buffer, int len);
|
33
|
+
|
34
|
+
natsStatus
|
35
|
+
natsConn_bufferFlush(natsConnection *nc);
|
36
|
+
|
37
|
+
bool
|
38
|
+
natsConn_isClosed(natsConnection *nc);
|
39
|
+
|
40
|
+
bool
|
41
|
+
natsConn_isReconnecting(natsConnection *nc);
|
42
|
+
|
43
|
+
void
|
44
|
+
natsConn_kickFlusher(natsConnection *nc);
|
45
|
+
|
46
|
+
natsStatus
|
47
|
+
natsConn_processMsg(natsConnection *nc, char *buf, int bufLen);
|
48
|
+
|
49
|
+
void
|
50
|
+
natsConn_processOK(natsConnection *nc);
|
51
|
+
|
52
|
+
void
|
53
|
+
natsConn_processErr(natsConnection *nc, char *buf, int bufLen);
|
54
|
+
|
55
|
+
void
|
56
|
+
natsConn_processPing(natsConnection *nc);
|
57
|
+
|
58
|
+
void
|
59
|
+
natsConn_processPong(natsConnection *nc);
|
60
|
+
|
61
|
+
natsStatus
|
62
|
+
natsConn_subscribe(natsSubscription **newSub,
|
63
|
+
natsConnection *nc, const char *subj, const char *queue,
|
64
|
+
int64_t timeout, natsMsgHandler cb, void *cbClosure);
|
65
|
+
|
66
|
+
natsStatus
|
67
|
+
natsConn_unsubscribe(natsConnection *nc, natsSubscription *sub, int max);
|
68
|
+
|
69
|
+
void
|
70
|
+
natsConn_removeSubscription(natsConnection *nc, natsSubscription *sub, bool needsLock);
|
71
|
+
|
72
|
+
void
|
73
|
+
natsConn_processAsyncINFO(natsConnection *nc, char *buf, int len);
|
74
|
+
|
75
|
+
#endif /* CONN_H_ */
|
@@ -0,0 +1,31 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
|
4
|
+
#ifndef ERR_H_
|
5
|
+
#define ERR_H_
|
6
|
+
|
7
|
+
#include "status.h"
|
8
|
+
#include "nats.h"
|
9
|
+
#include "natsp.h"
|
10
|
+
|
11
|
+
#define NATS_SSL_ERR_REASON_STRING ERR_reason_error_string(ERR_get_error())
|
12
|
+
|
13
|
+
#define nats_setDefaultError(e) nats_setError((e), "%s", natsStatus_GetText(e))
|
14
|
+
|
15
|
+
#define nats_setError(e, f, ...) nats_setErrorReal(__FILE__, __NATS_FUNCTION__, __LINE__, (e), (f), __VA_ARGS__)
|
16
|
+
|
17
|
+
natsStatus
|
18
|
+
nats_setErrorReal(const char *fileName, const char *funcName, int line, natsStatus errSts, const void *errTxtFmt, ...);
|
19
|
+
|
20
|
+
#define NATS_UPDATE_ERR_STACK(s) (s == NATS_OK ? s : nats_updateErrStack(s, __NATS_FUNCTION__))
|
21
|
+
|
22
|
+
natsStatus
|
23
|
+
nats_updateErrStack(natsStatus err, const char *func);
|
24
|
+
|
25
|
+
void
|
26
|
+
nats_clearLastError(void);
|
27
|
+
|
28
|
+
void
|
29
|
+
nats_doNotUpdateErrStack(bool skipStackUpdate);
|
30
|
+
|
31
|
+
#endif /* ERR_H_ */
|
@@ -0,0 +1,27 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
|
4
|
+
#ifndef GC_H_
|
5
|
+
#define GC_H_
|
6
|
+
|
7
|
+
// This callback implements the specific code to free the given object.
|
8
|
+
// This is invoked by the garbage collector.
|
9
|
+
typedef void (*nats_FreeObjectCb)(void *object);
|
10
|
+
|
11
|
+
// This structure should be included as the first field of any object
|
12
|
+
// that needs to be garbage collected.
|
13
|
+
typedef struct __natsGCItem
|
14
|
+
{
|
15
|
+
struct __natsGCItem *next;
|
16
|
+
nats_FreeObjectCb freeCb;
|
17
|
+
|
18
|
+
} natsGCItem;
|
19
|
+
|
20
|
+
// Gives the object to the garbage collector.
|
21
|
+
// Returns 'true' if the GC takes ownership, 'false' otherwise (in this case,
|
22
|
+
// the caller is responsible for freeing the object).
|
23
|
+
bool
|
24
|
+
natsGC_collect(natsGCItem *item);
|
25
|
+
|
26
|
+
|
27
|
+
#endif /* GC_H_ */
|
@@ -0,0 +1,725 @@
|
|
1
|
+
// Copyright 2015 Apcera Inc. All rights reserved.
|
2
|
+
|
3
|
+
#include "natsp.h"
|
4
|
+
|
5
|
+
#include <string.h>
|
6
|
+
|
7
|
+
#include "status.h"
|
8
|
+
#include "mem.h"
|
9
|
+
#include "hash.h"
|
10
|
+
|
11
|
+
#define _freeEntry(e) { NATS_FREE(e); (e) = NULL; }
|
12
|
+
|
13
|
+
#define _OFF32 (2166136261)
|
14
|
+
#define _YP32 (709607)
|
15
|
+
|
16
|
+
#define _BSZ (8)
|
17
|
+
#define _WSZ (4)
|
18
|
+
|
19
|
+
static int _DWSZ = _WSZ << 1; // 8
|
20
|
+
static int _DDWSZ = _WSZ << 2; // 16
|
21
|
+
|
22
|
+
static int _MAX_BKT_SIZE = (1 << 30) - 1;
|
23
|
+
|
24
|
+
natsStatus
|
25
|
+
natsHash_Create(natsHash **newHash, int initialSize)
|
26
|
+
{
|
27
|
+
natsHash *hash = NULL;
|
28
|
+
|
29
|
+
if (initialSize <= 0)
|
30
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
31
|
+
|
32
|
+
if ((initialSize & (initialSize - 1)) != 0)
|
33
|
+
{
|
34
|
+
// Size of buckets must be power of 2
|
35
|
+
initialSize--;
|
36
|
+
initialSize |= initialSize >> 1;
|
37
|
+
initialSize |= initialSize >> 2;
|
38
|
+
initialSize |= initialSize >> 4;
|
39
|
+
initialSize |= initialSize >> 8;
|
40
|
+
initialSize |= initialSize >> 16;
|
41
|
+
initialSize++;
|
42
|
+
}
|
43
|
+
|
44
|
+
hash = (natsHash*) NATS_CALLOC(1, sizeof(natsHash));
|
45
|
+
if (hash == NULL)
|
46
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
47
|
+
|
48
|
+
hash->mask = (initialSize - 1);
|
49
|
+
hash->numBkts = initialSize;
|
50
|
+
hash->canResize = true;
|
51
|
+
hash->bkts = (natsHashEntry**) NATS_CALLOC(initialSize, sizeof(natsHashEntry*));
|
52
|
+
if (hash->bkts == NULL)
|
53
|
+
{
|
54
|
+
NATS_FREE(hash);
|
55
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
56
|
+
}
|
57
|
+
|
58
|
+
*newHash = hash;
|
59
|
+
|
60
|
+
return NATS_OK;
|
61
|
+
}
|
62
|
+
|
63
|
+
static natsStatus
|
64
|
+
_resize(natsHash *hash, int newSize)
|
65
|
+
{
|
66
|
+
natsHashEntry **bkts = NULL;
|
67
|
+
int newMask = newSize - 1;
|
68
|
+
natsHashEntry *ne;
|
69
|
+
natsHashEntry *e;
|
70
|
+
int k;
|
71
|
+
int newIndex;
|
72
|
+
|
73
|
+
bkts = (natsHashEntry**) NATS_CALLOC(newSize, sizeof(natsHashEntry*));
|
74
|
+
if (bkts == NULL)
|
75
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
76
|
+
|
77
|
+
for (k = 0; k < hash->numBkts; k++)
|
78
|
+
{
|
79
|
+
e = hash->bkts[k];
|
80
|
+
while (e != NULL)
|
81
|
+
{
|
82
|
+
ne = e;
|
83
|
+
e = e->next;
|
84
|
+
|
85
|
+
newIndex = ne->key & newMask;
|
86
|
+
ne->next = bkts[newIndex];
|
87
|
+
bkts[newIndex] = ne;
|
88
|
+
}
|
89
|
+
}
|
90
|
+
|
91
|
+
NATS_FREE(hash->bkts);
|
92
|
+
hash->bkts = bkts;
|
93
|
+
hash->mask = newMask;
|
94
|
+
hash->numBkts = newSize;
|
95
|
+
|
96
|
+
return NATS_OK;
|
97
|
+
}
|
98
|
+
|
99
|
+
static natsStatus
|
100
|
+
_grow(natsHash *hash)
|
101
|
+
{
|
102
|
+
// Can't grow beyond max signed int for now
|
103
|
+
if (hash->numBkts >= _MAX_BKT_SIZE)
|
104
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
105
|
+
|
106
|
+
return _resize(hash, 2 * (hash->numBkts));
|
107
|
+
}
|
108
|
+
|
109
|
+
static void
|
110
|
+
_shrink(natsHash *hash)
|
111
|
+
{
|
112
|
+
if (hash->numBkts <= _BSZ)
|
113
|
+
return;
|
114
|
+
|
115
|
+
// Ignore memory issue when resizing, since if we fail to allocate
|
116
|
+
// the original hash is still intact.
|
117
|
+
(void) _resize(hash, hash->numBkts / 2);
|
118
|
+
}
|
119
|
+
|
120
|
+
static natsHashEntry*
|
121
|
+
_createEntry(int64_t key, void *data)
|
122
|
+
{
|
123
|
+
natsHashEntry *e = (natsHashEntry*) NATS_MALLOC(sizeof(natsHashEntry));
|
124
|
+
|
125
|
+
if (e == NULL)
|
126
|
+
return NULL;
|
127
|
+
|
128
|
+
e->key = key;
|
129
|
+
e->data = data;
|
130
|
+
e->next = NULL;
|
131
|
+
|
132
|
+
return e;
|
133
|
+
}
|
134
|
+
|
135
|
+
natsStatus
|
136
|
+
natsHash_Set(natsHash *hash, int64_t key, void *data, void **oldData)
|
137
|
+
{
|
138
|
+
natsStatus s = NATS_OK;
|
139
|
+
int index = (int) (key & hash->mask);
|
140
|
+
natsHashEntry *newEntry = NULL;
|
141
|
+
natsHashEntry *e;
|
142
|
+
|
143
|
+
if (oldData != NULL)
|
144
|
+
*oldData = NULL;
|
145
|
+
|
146
|
+
e = (natsHashEntry*) hash->bkts[index];
|
147
|
+
while (e != NULL)
|
148
|
+
{
|
149
|
+
if (e->key == key)
|
150
|
+
{
|
151
|
+
// Success, replace data field
|
152
|
+
if (oldData != NULL)
|
153
|
+
*oldData = e->data;
|
154
|
+
e->data = data;
|
155
|
+
return NATS_OK;
|
156
|
+
}
|
157
|
+
|
158
|
+
e = e->next;
|
159
|
+
}
|
160
|
+
|
161
|
+
// We have a new entry here
|
162
|
+
newEntry = _createEntry(key, data);
|
163
|
+
if (newEntry == NULL)
|
164
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
165
|
+
|
166
|
+
newEntry->next = hash->bkts[index];
|
167
|
+
hash->bkts[index] = newEntry;
|
168
|
+
hash->used++;
|
169
|
+
|
170
|
+
// Check for resizing
|
171
|
+
if (hash->canResize && (hash->used > hash->numBkts))
|
172
|
+
s = _grow(hash);
|
173
|
+
|
174
|
+
return NATS_UPDATE_ERR_STACK(s);
|
175
|
+
}
|
176
|
+
|
177
|
+
void*
|
178
|
+
natsHash_Get(natsHash *hash, int64_t key)
|
179
|
+
{
|
180
|
+
natsHashEntry *e;
|
181
|
+
|
182
|
+
e = hash->bkts[key & hash->mask];
|
183
|
+
while (e != NULL)
|
184
|
+
{
|
185
|
+
if (e->key == key)
|
186
|
+
return e->data;
|
187
|
+
|
188
|
+
e = e->next;
|
189
|
+
}
|
190
|
+
|
191
|
+
return NULL;
|
192
|
+
}
|
193
|
+
|
194
|
+
void*
|
195
|
+
natsHash_Remove(natsHash *hash, int64_t key)
|
196
|
+
{
|
197
|
+
natsHashEntry *entryRemoved = NULL;
|
198
|
+
void *dataRemoved = NULL;
|
199
|
+
natsHashEntry **e;
|
200
|
+
|
201
|
+
e = (natsHashEntry**) &(hash->bkts[key & hash->mask]);
|
202
|
+
while (*e != NULL)
|
203
|
+
{
|
204
|
+
if ((*e)->key == key)
|
205
|
+
{
|
206
|
+
// Success
|
207
|
+
entryRemoved = *e;
|
208
|
+
dataRemoved = entryRemoved->data;
|
209
|
+
|
210
|
+
*e = entryRemoved->next;
|
211
|
+
_freeEntry(entryRemoved);
|
212
|
+
|
213
|
+
hash->used--;
|
214
|
+
|
215
|
+
// Check for resizing
|
216
|
+
if (hash->canResize
|
217
|
+
&& (hash->numBkts > _BSZ)
|
218
|
+
&& (hash->used < hash->numBkts / 4))
|
219
|
+
{
|
220
|
+
_shrink(hash);
|
221
|
+
}
|
222
|
+
|
223
|
+
break;
|
224
|
+
}
|
225
|
+
|
226
|
+
e = (natsHashEntry**) &((*e)->next);
|
227
|
+
}
|
228
|
+
|
229
|
+
return dataRemoved;
|
230
|
+
}
|
231
|
+
|
232
|
+
void
|
233
|
+
natsHash_Destroy(natsHash *hash)
|
234
|
+
{
|
235
|
+
natsHashEntry *e, *ne;
|
236
|
+
int i;
|
237
|
+
|
238
|
+
if (hash == NULL)
|
239
|
+
return;
|
240
|
+
|
241
|
+
for (i = 0; i < hash->numBkts; i++)
|
242
|
+
{
|
243
|
+
e = hash->bkts[i];
|
244
|
+
while (e != NULL)
|
245
|
+
{
|
246
|
+
ne = e->next;
|
247
|
+
|
248
|
+
_freeEntry(e);
|
249
|
+
|
250
|
+
e = ne;
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
NATS_FREE(hash->bkts);
|
255
|
+
NATS_FREE(hash);
|
256
|
+
}
|
257
|
+
|
258
|
+
void
|
259
|
+
natsHashIter_Init(natsHashIter *iter, natsHash *hash)
|
260
|
+
{
|
261
|
+
memset(iter, 0, sizeof(natsHashIter));
|
262
|
+
|
263
|
+
hash->canResize = false;
|
264
|
+
iter->hash = hash;
|
265
|
+
iter->current = hash->bkts[0];
|
266
|
+
iter->next = iter->current;
|
267
|
+
}
|
268
|
+
|
269
|
+
bool
|
270
|
+
natsHashIter_Next(natsHashIter *iter, int64_t *key, void **value)
|
271
|
+
{
|
272
|
+
if ((iter->started) && (iter->next == NULL))
|
273
|
+
return false;
|
274
|
+
|
275
|
+
if (!(iter->started) && (iter->current == NULL))
|
276
|
+
{
|
277
|
+
while ((iter->next == NULL)
|
278
|
+
&& (iter->currBkt < (iter->hash->numBkts - 1)))
|
279
|
+
{
|
280
|
+
iter->next = iter->hash->bkts[++(iter->currBkt)];
|
281
|
+
}
|
282
|
+
|
283
|
+
if (iter->next == NULL)
|
284
|
+
{
|
285
|
+
iter->started = true;
|
286
|
+
return false;
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
iter->started = true;
|
291
|
+
|
292
|
+
iter->current = iter->next;
|
293
|
+
if (iter->current != NULL)
|
294
|
+
{
|
295
|
+
if (key != NULL)
|
296
|
+
*key = iter->current->key;
|
297
|
+
if (value != NULL)
|
298
|
+
*value = iter->current->data;
|
299
|
+
|
300
|
+
iter->next = iter->current->next;
|
301
|
+
}
|
302
|
+
|
303
|
+
while ((iter->next == NULL)
|
304
|
+
&& (iter->currBkt < (iter->hash->numBkts - 1)))
|
305
|
+
{
|
306
|
+
iter->next = iter->hash->bkts[++(iter->currBkt)];
|
307
|
+
}
|
308
|
+
|
309
|
+
return true;
|
310
|
+
}
|
311
|
+
|
312
|
+
natsStatus
|
313
|
+
natsHashIter_RemoveCurrent(natsHashIter *iter)
|
314
|
+
{
|
315
|
+
int64_t key;
|
316
|
+
|
317
|
+
if (iter->current == NULL)
|
318
|
+
return nats_setDefaultError(NATS_NOT_FOUND);
|
319
|
+
|
320
|
+
key = iter->current->key;
|
321
|
+
iter->current = iter->next;
|
322
|
+
|
323
|
+
(void) natsHash_Remove(iter->hash, key);
|
324
|
+
|
325
|
+
return NATS_OK;
|
326
|
+
}
|
327
|
+
|
328
|
+
void
|
329
|
+
natsHashIter_Done(natsHashIter *iter)
|
330
|
+
{
|
331
|
+
iter->hash->canResize = true;
|
332
|
+
}
|
333
|
+
|
334
|
+
|
335
|
+
// Jesteress derivative of FNV1A from [http://www.sanmayce.com/Fastest_Hash/]
|
336
|
+
uint32_t
|
337
|
+
natsStrHash_Hash(const char *data, int dataLen)
|
338
|
+
{
|
339
|
+
int i = 0;
|
340
|
+
int dlen = dataLen;
|
341
|
+
uint32_t h32 = (uint32_t)_OFF32;
|
342
|
+
uint64_t k1, k2;
|
343
|
+
|
344
|
+
for (; dlen >= _DDWSZ; dlen -= _DDWSZ)
|
345
|
+
{
|
346
|
+
k1 = *(uint64_t*) &(data[i]);
|
347
|
+
k2 = *(uint64_t*) &(data[i + 4]);
|
348
|
+
h32 = (uint32_t) ((((uint64_t) h32) ^ ((k1<<5 | k1>>27) ^ k2)) * _YP32);
|
349
|
+
i += _DDWSZ;
|
350
|
+
}
|
351
|
+
|
352
|
+
// Cases: 0,1,2,3,4,5,6,7
|
353
|
+
if ((dlen & _DWSZ) > 0)
|
354
|
+
{
|
355
|
+
k1 = *(uint64_t*) &(data[i]);
|
356
|
+
h32 = (uint32_t) ((((uint64_t) h32) ^ k1) * _YP32);
|
357
|
+
i += _DWSZ;
|
358
|
+
}
|
359
|
+
if ((dlen & _WSZ) > 0)
|
360
|
+
{
|
361
|
+
k1 = *(uint32_t*) &(data[i]);
|
362
|
+
h32 = (uint32_t) ((((uint64_t) h32) ^ k1) * _YP32);
|
363
|
+
i += _WSZ;
|
364
|
+
}
|
365
|
+
if ((dlen & 1) > 0)
|
366
|
+
{
|
367
|
+
h32 = (h32 ^ (uint32_t)(data[i])) * _YP32;
|
368
|
+
}
|
369
|
+
|
370
|
+
return h32 ^ (h32 >> 16);
|
371
|
+
}
|
372
|
+
|
373
|
+
natsStatus
|
374
|
+
natsStrHash_Create(natsStrHash **newHash, int initialSize)
|
375
|
+
{
|
376
|
+
natsStrHash *hash = NULL;
|
377
|
+
|
378
|
+
if (initialSize <= 0)
|
379
|
+
return nats_setDefaultError(NATS_INVALID_ARG);
|
380
|
+
|
381
|
+
if ((initialSize & (initialSize - 1)) != 0)
|
382
|
+
{
|
383
|
+
// Size of buckets must be power of 2
|
384
|
+
initialSize--;
|
385
|
+
initialSize |= initialSize >> 1;
|
386
|
+
initialSize |= initialSize >> 2;
|
387
|
+
initialSize |= initialSize >> 4;
|
388
|
+
initialSize |= initialSize >> 8;
|
389
|
+
initialSize |= initialSize >> 16;
|
390
|
+
initialSize++;
|
391
|
+
}
|
392
|
+
|
393
|
+
hash = (natsStrHash*) NATS_CALLOC(1, sizeof(natsStrHash));
|
394
|
+
if (hash == NULL)
|
395
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
396
|
+
|
397
|
+
hash->mask = (initialSize - 1);
|
398
|
+
hash->numBkts = initialSize;
|
399
|
+
hash->canResize = true;
|
400
|
+
hash->bkts = (natsStrHashEntry**) NATS_CALLOC(initialSize, sizeof(natsStrHashEntry*));
|
401
|
+
if (hash->bkts == NULL)
|
402
|
+
{
|
403
|
+
NATS_FREE(hash);
|
404
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
405
|
+
}
|
406
|
+
|
407
|
+
*newHash = hash;
|
408
|
+
|
409
|
+
return NATS_OK;
|
410
|
+
}
|
411
|
+
|
412
|
+
static natsStatus
|
413
|
+
_resizeStr(natsStrHash *hash, int newSize)
|
414
|
+
{
|
415
|
+
natsStrHashEntry **bkts = NULL;
|
416
|
+
int newMask = newSize - 1;
|
417
|
+
natsStrHashEntry *ne;
|
418
|
+
natsStrHashEntry *e;
|
419
|
+
int k;
|
420
|
+
int newIndex;
|
421
|
+
|
422
|
+
bkts = (natsStrHashEntry**) NATS_CALLOC(newSize, sizeof(natsStrHashEntry*));
|
423
|
+
if (bkts == NULL)
|
424
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
425
|
+
|
426
|
+
for (k = 0; k < hash->numBkts; k++)
|
427
|
+
{
|
428
|
+
e = hash->bkts[k];
|
429
|
+
while (e != NULL)
|
430
|
+
{
|
431
|
+
ne = e;
|
432
|
+
e = e->next;
|
433
|
+
|
434
|
+
newIndex = ne->hk & newMask;
|
435
|
+
ne->next = bkts[newIndex];
|
436
|
+
bkts[newIndex] = ne;
|
437
|
+
}
|
438
|
+
}
|
439
|
+
|
440
|
+
NATS_FREE(hash->bkts);
|
441
|
+
hash->bkts = bkts;
|
442
|
+
hash->mask = newMask;
|
443
|
+
hash->numBkts = newSize;
|
444
|
+
|
445
|
+
return NATS_OK;
|
446
|
+
}
|
447
|
+
|
448
|
+
static natsStatus
|
449
|
+
_growStr(natsStrHash *hash)
|
450
|
+
{
|
451
|
+
// Can't grow beyond max signed int for now
|
452
|
+
if (hash->numBkts >= _MAX_BKT_SIZE)
|
453
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
454
|
+
|
455
|
+
return _resizeStr(hash, 2 * (hash->numBkts));
|
456
|
+
}
|
457
|
+
|
458
|
+
static void
|
459
|
+
_shrinkStr(natsStrHash *hash)
|
460
|
+
{
|
461
|
+
if (hash->numBkts <= _BSZ)
|
462
|
+
return;
|
463
|
+
|
464
|
+
// Ignore memory issue when resizing, since if we fail to allocate
|
465
|
+
// the original hash is still intact.
|
466
|
+
(void) _resizeStr(hash, hash->numBkts / 2);
|
467
|
+
}
|
468
|
+
|
469
|
+
|
470
|
+
static natsStrHashEntry*
|
471
|
+
_createStrEntry(uint32_t hk, char *key, bool copyKey, void *data)
|
472
|
+
{
|
473
|
+
natsStrHashEntry *e = (natsStrHashEntry*) NATS_MALLOC(sizeof(natsStrHashEntry));
|
474
|
+
|
475
|
+
if (e == NULL)
|
476
|
+
return NULL;
|
477
|
+
|
478
|
+
e->hk = hk;
|
479
|
+
e->key = (copyKey ? NATS_STRDUP(key) : key);
|
480
|
+
e->freeKey = copyKey;
|
481
|
+
e->data = data;
|
482
|
+
e->next = NULL;
|
483
|
+
|
484
|
+
if (e->key == NULL)
|
485
|
+
{
|
486
|
+
NATS_FREE(e);
|
487
|
+
return NULL;
|
488
|
+
}
|
489
|
+
|
490
|
+
return e;
|
491
|
+
}
|
492
|
+
|
493
|
+
natsStatus
|
494
|
+
natsStrHash_Set(natsStrHash *hash, char *key, bool copyKey,
|
495
|
+
void *data, void **oldData)
|
496
|
+
{
|
497
|
+
natsStatus s = NATS_OK;
|
498
|
+
uint32_t hk = 0;
|
499
|
+
int index = 0;
|
500
|
+
natsStrHashEntry *newEntry = NULL;
|
501
|
+
natsStrHashEntry *e;
|
502
|
+
char *oldKey;
|
503
|
+
|
504
|
+
if (oldData != NULL)
|
505
|
+
*oldData = NULL;
|
506
|
+
|
507
|
+
hk = natsStrHash_Hash(key, (int) strlen(key));
|
508
|
+
index = hk & hash->mask;
|
509
|
+
|
510
|
+
e = (natsStrHashEntry*) hash->bkts[index];
|
511
|
+
while (e != NULL)
|
512
|
+
{
|
513
|
+
if ((e->hk == hk)
|
514
|
+
&& (strcmp(e->key, key) == 0))
|
515
|
+
{
|
516
|
+
// Success, replace data field
|
517
|
+
if (oldData != NULL)
|
518
|
+
*oldData = e->data;
|
519
|
+
e->data = data;
|
520
|
+
|
521
|
+
if (copyKey)
|
522
|
+
{
|
523
|
+
oldKey = e->key;
|
524
|
+
e->key = NATS_STRDUP(key);
|
525
|
+
|
526
|
+
if (e->freeKey)
|
527
|
+
NATS_FREE(oldKey);
|
528
|
+
|
529
|
+
e->freeKey = true;
|
530
|
+
}
|
531
|
+
return NATS_OK;
|
532
|
+
}
|
533
|
+
|
534
|
+
e = e->next;
|
535
|
+
}
|
536
|
+
|
537
|
+
// We have a new entry here
|
538
|
+
newEntry = _createStrEntry(hk, key, copyKey, data);
|
539
|
+
if (newEntry == NULL)
|
540
|
+
return nats_setDefaultError(NATS_NO_MEMORY);
|
541
|
+
|
542
|
+
newEntry->next = hash->bkts[index];
|
543
|
+
hash->bkts[index] = newEntry;
|
544
|
+
hash->used++;
|
545
|
+
|
546
|
+
// Check for resizing
|
547
|
+
if (hash->canResize && (hash->used > hash->numBkts))
|
548
|
+
s = _growStr(hash);
|
549
|
+
|
550
|
+
return NATS_UPDATE_ERR_STACK(s);
|
551
|
+
}
|
552
|
+
|
553
|
+
void*
|
554
|
+
natsStrHash_Get(natsStrHash *hash, char *key)
|
555
|
+
{
|
556
|
+
natsStrHashEntry *e;
|
557
|
+
uint32_t hk = natsStrHash_Hash(key, (int) strlen(key));
|
558
|
+
|
559
|
+
e = hash->bkts[hk & hash->mask];
|
560
|
+
while (e != NULL)
|
561
|
+
{
|
562
|
+
if ((e->hk == hk)
|
563
|
+
&& (strcmp(e->key, key) == 0))
|
564
|
+
{
|
565
|
+
return e->data;
|
566
|
+
}
|
567
|
+
|
568
|
+
e = e->next;
|
569
|
+
}
|
570
|
+
|
571
|
+
return NULL;
|
572
|
+
}
|
573
|
+
|
574
|
+
static void
|
575
|
+
_freeStrEntry(natsStrHashEntry *e)
|
576
|
+
{
|
577
|
+
if (e->freeKey)
|
578
|
+
NATS_FREE(e->key);
|
579
|
+
|
580
|
+
NATS_FREE(e);
|
581
|
+
}
|
582
|
+
|
583
|
+
void*
|
584
|
+
natsStrHash_Remove(natsStrHash *hash, char *key)
|
585
|
+
{
|
586
|
+
natsStrHashEntry *entryRemoved = NULL;
|
587
|
+
void *dataRemoved = NULL;
|
588
|
+
natsStrHashEntry **e;
|
589
|
+
uint32_t hk;
|
590
|
+
|
591
|
+
hk = natsStrHash_Hash(key, (int) strlen(key));
|
592
|
+
|
593
|
+
e = (natsStrHashEntry**) &(hash->bkts[hk & hash->mask]);
|
594
|
+
while (*e != NULL)
|
595
|
+
{
|
596
|
+
if (((*e)->hk == hk)
|
597
|
+
&& (strcmp((*e)->key, key) == 0))
|
598
|
+
{
|
599
|
+
// Success
|
600
|
+
entryRemoved = *e;
|
601
|
+
dataRemoved = entryRemoved->data;
|
602
|
+
|
603
|
+
*e = entryRemoved->next;
|
604
|
+
_freeStrEntry(entryRemoved);
|
605
|
+
|
606
|
+
hash->used--;
|
607
|
+
|
608
|
+
// Check for resizing
|
609
|
+
if (hash->canResize
|
610
|
+
&& (hash->numBkts > _BSZ)
|
611
|
+
&& (hash->used < hash->numBkts / 4))
|
612
|
+
{
|
613
|
+
_shrinkStr(hash);
|
614
|
+
}
|
615
|
+
|
616
|
+
break;
|
617
|
+
}
|
618
|
+
|
619
|
+
e = (natsStrHashEntry**) &((*e)->next);
|
620
|
+
}
|
621
|
+
|
622
|
+
return dataRemoved;
|
623
|
+
}
|
624
|
+
|
625
|
+
void
|
626
|
+
natsStrHash_Destroy(natsStrHash *hash)
|
627
|
+
{
|
628
|
+
natsStrHashEntry *e, *ne;
|
629
|
+
int i;
|
630
|
+
|
631
|
+
if (hash == NULL)
|
632
|
+
return;
|
633
|
+
|
634
|
+
for (i = 0; i < hash->numBkts; i++)
|
635
|
+
{
|
636
|
+
e = hash->bkts[i];
|
637
|
+
while (e != NULL)
|
638
|
+
{
|
639
|
+
ne = e->next;
|
640
|
+
|
641
|
+
_freeStrEntry(e);
|
642
|
+
|
643
|
+
e = ne;
|
644
|
+
}
|
645
|
+
}
|
646
|
+
|
647
|
+
NATS_FREE(hash->bkts);
|
648
|
+
NATS_FREE(hash);
|
649
|
+
}
|
650
|
+
|
651
|
+
void
|
652
|
+
natsStrHashIter_Init(natsStrHashIter *iter, natsStrHash *hash)
|
653
|
+
{
|
654
|
+
memset(iter, 0, sizeof(natsStrHashIter));
|
655
|
+
|
656
|
+
hash->canResize = false;
|
657
|
+
iter->hash = hash;
|
658
|
+
iter->current = hash->bkts[0];
|
659
|
+
iter->next = iter->current;
|
660
|
+
}
|
661
|
+
|
662
|
+
bool
|
663
|
+
natsStrHashIter_Next(natsStrHashIter *iter, char **key, void **value)
|
664
|
+
{
|
665
|
+
if ((iter->started) && (iter->next == NULL))
|
666
|
+
return false;
|
667
|
+
|
668
|
+
if (!(iter->started) && (iter->current == NULL))
|
669
|
+
{
|
670
|
+
while ((iter->next == NULL)
|
671
|
+
&& (iter->currBkt < (iter->hash->numBkts - 1)))
|
672
|
+
{
|
673
|
+
iter->next = iter->hash->bkts[++(iter->currBkt)];
|
674
|
+
}
|
675
|
+
|
676
|
+
if (iter->next == NULL)
|
677
|
+
{
|
678
|
+
iter->started = true;
|
679
|
+
return false;
|
680
|
+
}
|
681
|
+
}
|
682
|
+
|
683
|
+
iter->started = true;
|
684
|
+
|
685
|
+
iter->current = iter->next;
|
686
|
+
if (iter->current != NULL)
|
687
|
+
{
|
688
|
+
if (key != NULL)
|
689
|
+
*key = iter->current->key;
|
690
|
+
if (value != NULL)
|
691
|
+
*value = iter->current->data;
|
692
|
+
|
693
|
+
iter->next = iter->current->next;
|
694
|
+
}
|
695
|
+
|
696
|
+
while ((iter->next == NULL)
|
697
|
+
&& (iter->currBkt < (iter->hash->numBkts - 1)))
|
698
|
+
{
|
699
|
+
iter->next = iter->hash->bkts[++(iter->currBkt)];
|
700
|
+
}
|
701
|
+
|
702
|
+
return true;
|
703
|
+
}
|
704
|
+
|
705
|
+
natsStatus
|
706
|
+
natsStrHashIter_RemoveCurrent(natsStrHashIter *iter)
|
707
|
+
{
|
708
|
+
char *key;
|
709
|
+
|
710
|
+
if (iter->current == NULL)
|
711
|
+
return nats_setDefaultError(NATS_NOT_FOUND);
|
712
|
+
|
713
|
+
key = iter->current->key;
|
714
|
+
iter->current = iter->next;
|
715
|
+
|
716
|
+
(void) natsStrHash_Remove(iter->hash, key);
|
717
|
+
|
718
|
+
return NATS_OK;
|
719
|
+
}
|
720
|
+
|
721
|
+
void
|
722
|
+
natsStrHashIter_Done(natsStrHashIter *iter)
|
723
|
+
{
|
724
|
+
natsHashIter_Done((natsHashIter*) iter);
|
725
|
+
}
|