hirlite 0.0.2.2 → 0.1.0

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.
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
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 230e3116dc619903ad5ccacfc55db410285d49df
4
- data.tar.gz: a5a2438d15aee3f321ae07292f716133c566f01b
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YjUxZDMzOWRkZTFmMzM5MzczYWM4ODMwMDNhNjdiNzQ0N2M5ZDBkOQ==
5
+ data.tar.gz: !binary |-
6
+ ZTVlOGRiYjkyZGIzZGFlOGFlNTg0YzBhZWJhMWZjYjE2ZmM0Y2U2OA==
5
7
  SHA512:
6
- metadata.gz: 9d8409500bc29bbcb49c2789e84e2b8472a4ead6c28aac001433193c068aaf4d82525ef7aa555a3f5a6a18f13fc329a5996cc005f58c7cdfb530095ab4374acf
7
- data.tar.gz: 24887f0b6bab58f80d42860c9093be592b27a77f3d5ff7075cfc1a720fc400eb8b265a6ee2a80b7109791025d585eb0461579b0281377fa85af3698fc73d2f15
8
+ metadata.gz: !binary |-
9
+ NjBjNDIxZjdiYTUwM2FlOWQ1ODFjOGI0Yjg3ZTllMmE3ZmU0NGYzZWYyNDMy
10
+ YzNkYzliYThhMjlhYWQ5NTBiNmJiOGY3YjhjYjAyOWZjNmE3MzFiZTY4YTBj
11
+ MmU0YzBlYWM3NDlhNGNkMTY2ZmM2Yzk3ZjUzMzI1MjEyMDliNjA=
12
+ data.tar.gz: !binary |-
13
+ NDYwOWQ5YWE5OWI0MWFmNGQ4ZDk1YzIxZDU1MDliN2QyMDk0NTkzYWM0YTI1
14
+ NjgxNDY1MTZlZmM0YWE3MzI5NWRiYzZlNzI4MjhmMjg2MTVhMjVjOTJlZmFj
15
+ MTM0NWQzNTQ2NDYzNzZmNmQ2ZjNlOTAxMzhmMDY3OTVlYWVkODc=
@@ -8,7 +8,7 @@
8
8
  */
9
9
  #define RSTRING_NOT_MODIFIED
10
10
 
11
- #include "hirlite.h"
11
+ #include "rlite/hirlite.h"
12
12
  #include "ruby.h"
13
13
 
14
14
  /* Defined in hirlite_ext.c */
@@ -95,7 +95,7 @@ static VALUE rlite_parent_context_alloc(VALUE klass) {
95
95
  return Data_Wrap_Struct(klass, parent_context_mark, parent_context_free, pc);
96
96
  }
97
97
 
98
- static VALUE rlite_generic_connect(VALUE self, rliteContext *c, VALUE arg_timeout) {
98
+ static VALUE rlite_generic_connect(VALUE self, rliteContext *c) {
99
99
  rliteParentContext *pc;
100
100
 
101
101
  Data_Get_Struct(self,rliteParentContext,pc);
@@ -127,50 +127,30 @@ static VALUE rlite_connect(int argc, VALUE *argv, VALUE self) {
127
127
  rliteContext *c;
128
128
  VALUE arg_host = Qnil;
129
129
  VALUE arg_port = Qnil;
130
- VALUE arg_timeout = Qnil;
131
130
 
132
131
  if (argc == 2 || argc == 3) {
133
132
  arg_host = argv[0];
134
133
  arg_port = argv[1];
135
-
136
- if (argc == 3) {
137
- arg_timeout = argv[2];
138
-
139
- /* Sanity check */
140
- if (NUM2INT(arg_timeout) <= 0) {
141
- rb_raise(rb_eArgError, "timeout should be positive");
142
- }
143
- }
144
134
  } else {
145
135
  rb_raise(rb_eArgError, "invalid number of arguments");
146
136
  }
147
137
 
148
138
  c = rliteConnectNonBlock(StringValuePtr(arg_host), NUM2INT(arg_port));
149
- return rlite_generic_connect(self,c,arg_timeout);
139
+ return rlite_generic_connect(self,c);
150
140
  }
151
141
 
152
142
  static VALUE rlite_connect_unix(int argc, VALUE *argv, VALUE self) {
153
143
  rliteContext *c;
154
144
  VALUE arg_path = Qnil;
155
- VALUE arg_timeout = Qnil;
156
145
 
157
146
  if (argc == 1 || argc == 2) {
158
147
  arg_path = argv[0];
159
-
160
- if (argc == 2) {
161
- arg_timeout = argv[1];
162
-
163
- /* Sanity check */
164
- if (NUM2INT(arg_timeout) <= 0) {
165
- rb_raise(rb_eArgError, "timeout should be positive");
166
- }
167
- }
168
148
  } else {
169
149
  rb_raise(rb_eArgError, "invalid number of arguments");
170
150
  }
171
151
 
172
152
  c = rliteConnectUnixNonBlock(StringValuePtr(arg_path));
173
- return rlite_generic_connect(self,c,arg_timeout);
153
+ return rlite_generic_connect(self,c);
174
154
  }
175
155
 
176
156
  static VALUE rlite_is_connected(VALUE self) {
@@ -50,6 +50,10 @@ class Rlite
50
50
 
51
51
  def read
52
52
  reply = @connection.read
53
+ if reply == nil
54
+ write(['__rlite_poll'])
55
+ reply = @connection.read
56
+ end
53
57
  reply = CommandError.new(reply.message) if reply.is_a?(RuntimeError)
54
58
  reply
55
59
  rescue Errno::EAGAIN
@@ -1,3 +1,3 @@
1
1
  module Hirlite
2
- VERSION = "0.0.2.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -46,7 +46,7 @@
46
46
  #include "strbuf.h"
47
47
  #include "fpconv.h"
48
48
 
49
- #include "../../../src/solarisfixes.h"
49
+ #include "../../../src/rlite/solarisfixes.h"
50
50
 
51
51
  #ifndef CJSON_MODNAME
52
52
  #define CJSON_MODNAME "cjson"
@@ -8,7 +8,8 @@
8
8
 
9
9
  uname_S:= $(shell sh -c 'uname -s 2>/dev/null || echo not')
10
10
 
11
- OBJ=rlite.o page_skiplist.o page_string.o page_list.o page_btree.o page_key.o page_multi_string.o page_long.o type_string.o type_list.o type_set.o type_zset.o type_hash.o util.o restore.o dump.o sort.o pqsort.o utilfromredis.o hyperloglog.o sha1.o crc64.o lzf_c.o lzf_d.o scripting.o rand.o hirlite.o
11
+ OBJ=rlite.o page_skiplist.o page_string.o page_list.o page_btree.o page_key.o page_multi_string.o page_long.o type_string.o type_list.o type_set.o type_zset.o type_hash.o util.o restore.o dump.o sort.o pqsort.o utilfromredis.o hyperloglog.o sha1.o crc64.o lzf_c.o lzf_d.o scripting.o rand.o flock_posix.o signal_posix.o pubsub.o wal.o hirlite.o
12
+ LUA_OBJ=../deps/lua/src/lapi.o ../deps/lua/src/lcode.o ../deps/lua/src/ldebug.o ../deps/lua/src/ldo.o ../deps/lua/src/ldump.o ../deps/lua/src/lfunc.o ../deps/lua/src/lgc.o ../deps/lua/src/llex.o ../deps/lua/src/lmem.o ../deps/lua/src/lobject.o ../deps/lua/src/lopcodes.o ../deps/lua/src/lparser.o ../deps/lua/src/lstate.o ../deps/lua/src/lstring.o ../deps/lua/src/ltable.o ../deps/lua/src/ltm.o ../deps/lua/src/lundump.o ../deps/lua/src/lvm.o ../deps/lua/src/lzio.o ../deps/lua/src/strbuf.o ../deps/lua/src/fpconv.o ../deps/lua/src/lauxlib.o ../deps/lua/src/lbaselib.o ../deps/lua/src/ldblib.o ../deps/lua/src/liolib.o ../deps/lua/src/lmathlib.o ../deps/lua/src/loslib.o ../deps/lua/src/ltablib.o ../deps/lua/src/lstrlib.o ../deps/lua/src/loadlib.o ../deps/lua/src/linit.o ../deps/lua/src/lua_cjson.o ../deps/lua/src/lua_struct.o ../deps/lua/src/lua_cmsgpack.o ../deps/lua/src/lua_bit.o
12
13
  LIBNAME=libhirlite
13
14
  PKGCONFNAME=hirlite.pc
14
15
 
@@ -27,7 +28,6 @@ endif
27
28
 
28
29
  CFLAGS += -I./ -I../deps/lua/src/
29
30
 
30
- DEBUG.gcc += -rdynamic
31
31
  CFLAGS.gcc += -std=c99
32
32
 
33
33
  ifeq ($(shell $(CC) -v 2>&1 | grep -c "clang version"), 1)
@@ -38,7 +38,7 @@ DEBUG += ${DEBUG.gcc}
38
38
  CFLAGS += ${CFLAGS.gcc}
39
39
  endif
40
40
 
41
- LIBS=-lm
41
+ LIBS=-lm -lpthread
42
42
 
43
43
  INSTALL?= cp -a
44
44
  # Installation related variables and target
@@ -70,19 +70,11 @@ STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
70
70
 
71
71
  all: $(DYLIBNAME) $(STLIBNAME)
72
72
 
73
- gcov: CFLAGS += -fprofile-arcs -ftest-coverage
74
- gcov: clean test
75
-
76
- builddebug: CFLAGS += -DDEBUG=1
77
- builddebug: clean buildtest
78
-
79
- debug: builddebug vtest
80
-
81
73
  ifeq ($(uname_S),SunOS)
82
74
  # Make isinf() available
83
75
  LUA_CFLAGS= -D__C99FEATURES__=1
84
76
  endif
85
- LUA_CFLAGS+= -O2 -Wall -DENABLE_CJSON_GLOBAL $(CFLAGS)
77
+ LUA_CFLAGS+= -O2 -Wall -DENABLE_CJSON_GLOBAL -fPIC $(CFLAGS)
86
78
  LUA_LDFLAGS+= $(LDFLAGS)
87
79
  LUA_STLIB=../deps/lua/src/liblua.a
88
80
  AR=ar
@@ -96,9 +88,6 @@ lcov: gcov
96
88
  lcov --directory . --capture --output-file lcov/app.info
97
89
  genhtml lcov/app.info -o lcov/html
98
90
 
99
- full-lcov: CFLAGS += -fprofile-arcs -ftest-coverage -DDEBUG=1
100
- full-lcov: clean buildtest
101
-
102
91
  clang-analyzer:
103
92
  rm -rf analyzer
104
93
  scan-build -o analyzer $(MAKE)
@@ -107,22 +96,19 @@ clang-analyzer:
107
96
  $(CC) $(ARCH) $(DEBUG) $(CFLAGS) -c $<
108
97
 
109
98
  $(DYLIBNAME): $(OBJ) lua
110
- $(DYLIB_MAKE_CMD) $(LUA_STLIB) $(OBJ)
99
+ $(DYLIB_MAKE_CMD) $(LUA_OBJ) $(OBJ)
111
100
 
112
101
  $(STLIBNAME): $(OBJ)
113
102
  ar -cq libhirlite.a $(OBJ)
114
103
 
115
- buildtest: $(STLIBNAME) test/rlite-test.o test/btree-test.o test/list-test.o test/string-test.o test/multi_string-test.o test/multi-test.o test/key-test.o test/type_string-test.o test/type_list-test.o test/type_set-test.o test/type_zset-test.o test/type_hash-test.o test/skiplist-test.o test/long-test.o test/restore-test.o test/hyperloglog-test.o test/dump-test.o test/sort-test.o test/test_util.o test/test.o test/echo.o test/hash.o test/list.o test/parser.o test/set.o test/string.o test/test_hirlite.o test/zset.o test/db.o test/multi.o test/hsort.o test/scripting-test.o
116
- $(CC) $(DEBUG) $(CFLAGS) -o rlite-test test.o rlite-test.o btree-test.o list-test.o string-test.o multi_string-test.o multi-test.o key-test.o type_string-test.o type_list-test.o type_set-test.o type_zset-test.o type_hash-test.o skiplist-test.o long-test.o restore-test.o hyperloglog-test.o dump-test.o sort-test.o test_util.o $(STLIBNAME) $(LIBS)
117
- $(CC) $(DEBUG) $(CFLAGS) -o hirlite-test echo.o hash.o list.o parser.o set.o string.o test_hirlite.o zset.o db.o multi.o hsort.o scripting-test.o $(STLIBNAME) $(LUA_STLIB) $(LIBS)
104
+ buildtest: $(STLIBNAME)
105
+ cd ../tests/ && $(MAKE) buildtest
118
106
 
119
- test: buildtest
120
- ./rlite-test
121
- ./hirlite-test
107
+ test: $(STLIBNAME)
108
+ cd ../tests/ && $(MAKE) test
122
109
 
123
- vtest: buildtest
124
- valgrind --track-origins=yes --leak-check=full --show-reachable=yes ./rlite-test
125
- valgrind --track-origins=yes --leak-check=full --show-reachable=yes ./hirlite-test
110
+ vtest: $(STLIBNAME)
111
+ cd ../tests/ && $(MAKE) vtest
126
112
 
127
113
  $(PKGCONFNAME): hirlite.h
128
114
  @echo "Generating $@ for pkgconfig..."
@@ -149,3 +135,4 @@ install: $(DYLIBNAME) $(STLIBNAME) $(PKGCONFNAME)
149
135
 
150
136
  clean:
151
137
  rm -rf *-test *.o *.a *.dSYM *.gcda *.gcno lcov *.dylib ./deps/lua/src/*.a
138
+ cd ../tests && $(MAKE) clean
@@ -1,8 +1,8 @@
1
1
  #include <arpa/inet.h>
2
2
  #include "rlite.h"
3
- #include "util.h"
4
- #include "crc64.h"
5
- #include "endianconv.h"
3
+ #include "rlite/util.h"
4
+ #include "rlite/crc64.h"
5
+ #include "rlite/endianconv.h"
6
6
 
7
7
  int rl_dump(struct rlite *db, const unsigned char *key, long keylen, unsigned char **data, long *datalen)
8
8
  {
@@ -0,0 +1,79 @@
1
+ #include <sys/fcntl.h>
2
+ #include <sys/file.h>
3
+ #include <sys/time.h>
4
+ #include <unistd.h>
5
+ #include <errno.h>
6
+
7
+ #include "rlite.h"
8
+
9
+ int rl_flock(FILE *fp, int type)
10
+ {
11
+ int fd = fileno(fp);
12
+ int locktype;
13
+ if (type == RLITE_FLOCK_SH) {
14
+ locktype = LOCK_SH;
15
+ } else if (type == RLITE_FLOCK_EX) {
16
+ locktype = LOCK_EX;
17
+ } else if (type == RLITE_FLOCK_UN) {
18
+ locktype = LOCK_UN;
19
+ } else {
20
+ return RL_UNEXPECTED;
21
+ }
22
+ flock(fd, locktype);
23
+ return RL_OK;
24
+ }
25
+
26
+ int rl_is_flocked(const char *path, int type)
27
+ {
28
+ int retval, oflags = O_NONBLOCK;
29
+ int locktype;
30
+
31
+ if (type == RLITE_FLOCK_SH) {
32
+ oflags |= O_RDONLY;
33
+ // we want to know if someone has a shared lock
34
+ // if we can get an exclusive, we know they do not
35
+ // if we cannot, we will try to get a shared to discard someone
36
+ // having an exclusive one
37
+ locktype = LOCK_EX;
38
+ } else if (type == RLITE_FLOCK_EX) {
39
+ oflags |= O_WRONLY;
40
+ // we'll get a shared lock iff nobody has an exclusive lock
41
+ locktype = LOCK_SH;
42
+ } else {
43
+ return RL_UNEXPECTED;
44
+ }
45
+ int fd = open(path, oflags);
46
+ if (fd == -1) {
47
+ // if the file does not exist, the lock is not found
48
+ if (errno == ENOENT || errno == EACCES) {
49
+ return RL_NOT_FOUND;
50
+ }
51
+ return RL_UNEXPECTED;
52
+ }
53
+
54
+ retval = flock(fd, locktype | LOCK_NB);
55
+ if (retval == 0) {
56
+ retval = RL_NOT_FOUND;
57
+ goto cleanup;
58
+ }
59
+ if (errno == EWOULDBLOCK) {
60
+ if (type == RLITE_FLOCK_SH) {
61
+ retval = flock(fd, LOCK_SH | LOCK_NB);
62
+ if (retval == 0) {
63
+ // can get a shared lock but not an exclusive
64
+ // thus someone has a shared lock
65
+ retval = RL_FOUND;
66
+ goto cleanup;
67
+ } else {
68
+ retval = RL_NOT_FOUND;
69
+ goto cleanup;
70
+ }
71
+ }
72
+ retval = RL_FOUND;
73
+ goto cleanup;
74
+ }
75
+ retval = RL_UNEXPECTED;
76
+ cleanup:
77
+ close(fd);
78
+ return retval;
79
+ }
@@ -0,0 +1,6 @@
1
+ #include "rlite.h"
2
+
3
+ int rl_flock(FILE *fp, int type) {
4
+ // TODO: implement flock
5
+ return RL_OK;
6
+ }
@@ -1,5 +1,5 @@
1
1
  #include <stdio.h>
2
- #include "constants.h"
2
+ #include "rlite/constants.h"
3
3
  #include <assert.h>
4
4
  #include <errno.h>
5
5
  #include <ctype.h>
@@ -11,10 +11,11 @@
11
11
  #include <time.h>
12
12
  #include <unistd.h>
13
13
 
14
- #include "hyperloglog.h"
15
- #include "hirlite.h"
16
- #include "scripting.h"
17
- #include "util.h"
14
+ #include "rlite/hyperloglog.h"
15
+ #include "rlite/hirlite.h"
16
+ #include "rlite/scripting.h"
17
+ #include "rlite/util.h"
18
+ #include "rlite/pubsub.h"
18
19
 
19
20
  #define UNSIGN(val) ((unsigned char *)val)
20
21
 
@@ -23,9 +24,13 @@
23
24
  c->reply = createErrorObject(RLITE_WRONGTYPEERR);\
24
25
  goto cleanup;\
25
26
  }\
27
+ if (retval == RL_UNEXPECTED) {\
28
+ c->reply = createErrorObject("ERR unexpected");\
29
+ goto cleanup;\
30
+ }\
26
31
  if (retval == RL_OVERFLOW) {\
27
32
  c->reply = createErrorObject("ERR increment would produce NaN or Infinity");\
28
- return;\
33
+ goto cleanup;\
29
34
  }\
30
35
  if (retval == RL_NAN) {\
31
36
  c->reply = createErrorObject("ERR resulting score is not a number (NaN)");\
@@ -188,8 +193,7 @@ static int addReply(rliteContext* c, rliteReply *reply) {
188
193
  c->replies = tmp;
189
194
  }
190
195
 
191
- c->replies[c->replyPosition] = reply;
192
- c->replyLength++;
196
+ c->replies[c->replyLength++] = reply;
193
197
  return RLITE_OK;
194
198
  }
195
199
 
@@ -605,6 +609,10 @@ int rliteFormatCommandArgv(rliteClient *client, int argc, char **argv, size_t *a
605
609
  return RLITE_OK;
606
610
  }
607
611
 
612
+ static int refresh_rlite_fp(rliteContext* context) {
613
+ return rl_refresh(context->db);
614
+ }
615
+
608
616
  #define DEFAULT_REPLIES_SIZE 16
609
617
  static rliteContext *_rliteConnect(const char *path) {
610
618
  rliteContext *context = malloc(sizeof(*context));
@@ -617,6 +625,15 @@ static rliteContext *_rliteConnect(const char *path) {
617
625
  context = NULL;
618
626
  goto cleanup;
619
627
  }
628
+ size_t pathlen = 1 + strlen(path);
629
+ context->path = malloc(sizeof(char) * pathlen);
630
+ if (!context->path) {
631
+ free(context->replies);
632
+ free(context);
633
+ context = NULL;
634
+ goto cleanup;
635
+ }
636
+ memcpy(context->path, path, pathlen);
620
637
  context->err = 0;
621
638
  context->writeCommand = NULL;
622
639
  context->replyPosition = 0;
@@ -627,18 +644,31 @@ static rliteContext *_rliteConnect(const char *path) {
627
644
  context->cluster_enabled = 0;
628
645
  context->hashtableLimitValue = 0;
629
646
  context->inLuaScript = 0;
630
- int retval = rl_open(path, &context->db, RLITE_OPEN_READWRITE | RLITE_OPEN_CREATE);
631
- if (retval != RL_OK) {
632
- free(context);
633
- context = NULL;
634
- goto cleanup;
635
- }
636
647
  context->inTransaction = 0;
637
648
  context->transactionFailed = 0;
638
649
  context->watchedKeysLength = context->enqueuedCommandsLength = 0;
639
650
  context->watchedKeysAlloc = context->enqueuedCommandsAlloc = 0;
640
651
  context->watchedKeys = NULL;
641
652
  context->enqueuedCommands = NULL;
653
+ context->db = NULL;
654
+ int retval = rl_open(context->path, &context->db, RLITE_OPEN_READWRITE | RLITE_OPEN_CREATE);;
655
+ if (retval != RL_OK) {
656
+ free(context->path);
657
+ free(context->replies);
658
+ free(context);
659
+ context = NULL;
660
+ goto cleanup;
661
+ }
662
+ // if created, need to release locks
663
+ retval = rl_commit(context->db);
664
+ if (retval != RL_OK) {
665
+ rl_close(context->db);
666
+ free(context->path);
667
+ free(context->replies);
668
+ free(context);
669
+ context = NULL;
670
+ goto cleanup;
671
+ }
642
672
  cleanup:
643
673
  return context;
644
674
  }
@@ -682,12 +712,15 @@ int rliteEnableKeepAlive(rliteContext *UNUSED(c)) {
682
712
  return 0;
683
713
  }
684
714
  void rliteFree(rliteContext *c) {
685
- rl_close(c->db);
715
+ if (c->db) {
716
+ rl_close(c->db);
717
+ }
686
718
  int i;
687
719
  for (i = c->replyPosition; i < c->replyLength; i++) {
688
720
  rliteFreeReplyObject(c->replies[i]);
689
721
  }
690
722
  free(c->replies);
723
+ free(c->path);
691
724
  free(c);
692
725
  }
693
726
 
@@ -759,6 +792,7 @@ static void execCommand(rliteClient *c) {
759
792
  c->reply = createErrorObject("EXECABORT Transaction discarded because of previous errors.");
760
793
  goto cleanup;
761
794
  }
795
+ RL_CALL(refresh_rlite_fp, RL_OK, c->context);
762
796
  retval = rl_check_watched_keys(c->context->db, c->context->watchedKeysLength, c->context->watchedKeys);
763
797
  RLITE_SERVER_ERR(c, retval);
764
798
  if (retval != RL_OK) {
@@ -797,7 +831,7 @@ static void execCommand(rliteClient *c) {
797
831
  if (command->sflags[i] == 'w') {
798
832
  char *argv[] = {"multi"};
799
833
  size_t argvlen[] = {5};
800
- c->context->writeCommand(c->context->db->selected_database, 1, argv, argvlen);
834
+ c->context->writeCommand(rl_get_selected_db(c->context->db), 1, argv, argvlen);
801
835
  written = 1;
802
836
  break;
803
837
  }
@@ -805,7 +839,7 @@ static void execCommand(rliteClient *c) {
805
839
  }
806
840
  RL_CALL(rl_dirty_hash, RL_OK, client->context->db, &newhash);
807
841
  if (newhash && (!oldhash || memcmp(newhash, oldhash, 20) != 0)) {
808
- client->context->writeCommand(client->context->db->selected_database, client->argc, client->argv, client->argvlen);
842
+ client->context->writeCommand(rl_get_selected_db(client->context->db), client->argc, client->argv, client->argvlen);
809
843
  }
810
844
  }
811
845
  rl_free(oldhash);
@@ -817,7 +851,7 @@ static void execCommand(rliteClient *c) {
817
851
  if (written) {
818
852
  char *argv[] = {"exec"};
819
853
  size_t argvlen[] = {4};
820
- c->context->writeCommand(c->context->db->selected_database, 1, argv, argvlen);
854
+ c->context->writeCommand(rl_get_selected_db(c->context->db), 1, argv, argvlen);
821
855
  }
822
856
 
823
857
  retval = rl_commit(c->context->db);
@@ -888,6 +922,18 @@ static void unwatchCommand(rliteClient *c) {
888
922
  c->reply = createStatusObject(RLITE_STR_OK);
889
923
  }
890
924
 
925
+ static rliteReply *pollToReply(long elementc, unsigned char **elements, long *elementslen) {
926
+ long i;
927
+ rliteReply *reply = createArrayObject(elementc);
928
+ for (i = 0; i < elementc; i++) {
929
+ reply->element[i] = createStringObject((char *)elements[i], elementslen[i]);
930
+ rl_free(elements[i]);
931
+ }
932
+ rl_free(elements);
933
+ rl_free(elementslen);
934
+ return reply;
935
+ }
936
+
891
937
  static void *_popReply(rliteContext *c) {
892
938
  if (c->replyPosition < c->replyLength) {
893
939
  void *ret;
@@ -897,6 +943,18 @@ static void *_popReply(rliteContext *c) {
897
943
  c->replyPosition = c->replyLength = 0;
898
944
  }
899
945
  return ret;
946
+ } else if (c->replyPosition == c->replyLength && c->db->subscriber_id) {
947
+ int elementc;
948
+ unsigned char **elements;
949
+ long *elementslen;
950
+ int retval = rl_poll_wait(c->db, &elementc, &elements, &elementslen, NULL);
951
+ if (retval == RL_NOT_FOUND) {
952
+ return createReplyObject(RLITE_REPLY_NIL);
953
+ } else if (retval == RL_OK) {
954
+ return pollToReply(elementc, elements, elementslen);
955
+ } else {
956
+ return createErrorObject("unknown retval");
957
+ }
900
958
  } else {
901
959
  return NULL;
902
960
  }
@@ -931,6 +989,8 @@ int rliteAppendCommandClient(rliteClient *client) {
931
989
  retval = addReplyErrorFormat(client->context, "wrong number of arguments for '%s' command", command->name);
932
990
  flagTransactions(client);
933
991
  } else {
992
+ RL_CALL(refresh_rlite_fp, RL_OK, client->context);
993
+
934
994
  if (client->context->inTransaction && (command->proc != execCommand && command->proc != discardCommand &&
935
995
  command->proc != multiCommand && command->proc != watchCommand)) {
936
996
  if (client->context->enqueuedCommandsLength == client->context->enqueuedCommandsAlloc) {
@@ -984,7 +1044,7 @@ int rliteAppendCommandClient(rliteClient *client) {
984
1044
  if (client->context->writeCommand) {
985
1045
  RL_CALL(rl_dirty_hash, RL_OK, client->context->db, &newhash);
986
1046
  if (newhash && (!oldhash || memcmp(newhash, oldhash, 20) != 0)) {
987
- client->context->writeCommand(client->context->db->selected_database, client->argc, client->argv, client->argvlen);
1047
+ client->context->writeCommand(rl_get_selected_db(client->context->db), client->argc, client->argv, client->argvlen);
988
1048
  }
989
1049
  }
990
1050
  RL_CALL(rl_commit, RL_OK, client->context->db);
@@ -3819,6 +3879,185 @@ cleanup:
3819
3879
  free(getvlen);
3820
3880
  }
3821
3881
 
3882
+ static void pubsubVarargCommandProcessed(rliteClient *c, const char *type, int argc, unsigned char **args, long *argslen, int func(rlite *db, int argc, unsigned char **argv, long *argvlen)) {
3883
+ int i, retval;
3884
+ retval = func(c->context->db, argc, args, argslen);
3885
+ RLITE_SERVER_ERR(c, retval);
3886
+
3887
+ long count = 0;
3888
+ int subscribing = !strcasecmp(type, "subscribe") || !strcasecmp(type, "psubscribe");
3889
+ rl_pubsub_count_subscriptions(c->context->db, &count);
3890
+ for (i = 0; i < argc; i++) {
3891
+ rliteReply *reply = createArrayObject(3);;
3892
+ if (reply) {
3893
+ reply->element[0] = createCStringObject(type);
3894
+ reply->element[1] = createStringObject((char *)args[i], argslen[i]);
3895
+ // TODO: count might be off if a clients connects to the same channel multiple times
3896
+ reply->element[2] = createLongLongObject(subscribing ? (count - argc + i + 1) : (count + argc - i - 1));
3897
+ addReply(c->context, reply);
3898
+ }
3899
+ }
3900
+ retval = RL_OK;
3901
+ cleanup:
3902
+ return;
3903
+ }
3904
+
3905
+ static void pubsubVarargCommand(rliteClient *c, const char *type, int func(rlite *db, int argc, unsigned char **argv, long *argvlen)) {
3906
+ int i = 0, argc = c->argc - 1;
3907
+ unsigned char **args = NULL;
3908
+ long *argslen = NULL;
3909
+
3910
+ args = malloc(sizeof(unsigned char *) * argc);
3911
+ if (!args) {
3912
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3913
+ goto cleanup;
3914
+ }
3915
+ argslen = malloc(sizeof(long) * argc);
3916
+ if (!argslen) {
3917
+ __rliteSetError(c->context, RLITE_ERR_OOM, "Out of memory");
3918
+ goto cleanup;
3919
+ }
3920
+ for (i = 0; i < argc; i++) {
3921
+ args[i] = (unsigned char *)c->argv[1 + i];
3922
+ argslen[i] = (long)c->argvlen[1 + i];
3923
+ }
3924
+ pubsubVarargCommandProcessed(c, type, argc, args, argslen, func);
3925
+ cleanup:
3926
+ rl_free(args);
3927
+ rl_free(argslen);
3928
+ }
3929
+
3930
+ static void subscribeCommand(rliteClient *c) {
3931
+ pubsubVarargCommand(c, "subscribe", rl_subscribe);
3932
+ }
3933
+
3934
+ static void unsubscribeCommand(rliteClient *c) {
3935
+ long i, channelc = 0;
3936
+ unsigned char **channelv = NULL;
3937
+ long *channelvlen = NULL;
3938
+ if (c->argc == 1) {
3939
+ int retval = rl_pubsub_channels(c->context->db, NULL, 0, &channelc, &channelv, &channelvlen);
3940
+ RLITE_SERVER_ERR(c, retval);
3941
+ pubsubVarargCommandProcessed(c, "unsubscribe", channelc, channelv, channelvlen, rl_unsubscribe);
3942
+ } else {
3943
+ pubsubVarargCommand(c, "unsubscribe", rl_unsubscribe);
3944
+ }
3945
+
3946
+ cleanup:
3947
+ for (i = 0; i < channelc; i++) {
3948
+ rl_free(channelv[i]);
3949
+ }
3950
+ rl_free(channelv);
3951
+ rl_free(channelvlen);
3952
+ }
3953
+
3954
+ static void psubscribeCommand(rliteClient *c) {
3955
+ pubsubVarargCommand(c, "psubscribe", rl_psubscribe);
3956
+ }
3957
+
3958
+ static void punsubscribeCommand(rliteClient *c) {
3959
+ long i, patternc = 0;
3960
+ unsigned char **patternv = NULL;
3961
+ long *patternvlen = NULL;
3962
+ if (c->argc == 1) {
3963
+ int retval = rl_pubsub_patterns(c->context->db, &patternc, &patternv, &patternvlen);
3964
+ RLITE_SERVER_ERR(c, retval);
3965
+ pubsubVarargCommandProcessed(c, "punsubscribe", patternc, patternv, patternvlen, rl_punsubscribe);
3966
+ } else {
3967
+ pubsubVarargCommand(c, "punsubscribe", rl_punsubscribe);
3968
+ }
3969
+
3970
+ cleanup:
3971
+ for (i = 0; i < patternc; i++) {
3972
+ rl_free(patternv[i]);
3973
+ }
3974
+ rl_free(patternv);
3975
+ rl_free(patternvlen);
3976
+ }
3977
+
3978
+ static void publishCommand(rliteClient *c) {
3979
+ unsigned char *channel = (unsigned char *)c->argv[1];
3980
+ size_t channellen = c->argvlen[1];
3981
+ char *data = c->argv[2];
3982
+ size_t datalen = c->argvlen[2];
3983
+ long recipients = 0;
3984
+ int retval = rl_publish(c->context->db, channel, channellen, data, datalen, &recipients);
3985
+ RLITE_SERVER_ERR(c, retval);
3986
+ c->reply = createLongLongObject(recipients);
3987
+ cleanup:
3988
+ return;
3989
+ }
3990
+
3991
+ static void pubsubCommand(rliteClient *c) {
3992
+ long i, channelc = 0;
3993
+ unsigned char **channelv = NULL;
3994
+ long *channelvlen = NULL;
3995
+ int retval;
3996
+ if (!strcasecmp(c->argv[1],"channels")) {
3997
+ unsigned char *pattern = NULL;
3998
+ long patternlen = 0;
3999
+ if (c->argc >= 3) {
4000
+ pattern = (unsigned char *)c->argv[2];
4001
+ patternlen = c->argvlen[2];
4002
+ }
4003
+ retval = rl_pubsub_channels(c->context->db, pattern, patternlen, &channelc, &channelv, &channelvlen);
4004
+ RLITE_SERVER_ERR(c, retval);
4005
+ c->reply = createArrayObject(channelc);
4006
+ if (c->reply == NULL) {
4007
+ goto cleanup;
4008
+ }
4009
+ for (i = 0; i < channelc; i++) {
4010
+ c->reply->element[i] = createStringObject((char *)channelv[i], channelvlen[i]);
4011
+ }
4012
+ } else if (!strcasecmp(c->argv[1],"numsub")) {
4013
+ long numsub;
4014
+ retval = rl_pubsub_numsub(c->context->db, c->argc - 2, (unsigned char **)&c->argv[2], (long *)&c->argvlen[2], &numsub);
4015
+ c->reply = createLongLongObject(numsub);
4016
+ } else if (!strcasecmp(c->argv[1],"numpat")) {
4017
+ long numpat;
4018
+ retval = rl_pubsub_numpat(c->context->db, &numpat);
4019
+ c->reply = createLongLongObject(numpat);
4020
+ }
4021
+ cleanup:
4022
+ for (i = 0; i < channelc; i++) {
4023
+ rl_free(channelv[i]);
4024
+ }
4025
+ rl_free(channelv);
4026
+ rl_free(channelvlen);
4027
+ return;
4028
+ }
4029
+
4030
+ void pubsubPollCommand(rliteClient *c) {
4031
+ int retval;
4032
+ int elementc;
4033
+ unsigned char **elements;
4034
+ long *elementslen;
4035
+ if (c->argc >= 2) {
4036
+ long timeout_param;
4037
+ struct timeval timeout;
4038
+ if ((getLongFromObjectOrReply(c, c->argv[1], c->argvlen[1], &timeout_param, NULL) != RLITE_OK)) {
4039
+ return;
4040
+ }
4041
+ if (timeout_param != 0) {
4042
+ timeout.tv_sec = 0;
4043
+ timeout.tv_usec = timeout_param;
4044
+ }
4045
+ retval = rl_poll_wait(c->context->db, &elementc, &elements, &elementslen, timeout_param == 0 ? NULL : &timeout);
4046
+ } else {
4047
+ retval = rl_poll(c->context->db, &elementc, &elements, &elementslen);
4048
+ }
4049
+ RLITE_SERVER_ERR(c, retval);
4050
+ if (retval == RL_NOT_FOUND) {
4051
+ c->reply = createReplyObject(RLITE_REPLY_NIL);
4052
+ } else if (retval == RL_OK) {
4053
+ c->reply = pollToReply(elementc, elements, elementslen);
4054
+ } else {
4055
+ addReplyErrorFormat(c->context, "unknown retval %d", retval);
4056
+ }
4057
+ cleanup:
4058
+ return;
4059
+ }
4060
+
3822
4061
  static struct rliteCommand rliteCommandTable[] = {
3823
4062
  {"get",getCommand,2,"rF",0,1,1,1,0,0},
3824
4063
  {"set",setCommand,-3,"wm",0,1,1,1,0,0},
@@ -3949,12 +4188,13 @@ static struct rliteCommand rliteCommandTable[] = {
3949
4188
  // {"role",roleCommand,1,"last",0,NULL,0,0,0,0,0},
3950
4189
  {"debug",debugCommand,-2,"as",0,0,0,0,0,0},
3951
4190
  // {"config",configCommand,-2,"art",0,NULL,0,0,0,0,0},
3952
- // {"subscribe",subscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0},
3953
- // {"unsubscribe",unsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0},
3954
- // {"psubscribe",psubscribeCommand,-2,"rpslt",0,NULL,0,0,0,0,0},
3955
- // {"punsubscribe",punsubscribeCommand,-1,"rpslt",0,NULL,0,0,0,0,0},
3956
- // {"publish",publishCommand,3,"pltrF",0,NULL,0,0,0,0,0},
3957
- // {"pubsub",pubsubCommand,-2,"pltrR",0,NULL,0,0,0,0,0},
4191
+ {"subscribe",subscribeCommand,-2,"rpslt",0,0,0,0,0,0},
4192
+ {"unsubscribe",unsubscribeCommand,-1,"rpslt",0,0,0,0,0,0},
4193
+ {"psubscribe",psubscribeCommand,-2,"rpslt",0,0,0,0,0,0},
4194
+ {"punsubscribe",punsubscribeCommand,-1,"rpslt",0,0,0,0,0,0},
4195
+ {"publish",publishCommand,3,"pltrF",0,0,0,0,0,0},
4196
+ {"pubsub",pubsubCommand,-2,"pltrR",0,0,0,0,0,0},
4197
+ {"__rlite_poll",pubsubPollCommand,-1,"pltrR",0,0,0,0,0,0},
3958
4198
  {"watch",watchCommand,-2,"rsF",0,1,-1,1,0,0},
3959
4199
  {"unwatch",unwatchCommand,1,"rsF",0,0,0,0,0,0},
3960
4200
  // {"cluster",clusterCommand,-2,"ar",0,NULL,0,0,0,0,0},