hirlite 0.0.2.2 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (73) hide show
  1. checksums.yaml +13 -5
  2. data/ext/hirlite_ext/hirlite_ext.h +1 -1
  3. data/ext/hirlite_ext/rlite.c +3 -23
  4. data/lib/hirlite/connection.rb +4 -0
  5. data/lib/hirlite/version.rb +1 -1
  6. data/vendor/rlite/deps/lua/src/lua_cjson.c +1 -1
  7. data/vendor/rlite/src/Makefile +12 -25
  8. data/vendor/rlite/src/dump.c +3 -3
  9. data/vendor/rlite/src/flock_posix.c +79 -0
  10. data/vendor/rlite/src/flock_win.c +6 -0
  11. data/vendor/rlite/src/hirlite.c +265 -25
  12. data/vendor/rlite/src/hyperloglog.c +1 -1
  13. data/vendor/rlite/src/lzf_c.c +1 -1
  14. data/vendor/rlite/src/lzf_d.c +1 -1
  15. data/vendor/rlite/src/page_btree.c +3 -3
  16. data/vendor/rlite/src/page_key.c +12 -13
  17. data/vendor/rlite/src/page_list.c +4 -4
  18. data/vendor/rlite/src/page_long.c +2 -2
  19. data/vendor/rlite/src/page_multi_string.c +5 -5
  20. data/vendor/rlite/src/page_skiplist.c +3 -3
  21. data/vendor/rlite/src/page_string.c +2 -2
  22. data/vendor/rlite/src/pubsub.c +448 -0
  23. data/vendor/rlite/src/restore.c +5 -5
  24. data/vendor/rlite/src/rlite.c +141 -146
  25. data/vendor/rlite/src/rlite.h +40 -12
  26. data/vendor/rlite/src/{constants.h → rlite/constants.h} +0 -0
  27. data/vendor/rlite/src/{crc64.h → rlite/crc64.h} +0 -0
  28. data/vendor/rlite/src/{dump.h → rlite/dump.h} +0 -0
  29. data/vendor/rlite/src/{endianconv.h → rlite/endianconv.h} +0 -0
  30. data/vendor/rlite/src/rlite/flock.h +8 -0
  31. data/vendor/rlite/src/{hirlite.h → rlite/hirlite.h} +1 -0
  32. data/vendor/rlite/src/{hyperloglog.h → rlite/hyperloglog.h} +0 -0
  33. data/vendor/rlite/src/{lzf.h → rlite/lzf.h} +0 -0
  34. data/vendor/rlite/src/{lzfP.h → rlite/lzfP.h} +0 -0
  35. data/vendor/rlite/src/{page_btree.h → rlite/page_btree.h} +0 -0
  36. data/vendor/rlite/src/{page_key.h → rlite/page_key.h} +0 -0
  37. data/vendor/rlite/src/{page_list.h → rlite/page_list.h} +0 -0
  38. data/vendor/rlite/src/{page_long.h → rlite/page_long.h} +0 -0
  39. data/vendor/rlite/src/{page_multi_string.h → rlite/page_multi_string.h} +0 -0
  40. data/vendor/rlite/src/{page_skiplist.h → rlite/page_skiplist.h} +0 -0
  41. data/vendor/rlite/src/{page_string.h → rlite/page_string.h} +0 -0
  42. data/vendor/rlite/src/{pqsort.h → rlite/pqsort.h} +0 -0
  43. data/vendor/rlite/src/rlite/pubsub.h +25 -0
  44. data/vendor/rlite/src/{rand.h → rlite/rand.h} +0 -0
  45. data/vendor/rlite/src/{restore.h → rlite/restore.h} +0 -0
  46. data/vendor/rlite/src/{scripting.h → rlite/scripting.h} +0 -0
  47. data/vendor/rlite/src/{sha1.h → rlite/sha1.h} +0 -0
  48. data/vendor/rlite/src/rlite/signal.h +11 -0
  49. data/vendor/rlite/src/{solarisfixes.h → rlite/solarisfixes.h} +0 -0
  50. data/vendor/rlite/src/{sort.h → rlite/sort.h} +0 -0
  51. data/vendor/rlite/src/{status.h → rlite/status.h} +1 -0
  52. data/vendor/rlite/src/{type_hash.h → rlite/type_hash.h} +0 -0
  53. data/vendor/rlite/src/{type_list.h → rlite/type_list.h} +0 -0
  54. data/vendor/rlite/src/{type_set.h → rlite/type_set.h} +0 -0
  55. data/vendor/rlite/src/{type_string.h → rlite/type_string.h} +0 -0
  56. data/vendor/rlite/src/{type_zset.h → rlite/type_zset.h} +0 -0
  57. data/vendor/rlite/src/{util.h → rlite/util.h} +2 -1
  58. data/vendor/rlite/src/{utilfromredis.h → rlite/utilfromredis.h} +0 -0
  59. data/vendor/rlite/src/rlite/wal.h +8 -0
  60. data/vendor/rlite/src/scripting.c +8 -10
  61. data/vendor/rlite/src/sha1.c +2 -2
  62. data/vendor/rlite/src/signal_posix.c +118 -0
  63. data/vendor/rlite/src/signal_win.c +17 -0
  64. data/vendor/rlite/src/sort.c +2 -2
  65. data/vendor/rlite/src/type_hash.c +4 -4
  66. data/vendor/rlite/src/type_list.c +4 -4
  67. data/vendor/rlite/src/type_set.c +4 -4
  68. data/vendor/rlite/src/type_string.c +4 -4
  69. data/vendor/rlite/src/type_zset.c +7 -7
  70. data/vendor/rlite/src/util.c +28 -5
  71. data/vendor/rlite/src/utilfromredis.c +1 -1
  72. data/vendor/rlite/src/wal.c +309 -0
  73. metadata +59 -35
@@ -29,7 +29,7 @@
29
29
  * POSSIBILITY OF SUCH DAMAGE.
30
30
  */
31
31
 
32
- #include "hyperloglog.h"
32
+ #include "rlite/hyperloglog.h"
33
33
  #include <stdlib.h>
34
34
  #include <stdio.h>
35
35
  #include <string.h>
@@ -34,7 +34,7 @@
34
34
  * either the BSD or the GPL.
35
35
  */
36
36
 
37
- #include "lzfP.h"
37
+ #include "rlite/lzfP.h"
38
38
 
39
39
  #define HSIZE (1 << (HLOG))
40
40
 
@@ -34,7 +34,7 @@
34
34
  * either the BSD or the GPL.
35
35
  */
36
36
 
37
- #include "lzfP.h"
37
+ #include "rlite/lzfP.h"
38
38
 
39
39
  #if AVOID_ERRNO
40
40
  # define SET_ERRNO(n)
@@ -2,10 +2,10 @@
2
2
  #include <string.h>
3
3
  #include <stdio.h>
4
4
  #include <math.h>
5
- #include "status.h"
6
- #include "page_btree.h"
5
+ #include "rlite/status.h"
6
+ #include "rlite/page_btree.h"
7
7
  #include "rlite.h"
8
- #include "util.h"
8
+ #include "rlite/util.h"
9
9
 
10
10
  rl_btree_type rl_btree_type_hash_sha1_key = {
11
11
  0,
@@ -1,13 +1,13 @@
1
1
  #include <stdlib.h>
2
2
  #include <string.h>
3
3
  #include "rlite.h"
4
- #include "util.h"
5
- #include "page_btree.h"
6
- #include "page_key.h"
7
- #include "page_multi_string.h"
8
- #include "type_string.h"
9
- #include "type_zset.h"
10
- #include "type_hash.h"
4
+ #include "rlite/util.h"
5
+ #include "rlite/page_btree.h"
6
+ #include "rlite/page_key.h"
7
+ #include "rlite/page_multi_string.h"
8
+ #include "rlite/type_string.h"
9
+ #include "rlite/type_zset.h"
10
+ #include "rlite/type_hash.h"
11
11
 
12
12
  #define TYPES_LENGTH 5
13
13
  rl_type types[TYPES_LENGTH] = {
@@ -72,7 +72,7 @@ int rl_key_set(rlite *db, const unsigned char *key, long keylen, unsigned char t
72
72
  }
73
73
  key_obj->version = version;
74
74
 
75
- RL_CALL(rl_btree_add_element, RL_OK, db, btree, db->databases[db->selected_database], digest, key_obj);
75
+ RL_CALL(rl_btree_add_element, RL_OK, db, btree, db->databases[rl_get_selected_db(db)], digest, key_obj);
76
76
  retval = RL_OK;
77
77
  cleanup:
78
78
  if (retval != RL_OK) {
@@ -138,7 +138,6 @@ cleanup:
138
138
  static int rl_key_sha_check_version(struct rlite *db, struct watched_key* key) {
139
139
  int retval;
140
140
  long version;
141
- int selected_database = db->selected_database;
142
141
  // if the key has expired, the version is still valid, according to
143
142
  // https://code.google.com/p/redis/issues/detail?id=270
144
143
  // it seems to be relevant to redis being stateful and single process
@@ -154,7 +153,6 @@ static int rl_key_sha_check_version(struct rlite *db, struct watched_key* key) {
154
153
  retval = RL_OK;
155
154
  }
156
155
  cleanup:
157
- db->selected_database = selected_database;
158
156
  return retval;
159
157
  }
160
158
 
@@ -173,7 +171,7 @@ int rl_watch(struct rlite *db, struct watched_key** _watched_key, const unsigned
173
171
  int retval;
174
172
  struct watched_key* wkey = NULL;
175
173
  RL_MALLOC(wkey, sizeof(struct watched_key));
176
- wkey->database = db->selected_database;
174
+ wkey->database = rl_get_selected_db(db);
177
175
 
178
176
  RL_CALL(sha1, RL_OK, key, keylen, wkey->digest);
179
177
  RL_CALL2(rl_key_get_hash_ignore_expire, RL_FOUND, RL_NOT_FOUND, db, wkey->digest, NULL, NULL, NULL, NULL, &wkey->version, 1);
@@ -230,11 +228,12 @@ int rl_key_delete(struct rlite *db, const unsigned char *key, long keylen)
230
228
  RL_CALL(rl_get_key_btree, RL_OK, db, &btree, 0);
231
229
  retval = rl_btree_find_score(db, btree, digest, &tmp, NULL, NULL);
232
230
  if (retval == RL_FOUND) {
231
+ int selected_database = rl_get_selected_db(db);
233
232
  key_obj = tmp;
234
233
  RL_CALL(rl_multi_string_delete, RL_OK, db, key_obj->string_page);
235
- retval = rl_btree_remove_element(db, btree, db->databases[db->selected_database], digest);
234
+ retval = rl_btree_remove_element(db, btree, db->databases[selected_database], digest);
236
235
  if (retval == RL_DELETED) {
237
- db->databases[db->selected_database] = 0;
236
+ db->databases[selected_database] = 0;
238
237
  retval = RL_OK;
239
238
  }
240
239
  else if (retval != RL_OK) {
@@ -3,10 +3,10 @@
3
3
  #include <stdio.h>
4
4
  #include <math.h>
5
5
  #include "rlite.h"
6
- #include "status.h"
7
- #include "page_list.h"
8
- #include "page_string.h"
9
- #include "util.h"
6
+ #include "rlite/status.h"
7
+ #include "rlite/page_list.h"
8
+ #include "rlite/page_string.h"
9
+ #include "rlite/util.h"
10
10
 
11
11
  #ifdef RL_DEBUG
12
12
  int rl_print_list_node(rl_list *list, rl_list_node *node);
@@ -1,8 +1,8 @@
1
1
  #include <stdlib.h>
2
2
  #include <string.h>
3
3
  #include "rlite.h"
4
- #include "page_long.h"
5
- #include "util.h"
4
+ #include "rlite/page_long.h"
5
+ #include "rlite/util.h"
6
6
 
7
7
  int rl_long_serialize(rlite *UNUSED(db), void *obj, unsigned char *data)
8
8
  {
@@ -1,11 +1,11 @@
1
1
  #include <stdlib.h>
2
2
  #include <string.h>
3
- #include "sha1.h"
3
+ #include "rlite/sha1.h"
4
4
  #include "rlite.h"
5
- #include "page_list.h"
6
- #include "page_string.h"
7
- #include "page_multi_string.h"
8
- #include "util.h"
5
+ #include "rlite/page_list.h"
6
+ #include "rlite/page_string.h"
7
+ #include "rlite/page_multi_string.h"
8
+ #include "rlite/util.h"
9
9
 
10
10
  int rl_normalize_string_range(long totalsize, long *start, long *stop)
11
11
  {
@@ -1,8 +1,8 @@
1
1
  #include <string.h>
2
2
  #include <stdlib.h>
3
- #include "page_skiplist.h"
4
- #include "page_multi_string.h"
5
- #include "util.h"
3
+ #include "rlite/page_skiplist.h"
4
+ #include "rlite/page_multi_string.h"
5
+ #include "rlite/util.h"
6
6
 
7
7
  static int rl_skiplist_random_level()
8
8
  {
@@ -1,8 +1,8 @@
1
1
  #include <stdlib.h>
2
2
  #include <string.h>
3
3
  #include "rlite.h"
4
- #include "page_string.h"
5
- #include "util.h"
4
+ #include "rlite/page_string.h"
5
+ #include "rlite/util.h"
6
6
 
7
7
  int rl_string_serialize(rlite *db, void *obj, unsigned char *data)
8
8
  {
@@ -0,0 +1,448 @@
1
+ #include "rlite.h"
2
+ #include "rlite/util.h"
3
+ #include "rlite/signal.h"
4
+ #include "rlite/flock.h"
5
+ #include "rlite/pubsub.h"
6
+
7
+ #define ENSURE_SUBSCRIPTOR_ID(ret) \
8
+ if (db->subscriber_id == NULL) {\
9
+ generate_subscriber_id(db);\
10
+ if (db->subscriber_id == NULL) {\
11
+ return ret;\
12
+ }\
13
+ }
14
+
15
+ static void generate_subscriber_id(rlite *db);
16
+
17
+ static char *get_lock_filename(rlite *db, char *subscriber_id)
18
+ {
19
+ char suffix[46];
20
+ if (db->driver_type != RL_FILE_DRIVER) {
21
+ return NULL;
22
+ }
23
+ rl_file_driver *driver = db->driver;
24
+ // 40 come from subscriber_id, 5 ".lock" and then a null
25
+ memcpy(suffix, subscriber_id, 40);
26
+ memcpy(&suffix[40], ".lock", 6);
27
+ return rl_get_filename_with_suffix(driver->filename, suffix);
28
+ }
29
+
30
+ static void generate_subscriber_id(rlite *db)
31
+ {
32
+ // TODO: check for collisions and retry?
33
+ // this is probably the worst random hash in the history of programming
34
+ char str[60];
35
+ unsigned char digest[20];
36
+ memset(str, 0, 60);
37
+ snprintf(str, 60, "%llu", rl_mstime());
38
+ snprintf(&str[40], 20, "%d", rand());
39
+ sha1((unsigned char *)str, 60, digest);
40
+ sha1_formatter(digest, &db->subscriber_id, NULL);
41
+
42
+ db->subscriber_lock_filename = get_lock_filename(db, db->subscriber_id);
43
+ if (db->subscriber_lock_filename == NULL) {
44
+ rl_free(db->subscriber_id);
45
+ db->subscriber_id = NULL;
46
+ return;
47
+ }
48
+ db->subscriber_lock_fp = fopen(db->subscriber_lock_filename, "w");
49
+ if (db->subscriber_lock_fp == NULL) {
50
+ rl_free(db->subscriber_lock_filename);
51
+ rl_free(db->subscriber_id);
52
+ db->subscriber_id = NULL;
53
+ return;
54
+ }
55
+ int retval = rl_flock(db->subscriber_lock_fp, RLITE_FLOCK_EX);
56
+ if (retval != RL_OK) {
57
+ fclose(db->subscriber_lock_fp);
58
+ remove(db->subscriber_lock_filename);
59
+ rl_free(db->subscriber_lock_filename);
60
+ rl_free(db->subscriber_id);
61
+ db->subscriber_id = NULL;
62
+ }
63
+ }
64
+
65
+ static char *get_signal_filename(rlite *db, char *subscriber_id)
66
+ {
67
+ rl_file_driver *driver = db->driver;
68
+ return rl_get_filename_with_suffix(driver->filename, subscriber_id);
69
+ }
70
+
71
+ static int do_subscribe(rlite *db, int internal_db_to_subscriber, int internal_db_to_subscription, int subscriptionc, unsigned char **subscriptionv, long *subscriptionvlen)
72
+ {
73
+ int i, retval;
74
+ long identifierlen[1] = {40};
75
+ ENSURE_SUBSCRIPTOR_ID(RL_UNEXPECTED);
76
+ RL_CALL(rl_select_internal, RL_OK, db, internal_db_to_subscriber);
77
+ for (i = 0; i < subscriptionc; i++) {
78
+ RL_CALL(rl_sadd, RL_OK, db, subscriptionv[i], subscriptionvlen[i], 1, (unsigned char **)&db->subscriber_id, identifierlen, NULL);
79
+ }
80
+ RL_CALL(rl_select_internal, RL_OK, db, internal_db_to_subscription);
81
+ RL_CALL(rl_sadd, RL_OK, db, (unsigned char *)db->subscriber_id, identifierlen[0], subscriptionc, subscriptionv, subscriptionvlen, NULL);
82
+ // important! commit to release the exclusive lock
83
+ RL_CALL(rl_commit, RL_OK, db);
84
+ cleanup:
85
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
86
+ return retval;
87
+ }
88
+
89
+ int rl_subscribe(rlite *db, int channelc, unsigned char **channelv, long *channelvlen)
90
+ {
91
+ return do_subscribe(db, RLITE_INTERNAL_DB_CHANNEL_SUBSCRIBERS, RLITE_INTERNAL_DB_SUBSCRIBER_CHANNELS, channelc, channelv, channelvlen);
92
+ }
93
+
94
+ int rl_psubscribe(rlite *db, int patternc, unsigned char **patternv, long *patternvlen)
95
+ {
96
+ return do_subscribe(db, RLITE_INTERNAL_DB_PATTERN_SUBSCRIBERS, RLITE_INTERNAL_DB_SUBSCRIBER_PATTERNS, patternc, patternv, patternvlen);
97
+ }
98
+
99
+ static int do_unsubscribe(rlite *db, int internal_db_to_subscriber, int internal_db_to_subscription, int subscriptionc, unsigned char **subscriptionv, long *subscriptionvlen)
100
+ {
101
+ int i, retval;
102
+ long identifierlen[1] = {40};
103
+ if (db->subscriber_id == NULL) {
104
+ // if there's no subscriber id, then the connection is not subscribed to anything
105
+ return RL_OK;
106
+ }
107
+ RL_CALL(rl_select_internal, RL_OK, db, internal_db_to_subscription);
108
+ RL_CALL2(rl_srem, RL_OK, RL_NOT_FOUND, db, (unsigned char *)db->subscriber_id, identifierlen[0], subscriptionc, subscriptionv, subscriptionvlen, NULL);
109
+ RL_CALL(rl_select_internal, RL_OK, db, internal_db_to_subscriber);
110
+ for (i = 0; i < subscriptionc; i++) {
111
+ RL_CALL2(rl_srem, RL_OK, RL_NOT_FOUND, db, subscriptionv[i], subscriptionvlen[i], 1, (unsigned char **)&db->subscriber_id, identifierlen, NULL);
112
+ }
113
+ // important! commit to release the exclusive lock
114
+ RL_CALL(rl_commit, RL_OK, db);
115
+ cleanup:
116
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
117
+ return retval;
118
+ }
119
+
120
+ int rl_unsubscribe(rlite *db, int channelc, unsigned char **channelv, long *channelvlen)
121
+ {
122
+ return do_unsubscribe(db, RLITE_INTERNAL_DB_CHANNEL_SUBSCRIBERS, RLITE_INTERNAL_DB_SUBSCRIBER_CHANNELS, channelc, channelv, channelvlen);
123
+ }
124
+
125
+ int rl_punsubscribe(rlite *db, int patternc, unsigned char **patternv, long *patternvlen)
126
+ {
127
+ return do_unsubscribe(db, RLITE_INTERNAL_DB_PATTERN_SUBSCRIBERS, RLITE_INTERNAL_DB_SUBSCRIBER_PATTERNS, patternc, patternv, patternvlen);
128
+ }
129
+
130
+ static int rl_unsubscribe_all_type(rlite *db, char *subscriber_id, int internal_db_to_subscriber, int internal_db_to_subscription)
131
+ {
132
+ int i, retval;
133
+ rl_set_iterator *iterator;
134
+ int subscriptionc = 0;
135
+ unsigned char **subscriptionv = NULL, *subscription = NULL;
136
+ long *subscriptionvlen = NULL, subscriptionlen;
137
+ RL_CALL(rl_select_internal, RL_OK, db, internal_db_to_subscription);
138
+ RL_CALL(rl_smembers, RL_OK, db, &iterator, (unsigned char *)subscriber_id, 40);
139
+ RL_MALLOC(subscriptionv, sizeof(char *) * iterator->size);
140
+ RL_MALLOC(subscriptionvlen, sizeof(long) * iterator->size);
141
+ subscriptionc = 0;
142
+ while ((retval = rl_set_iterator_next(iterator, &subscription, &subscriptionlen)) == RL_OK) {
143
+ subscriptionv[subscriptionc] = subscription;
144
+ subscriptionvlen[subscriptionc] = subscriptionlen;
145
+ subscriptionc++;
146
+ subscription = NULL;
147
+ }
148
+ if (retval != RL_END) {
149
+ goto cleanup;
150
+ }
151
+ RL_CALL(do_unsubscribe, RL_OK, db, internal_db_to_subscriber, internal_db_to_subscription, subscriptionc, subscriptionv, subscriptionvlen);
152
+ cleanup:
153
+ if (subscriptionv) {
154
+ for (i = 0; i < subscriptionc; i++) {
155
+ rl_free(subscriptionv[i]);
156
+ }
157
+ rl_free(subscriptionv);
158
+ }
159
+ rl_free(subscriptionvlen);
160
+ rl_free(subscription);
161
+ return retval;
162
+ }
163
+
164
+ static int rl_unsubscribe_all_subscriber(rlite *db, char *subscriber_id)
165
+ {
166
+ int retval;
167
+ char *subscriber_lock_filename = NULL;
168
+
169
+ RL_CALL2(rl_unsubscribe_all_type, RL_OK, RL_NOT_FOUND, db, subscriber_id, RLITE_INTERNAL_DB_CHANNEL_SUBSCRIBERS, RLITE_INTERNAL_DB_SUBSCRIBER_CHANNELS);
170
+ RL_CALL2(rl_unsubscribe_all_type, RL_OK, RL_NOT_FOUND, db, subscriber_id, RLITE_INTERNAL_DB_PATTERN_SUBSCRIBERS, RLITE_INTERNAL_DB_SUBSCRIBER_PATTERNS);
171
+
172
+ subscriber_lock_filename = get_lock_filename(db, subscriber_id);
173
+ char *filename = get_signal_filename(db, subscriber_id);
174
+ remove(filename);
175
+ rl_free(filename);
176
+ cleanup:
177
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
178
+ if (retval == RL_NOT_FOUND) {
179
+ retval = RL_OK;
180
+ }
181
+ rl_free(subscriber_lock_filename);
182
+ return retval;
183
+ }
184
+
185
+ int rl_unsubscribe_all(rlite *db)
186
+ {
187
+ if (db->subscriber_id == NULL) {
188
+ // if there's no subscriber id, then the connection is not subscribed to anything
189
+ return RL_OK;
190
+ }
191
+ rl_refresh(db);
192
+ int retval = rl_unsubscribe_all_subscriber(db, db->subscriber_id);
193
+ if (retval == RL_OK) {
194
+ fclose(db->subscriber_lock_fp);
195
+ rl_free(db->subscriber_id);
196
+ db->subscriber_id = NULL;
197
+ }
198
+ return retval;
199
+ }
200
+
201
+ int rl_poll_wait(rlite *db, int *elementc, unsigned char ***_elements, long **_elementslen, struct timeval *timeout)
202
+ {
203
+ int retval = rl_poll(db, elementc, _elements, _elementslen);
204
+ if (retval == RL_NOT_FOUND) {
205
+ // TODO: possible race condition between poll and signal read?
206
+ // can we atomically do both without locking the database?
207
+ ENSURE_SUBSCRIPTOR_ID(RL_UNEXPECTED);
208
+ char *filename = get_signal_filename(db, db->subscriber_id);
209
+ rl_discard(db);
210
+ rl_create_signal(filename);
211
+ rl_read_signal(filename, timeout, NULL, NULL);
212
+ rl_free(filename);
213
+ rl_refresh(db);
214
+ retval = rl_poll(db, elementc, _elements, _elementslen);
215
+ }
216
+ return retval;
217
+ }
218
+
219
+ int rl_poll(rlite *db, int *elementc, unsigned char ***_elements, long **_elementslen)
220
+ {
221
+ int retval;
222
+ unsigned char *len = NULL, i;
223
+ long lenlen;
224
+ unsigned char **elements = NULL;
225
+ long *elementslen = NULL;
226
+ if (db->subscriber_id == NULL) {
227
+ retval = RL_NOT_FOUND;
228
+ goto cleanup;
229
+ }
230
+ RL_CALL(rl_refresh, RL_OK, db);
231
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_SUBSCRIBER_MESSAGES);
232
+ RL_CALL(rl_pop, RL_OK, db, (unsigned char *)db->subscriber_id, 40, &len, &lenlen, 1);
233
+ if (lenlen != 1) {
234
+ // TODO: delete the key and commit? PANIC
235
+ retval = RL_UNEXPECTED;
236
+ goto cleanup;
237
+ }
238
+
239
+ *elementc = len[0];
240
+ RL_MALLOC(elements, sizeof(unsigned char *) * len[0]);
241
+ RL_MALLOC(elementslen, sizeof(long) * len[0]);
242
+ for (i = 0; i < len[0]; i++) {
243
+ RL_CALL(rl_pop, RL_OK, db, (unsigned char *)db->subscriber_id, 40, &elements[i], &elementslen[i], 1);
244
+ }
245
+ *_elements = elements;
246
+ *_elementslen = elementslen;
247
+ RL_CALL(rl_commit, RL_OK, db);
248
+ cleanup:
249
+ rl_free(len);
250
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
251
+ return retval;
252
+ }
253
+
254
+ static int do_publish(rlite *db, char *subscriber_id, long subscribed_idlen, int valuec, unsigned char *values[], long valueslen[])
255
+ {
256
+ int retval;
257
+ char *filename = NULL;
258
+ filename = get_lock_filename(db, subscriber_id);
259
+ if (rl_is_flocked(filename, RLITE_FLOCK_EX) == RL_NOT_FOUND) {
260
+ // the client has "disconnected"; clean up for them
261
+ RL_CALL(rl_unsubscribe_all_subscriber, RL_OK, db, subscriber_id);
262
+ retval = RL_NOT_FOUND;
263
+ } else {
264
+ RL_CALL(rl_push, RL_OK, db, (unsigned char *)subscriber_id, subscribed_idlen, 1, 0, valuec, values, valueslen, NULL);
265
+
266
+ rl_free(filename); // reusing variables?! WHO WROTE THIS?
267
+ filename = get_signal_filename(db, subscriber_id);
268
+ // this only signals the signal recipient that new data is available
269
+ // - Maybe this should be executed AFTER the push was commited?
270
+ // - Ah, we have an exclusive lock anyway, so they'll have to wait
271
+ // when they poll
272
+ rl_write_signal(filename, "1", 1);
273
+ }
274
+ cleanup:
275
+ rl_free(filename);
276
+ return retval;
277
+ }
278
+
279
+ static int publish_to_members(rlite *db, rl_set_iterator *iterator, int valuec, unsigned char *values[], long valueslen[], long *recipients)
280
+ {
281
+ int retval;
282
+ unsigned char *value = NULL;
283
+ long valuelen;
284
+ char *subscriber_id = NULL;
285
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_SUBSCRIBER_MESSAGES);
286
+ while ((retval = rl_set_iterator_next(iterator, &value, &valuelen)) == RL_OK) {
287
+ subscriber_id = rl_malloc(sizeof(char) * (valuelen + 1));
288
+ memcpy(subscriber_id, value, valuelen);
289
+ subscriber_id[valuelen] = 0;
290
+
291
+ retval = do_publish(db, subscriber_id, valuelen, valuec, values, valueslen);
292
+ if (retval == RL_OK) {
293
+ (*recipients)++;
294
+ } else if (retval != RL_NOT_FOUND) {
295
+ goto cleanup;
296
+ }
297
+ rl_free(subscriber_id);
298
+ subscriber_id = NULL;
299
+ rl_free(value);
300
+ value = NULL;
301
+ }
302
+ if (retval == RL_END) {
303
+ retval = RL_OK;
304
+ }
305
+
306
+ cleanup:
307
+ rl_free(value);
308
+ rl_free(subscriber_id);
309
+ return retval;
310
+ }
311
+
312
+ int rl_publish(rlite *db, unsigned char *channel, size_t channellen, const char *data, size_t datalen, long *recipients)
313
+ {
314
+ int retval;
315
+ long i, patternc = 0;
316
+ unsigned char **patternv = NULL;
317
+ long *patternvlen = NULL;
318
+ unsigned char *values[5];
319
+ long valueslen[5];
320
+ rl_set_iterator *iterator;
321
+ *recipients = 0;
322
+
323
+ #define MESSAGE "message"
324
+ unsigned char q = 3;
325
+ values[0] = &q;
326
+ valueslen[0] = 1;
327
+ values[1] = (unsigned char *)MESSAGE;
328
+ valueslen[1] = (long)strlen(MESSAGE);
329
+ values[2] = channel;
330
+ valueslen[2] = channellen;
331
+ values[3] = (unsigned char *)data;
332
+ valueslen[3] = datalen;
333
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_CHANNEL_SUBSCRIBERS);
334
+ RL_CALL2(rl_smembers, RL_OK, RL_NOT_FOUND, db, &iterator, channel, channellen);
335
+ if (retval == RL_OK) {
336
+ RL_CALL(publish_to_members, RL_OK, db, iterator, 4, values, valueslen, recipients)
337
+ }
338
+
339
+ #define PMESSAGE "pmessage"
340
+ q = 4;
341
+ values[0] = &q;
342
+ valueslen[0] = 1;
343
+ values[1] = (unsigned char *)PMESSAGE;
344
+ valueslen[1] = (long)strlen(PMESSAGE);
345
+ values[3] = channel;
346
+ valueslen[3] = channellen;
347
+ values[4] = (unsigned char *)data;
348
+ valueslen[4] = datalen;
349
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_PATTERN_SUBSCRIBERS);
350
+ RL_CALL2(rl_keys, RL_OK, RL_NOT_FOUND, db, (unsigned char *)"*", 1, &patternc, &patternv, &patternvlen);
351
+ if (retval == RL_NOT_FOUND || patternc == 0) {
352
+ retval = RL_OK;
353
+ goto postpattern;
354
+ }
355
+ for (i = 0; i < patternc; i++) {
356
+ if (!rl_stringmatchlen((char *)patternv[i], patternvlen[i], (char *)channel, channellen, 0)) {
357
+ continue;
358
+ }
359
+ RL_CALL2(rl_smembers, RL_OK, RL_NOT_FOUND, db, &iterator, patternv[i], patternvlen[i]);
360
+ if (retval == RL_OK) {
361
+ values[2] = patternv[i];
362
+ valueslen[2] = patternvlen[i];
363
+ RL_CALL(publish_to_members, RL_OK, db, iterator, 5, values, valueslen, recipients)
364
+ }
365
+ }
366
+ postpattern:
367
+ // this is equivalent to cleanup, but I'd rather leave this here for clarity
368
+ // since an early not found needs to skip a bunch of code
369
+
370
+ cleanup:
371
+ for (i = 0; i < patternc; i++) {
372
+ rl_free(patternv[i]);
373
+ }
374
+ rl_free(patternv);
375
+ rl_free(patternvlen);
376
+
377
+ if (retval == RL_NOT_FOUND) {
378
+ // no subscriber? no problem
379
+ retval = RL_OK;
380
+ }
381
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
382
+ return retval;
383
+ }
384
+
385
+ int rl_pubsub_patterns(rlite *db, long *patternc, unsigned char ***patternv, long **patternvlen)
386
+ {
387
+ int retval;
388
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_PATTERN_SUBSCRIBERS);
389
+ RL_CALL2(rl_keys, RL_OK, RL_NOT_FOUND, db, (unsigned char *)"*", 1, patternc, patternv, patternvlen);
390
+ cleanup:
391
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
392
+ return retval;
393
+ }
394
+
395
+ int rl_pubsub_channels(rlite *db, unsigned char *pattern, long patternlen, long *channelc, unsigned char ***channelv, long **channelvlen)
396
+ {
397
+ int retval;
398
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_CHANNEL_SUBSCRIBERS);
399
+ RL_CALL2(rl_keys, RL_OK, RL_NOT_FOUND, db, pattern ? pattern : (unsigned char *)"*", pattern ? patternlen : 1, channelc, channelv, channelvlen);
400
+ cleanup:
401
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
402
+ return retval;
403
+ }
404
+
405
+ int rl_pubsub_numsub(rlite *db, int channelc, unsigned char **channelv, long *channelvlen, long *numsub)
406
+ {
407
+ int i, retval;
408
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_CHANNEL_SUBSCRIBERS);
409
+ for (i = 0; i < channelc; i++) {
410
+ numsub[i] = 0;
411
+ RL_CALL2(rl_scard, RL_OK, RL_NOT_FOUND, db, channelv[i], channelvlen[i], &numsub[i]);
412
+ }
413
+ retval = RL_OK;
414
+ cleanup:
415
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
416
+ return retval;
417
+ }
418
+
419
+ int rl_pubsub_numpat(rlite *db, long *numpat)
420
+ {
421
+ int retval;
422
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_PATTERN_SUBSCRIBERS);
423
+ RL_CALL(rl_dbsize, RL_OK, db, numpat);
424
+ retval = RL_OK;
425
+ cleanup:
426
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
427
+ return retval;
428
+ }
429
+
430
+ int rl_pubsub_count_subscriptions(rlite *db, long *numsubscriptions)
431
+ {
432
+ int retval;
433
+ if (!db->subscriber_id) {
434
+ *numsubscriptions = 0;
435
+ retval = RL_OK;
436
+ goto cleanup;
437
+ }
438
+ long count = 0, count2 = 0;
439
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_SUBSCRIBER_CHANNELS);
440
+ RL_CALL2(rl_scard, RL_OK, RL_NOT_FOUND, db, (unsigned char *)db->subscriber_id, 40, &count);
441
+ RL_CALL(rl_select_internal, RL_OK, db, RLITE_INTERNAL_DB_SUBSCRIBER_PATTERNS);
442
+ RL_CALL2(rl_scard, RL_OK, RL_NOT_FOUND, db, (unsigned char *)db->subscriber_id, 40, &count2);
443
+ *numsubscriptions = count + count2;
444
+ retval = RL_OK;
445
+ cleanup:
446
+ rl_select_internal(db, RLITE_INTERNAL_DB_NO);
447
+ return retval;
448
+ }