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
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},