vincentchu-handlersocket 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (135) hide show
  1. data/ext/HandlerSocket-Plugin-for-MySQL/AUTHORS +22 -0
  2. data/ext/HandlerSocket-Plugin-for-MySQL/COPYING +30 -0
  3. data/ext/HandlerSocket-Plugin-for-MySQL/ChangeLog +12 -0
  4. data/ext/HandlerSocket-Plugin-for-MySQL/Makefile.am +87 -0
  5. data/ext/HandlerSocket-Plugin-for-MySQL/README +78 -0
  6. data/ext/HandlerSocket-Plugin-for-MySQL/autogen.sh +117 -0
  7. data/ext/HandlerSocket-Plugin-for-MySQL/client/Makefile.am +24 -0
  8. data/ext/HandlerSocket-Plugin-for-MySQL/client/hsclient.cpp +88 -0
  9. data/ext/HandlerSocket-Plugin-for-MySQL/client/hslongrun.cpp +1041 -0
  10. data/ext/HandlerSocket-Plugin-for-MySQL/client/hspool_test.pl +224 -0
  11. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest.cpp +1532 -0
  12. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest.pl +228 -0
  13. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_hs.sh +4 -0
  14. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_hs_more50.sh +4 -0
  15. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_md.sh +7 -0
  16. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_my.sh +3 -0
  17. data/ext/HandlerSocket-Plugin-for-MySQL/client/hstest_my_more50.sh +3 -0
  18. data/ext/HandlerSocket-Plugin-for-MySQL/configure.ac +144 -0
  19. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/about-handlersocket.en.txt +72 -0
  20. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/configuration-options.en.txt +99 -0
  21. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/installation.en.txt +92 -0
  22. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/perl-client.en.txt +135 -0
  23. data/ext/HandlerSocket-Plugin-for-MySQL/docs-en/protocol.en.txt +205 -0
  24. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/about-handlersocket.ja.txt +51 -0
  25. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/installation.ja.txt +88 -0
  26. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/perl-client.ja.txt +127 -0
  27. data/ext/HandlerSocket-Plugin-for-MySQL/docs-ja/protocol.ja.txt +180 -0
  28. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/COPYRIGHT.txt +27 -0
  29. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.am +10 -0
  30. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/Makefile.plain.template +31 -0
  31. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/database.cpp +1190 -0
  32. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/database.hpp +142 -0
  33. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.cpp +222 -0
  34. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/handlersocket.spec.template +29 -0
  35. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr.cpp +149 -0
  36. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr.hpp +58 -0
  37. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr_worker.cpp +951 -0
  38. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/hstcpsvr_worker.hpp +35 -0
  39. data/ext/HandlerSocket-Plugin-for-MySQL/handlersocket/mysql_incl.hpp +50 -0
  40. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/COPYRIGHT.txt +27 -0
  41. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/Makefile.am +12 -0
  42. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/Makefile.plain +27 -0
  43. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/allocator.hpp +64 -0
  44. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/auto_addrinfo.hpp +49 -0
  45. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/auto_file.hpp +64 -0
  46. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/auto_ptrcontainer.hpp +67 -0
  47. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/config.cpp +67 -0
  48. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/config.hpp +32 -0
  49. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/escape.cpp +127 -0
  50. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/escape.hpp +66 -0
  51. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/fatal.cpp +36 -0
  52. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/fatal.hpp +22 -0
  53. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/hstcpcli.cpp +441 -0
  54. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/hstcpcli.hpp +62 -0
  55. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/libhsclient.spec.template +39 -0
  56. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/mutex.hpp +51 -0
  57. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/socket.cpp +186 -0
  58. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/socket.hpp +51 -0
  59. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_buffer.hpp +118 -0
  60. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_ref.hpp +63 -0
  61. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_util.cpp +182 -0
  62. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/string_util.hpp +53 -0
  63. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/thread.hpp +84 -0
  64. data/ext/HandlerSocket-Plugin-for-MySQL/libhsclient/util.hpp +25 -0
  65. data/ext/HandlerSocket-Plugin-for-MySQL/misc/microbench-hs.log +130 -0
  66. data/ext/HandlerSocket-Plugin-for-MySQL/misc/microbench-my.log +125 -0
  67. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/COPYRIGHT.txt +27 -0
  68. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/Changes +6 -0
  69. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/HandlerSocket.xs +632 -0
  70. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/MANIFEST +8 -0
  71. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/Makefile.PL +18 -0
  72. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/Makefile.PL.installed +20 -0
  73. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/README +30 -0
  74. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/lib/Net/HandlerSocket.pm +68 -0
  75. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/lib/Net/HandlerSocket/Pool.pm +362 -0
  76. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/perl-Net-HandlerSocket.spec.template +127 -0
  77. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/ppport.h +6375 -0
  78. data/ext/HandlerSocket-Plugin-for-MySQL/perl-Net-HandlerSocket/t/Net-HandlerSocket.t +15 -0
  79. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/Makefile +79 -0
  80. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/common/binary_my.cnf +4 -0
  81. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/common/compat.sh +29 -0
  82. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/common/hstest.pm +66 -0
  83. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/Makefile +4 -0
  84. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/run.sh +27 -0
  85. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test01.expected +100 -0
  86. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test01.pl +38 -0
  87. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test02.expected +100 -0
  88. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test02.pl +49 -0
  89. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test03.expected +771 -0
  90. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test03.pl +61 -0
  91. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test04.expected +0 -0
  92. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test04.pl +63 -0
  93. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test05.expected +771 -0
  94. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test05.pl +59 -0
  95. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test06.expected +644 -0
  96. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test06.pl +90 -0
  97. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test07.expected +304 -0
  98. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test07.pl +98 -0
  99. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test08.expected +2 -0
  100. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test08.pl +48 -0
  101. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test09.expected +12 -0
  102. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test09.pl +67 -0
  103. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test10.expected +771 -0
  104. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test10.pl +93 -0
  105. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test11.expected +37 -0
  106. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test11.pl +112 -0
  107. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test12.expected +273 -0
  108. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test12.pl +134 -0
  109. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test13.expected +92 -0
  110. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test13.pl +92 -0
  111. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test14.expected +144 -0
  112. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test14.pl +80 -0
  113. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test15.expected +764 -0
  114. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test15.pl +114 -0
  115. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test16.expected +66 -0
  116. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test16.pl +88 -0
  117. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test17.expected +0 -0
  118. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test17.pl +125 -0
  119. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test18.expected +22 -0
  120. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test18.pl +63 -0
  121. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test19.expected +14894 -0
  122. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test19.pl +190 -0
  123. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test20.expected +2 -0
  124. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test20.pl +33 -0
  125. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test21.expected +11 -0
  126. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test21.pl +58 -0
  127. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test22.expected +9 -0
  128. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test22.pl +61 -0
  129. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test23.expected +101 -0
  130. data/ext/HandlerSocket-Plugin-for-MySQL/regtest/test_01_lib/test23.pl +53 -0
  131. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/README +33 -0
  132. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/extconf.rb +27 -0
  133. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/handlersocket.cpp +437 -0
  134. data/ext/winebarrel-ruby-handlersocket-c19841e47ea2/handlersocket.h +32 -0
  135. metadata +200 -0
@@ -0,0 +1,58 @@
1
+
2
+ // vim:sw=2:ai
3
+
4
+ /*
5
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
6
+ * See COPYRIGHT.txt for details.
7
+ */
8
+
9
+ #ifndef DENA_HSTCPSVR_HPP
10
+ #define DENA_HSTCPSVR_HPP
11
+
12
+ #include <memory>
13
+ #include <string>
14
+ #include <map>
15
+
16
+ #include "mutex.hpp"
17
+ #include "auto_file.hpp"
18
+ #include "database.hpp"
19
+ #include "config.hpp"
20
+ #include "socket.hpp"
21
+
22
+ namespace dena {
23
+
24
+ struct hstcpsvr_shared_c {
25
+ config conf;
26
+ long num_threads;
27
+ long nb_conn_per_thread;
28
+ bool for_write_flag;
29
+ bool require_auth;
30
+ std::string plain_secret;
31
+ int readsize;
32
+ socket_args sockargs;
33
+ auto_file listen_fd;
34
+ database_ptr dbptr;
35
+ volatile unsigned int *thread_num_conns; /* 0 .. num_threads-1 */
36
+ hstcpsvr_shared_c() : num_threads(0), nb_conn_per_thread(100),
37
+ for_write_flag(false), require_auth(false), readsize(0),
38
+ thread_num_conns(0) { }
39
+ };
40
+
41
+ struct hstcpsvr_shared_v : public mutex {
42
+ int shutdown;
43
+ hstcpsvr_shared_v() : shutdown(0) { }
44
+ };
45
+
46
+ struct hstcpsvr_i;
47
+ typedef std::auto_ptr<hstcpsvr_i> hstcpsvr_ptr;
48
+
49
+ struct hstcpsvr_i {
50
+ virtual ~hstcpsvr_i() { }
51
+ virtual std::string start_listen() = 0;
52
+ static hstcpsvr_ptr create(const config& conf);
53
+ };
54
+
55
+ };
56
+
57
+ #endif
58
+
@@ -0,0 +1,951 @@
1
+
2
+ // vim:sw=2:ai
3
+
4
+ /*
5
+ * Copyright (C) 2010 DeNA Co.,Ltd.. All rights reserved.
6
+ * See COPYRIGHT.txt for details.
7
+ */
8
+
9
+ #include <netinet/in.h>
10
+ #include <errno.h>
11
+ #include <poll.h>
12
+ #include <unistd.h>
13
+ #include <fcntl.h>
14
+ #include <stdexcept>
15
+ #include <signal.h>
16
+ #include <list>
17
+ #if __linux__
18
+ #include <sys/epoll.h>
19
+ #endif
20
+
21
+ #include "hstcpsvr_worker.hpp"
22
+ #include "string_buffer.hpp"
23
+ #include "auto_ptrcontainer.hpp"
24
+ #include "string_util.hpp"
25
+ #include "escape.hpp"
26
+
27
+ #define DBG_FD(x)
28
+ #define DBG_TR(x)
29
+ #define DBG_EP(x)
30
+ #define DBG_MULTI(x)
31
+
32
+ /* TODO */
33
+ #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(MSG_NOSIGNAL)
34
+ #define MSG_NOSIGNAL 0
35
+ #endif
36
+
37
+ namespace dena {
38
+
39
+ struct dbconnstate {
40
+ string_buffer readbuf;
41
+ string_buffer writebuf;
42
+ std::vector<prep_stmt> prep_stmts;
43
+ size_t resp_begin_pos;
44
+ size_t find_nl_pos;
45
+ void reset() {
46
+ readbuf.clear();
47
+ writebuf.clear();
48
+ prep_stmts.clear();
49
+ resp_begin_pos = 0;
50
+ find_nl_pos = 0;
51
+ }
52
+ dbconnstate() : resp_begin_pos(0), find_nl_pos(0) { }
53
+ };
54
+
55
+ struct hstcpsvr_conn;
56
+ typedef auto_ptrcontainer< std::list<hstcpsvr_conn *> > hstcpsvr_conns_type;
57
+
58
+ struct hstcpsvr_conn : public dbcallback_i {
59
+ public:
60
+ auto_file fd;
61
+ sockaddr_storage addr;
62
+ socklen_t addr_len;
63
+ dbconnstate cstate;
64
+ std::string err;
65
+ size_t readsize;
66
+ bool nonblocking;
67
+ bool read_finished;
68
+ bool write_finished;
69
+ time_t nb_last_io;
70
+ hstcpsvr_conns_type::iterator conns_iter;
71
+ bool authorized;
72
+ public:
73
+ bool closed() const;
74
+ bool ok_to_close() const;
75
+ void reset();
76
+ int accept(const hstcpsvr_shared_c& cshared);
77
+ bool write_more(bool *more_r = 0);
78
+ bool read_more(bool *more_r = 0);
79
+ public:
80
+ virtual void dbcb_set_prep_stmt(size_t pst_id, const prep_stmt& v);
81
+ virtual const prep_stmt *dbcb_get_prep_stmt(size_t pst_id) const;
82
+ virtual void dbcb_resp_short(uint32_t code, const char *msg);
83
+ virtual void dbcb_resp_short_num(uint32_t code, uint32_t value);
84
+ virtual void dbcb_resp_short_num64(uint32_t code, uint64_t value);
85
+ virtual void dbcb_resp_begin(size_t num_flds);
86
+ virtual void dbcb_resp_entry(const char *fld, size_t fldlen);
87
+ virtual void dbcb_resp_end();
88
+ virtual void dbcb_resp_cancel();
89
+ public:
90
+ hstcpsvr_conn() : addr_len(sizeof(addr)), readsize(4096),
91
+ nonblocking(false), read_finished(false), write_finished(false),
92
+ nb_last_io(0), authorized(false) { }
93
+ };
94
+
95
+ bool
96
+ hstcpsvr_conn::closed() const
97
+ {
98
+ return fd.get() < 0;
99
+ }
100
+
101
+ bool
102
+ hstcpsvr_conn::ok_to_close() const
103
+ {
104
+ return write_finished || (read_finished && cstate.writebuf.size() == 0);
105
+ }
106
+
107
+ void
108
+ hstcpsvr_conn::reset()
109
+ {
110
+ addr = sockaddr_storage();
111
+ addr_len = sizeof(addr);
112
+ cstate.reset();
113
+ fd.reset();
114
+ read_finished = false;
115
+ write_finished = false;
116
+ }
117
+
118
+ int
119
+ hstcpsvr_conn::accept(const hstcpsvr_shared_c& cshared)
120
+ {
121
+ reset();
122
+ return socket_accept(cshared.listen_fd.get(), fd, cshared.sockargs, addr,
123
+ addr_len, err);
124
+ }
125
+
126
+ bool
127
+ hstcpsvr_conn::write_more(bool *more_r)
128
+ {
129
+ if (write_finished || cstate.writebuf.size() == 0) {
130
+ return false;
131
+ }
132
+ const size_t wlen = cstate.writebuf.size();
133
+ ssize_t len = send(fd.get(), cstate.writebuf.begin(), wlen, MSG_NOSIGNAL);
134
+ if (len <= 0) {
135
+ if (len == 0 || !nonblocking || errno != EWOULDBLOCK) {
136
+ cstate.writebuf.clear();
137
+ write_finished = true;
138
+ }
139
+ return false;
140
+ }
141
+ cstate.writebuf.erase_front(len);
142
+ /* FIXME: reallocate memory if too large */
143
+ if (more_r) {
144
+ *more_r = (static_cast<size_t>(len) == wlen);
145
+ }
146
+ return true;
147
+ }
148
+
149
+ bool
150
+ hstcpsvr_conn::read_more(bool *more_r)
151
+ {
152
+ if (read_finished) {
153
+ return false;
154
+ }
155
+ const size_t block_size = readsize > 4096 ? readsize : 4096;
156
+ char *wp = cstate.readbuf.make_space(block_size);
157
+ const ssize_t len = read(fd.get(), wp, block_size);
158
+ if (len <= 0) {
159
+ if (len == 0 || !nonblocking || errno != EWOULDBLOCK) {
160
+ read_finished = true;
161
+ }
162
+ return false;
163
+ }
164
+ cstate.readbuf.space_wrote(len);
165
+ if (more_r) {
166
+ *more_r = (static_cast<size_t>(len) == block_size);
167
+ }
168
+ return true;
169
+ }
170
+
171
+ void
172
+ hstcpsvr_conn::dbcb_set_prep_stmt(size_t pst_id, const prep_stmt& v)
173
+ {
174
+ if (cstate.prep_stmts.size() <= pst_id) {
175
+ cstate.prep_stmts.resize(pst_id + 1);
176
+ }
177
+ cstate.prep_stmts[pst_id] = v;
178
+ }
179
+
180
+ const prep_stmt *
181
+ hstcpsvr_conn::dbcb_get_prep_stmt(size_t pst_id) const
182
+ {
183
+ if (cstate.prep_stmts.size() <= pst_id) {
184
+ return 0;
185
+ }
186
+ return &cstate.prep_stmts[pst_id];
187
+ }
188
+
189
+ void
190
+ hstcpsvr_conn::dbcb_resp_short(uint32_t code, const char *msg)
191
+ {
192
+ write_ui32(cstate.writebuf, code);
193
+ const size_t msglen = strlen(msg);
194
+ if (msglen != 0) {
195
+ cstate.writebuf.append_literal("\t1\t");
196
+ cstate.writebuf.append(msg, msg + msglen);
197
+ } else {
198
+ cstate.writebuf.append_literal("\t1");
199
+ }
200
+ cstate.writebuf.append_literal("\n");
201
+ }
202
+
203
+ void
204
+ hstcpsvr_conn::dbcb_resp_short_num(uint32_t code, uint32_t value)
205
+ {
206
+ write_ui32(cstate.writebuf, code);
207
+ cstate.writebuf.append_literal("\t1\t");
208
+ write_ui32(cstate.writebuf, value);
209
+ cstate.writebuf.append_literal("\n");
210
+ }
211
+
212
+ void
213
+ hstcpsvr_conn::dbcb_resp_short_num64(uint32_t code, uint64_t value)
214
+ {
215
+ write_ui32(cstate.writebuf, code);
216
+ cstate.writebuf.append_literal("\t1\t");
217
+ write_ui64(cstate.writebuf, value);
218
+ cstate.writebuf.append_literal("\n");
219
+ }
220
+
221
+ void
222
+ hstcpsvr_conn::dbcb_resp_begin(size_t num_flds)
223
+ {
224
+ cstate.resp_begin_pos = cstate.writebuf.size();
225
+ cstate.writebuf.append_literal("0\t");
226
+ write_ui32(cstate.writebuf, num_flds);
227
+ }
228
+
229
+ void
230
+ hstcpsvr_conn::dbcb_resp_entry(const char *fld, size_t fldlen)
231
+ {
232
+ if (fld != 0) {
233
+ cstate.writebuf.append_literal("\t");
234
+ escape_string(cstate.writebuf, fld, fld + fldlen);
235
+ } else {
236
+ static const char t[] = "\t\0";
237
+ cstate.writebuf.append(t, t + 2);
238
+ }
239
+ }
240
+
241
+ void
242
+ hstcpsvr_conn::dbcb_resp_end()
243
+ {
244
+ cstate.writebuf.append_literal("\n");
245
+ cstate.resp_begin_pos = 0;
246
+ }
247
+
248
+ void
249
+ hstcpsvr_conn::dbcb_resp_cancel()
250
+ {
251
+ cstate.writebuf.resize(cstate.resp_begin_pos);
252
+ cstate.resp_begin_pos = 0;
253
+ }
254
+
255
+ struct hstcpsvr_worker : public hstcpsvr_worker_i, private noncopyable {
256
+ hstcpsvr_worker(const hstcpsvr_worker_arg& arg);
257
+ virtual void run();
258
+ private:
259
+ const hstcpsvr_shared_c& cshared;
260
+ volatile hstcpsvr_shared_v& vshared;
261
+ long worker_id;
262
+ dbcontext_ptr dbctx;
263
+ hstcpsvr_conns_type conns; /* conns refs dbctx */
264
+ time_t last_check_time;
265
+ std::vector<pollfd> pfds;
266
+ #ifdef __linux__
267
+ std::vector<epoll_event> events_vec;
268
+ auto_file epoll_fd;
269
+ #endif
270
+ bool accept_enabled;
271
+ int accept_balance;
272
+ std::vector<string_ref> invalues_work;
273
+ std::vector<record_filter> filters_work;
274
+ private:
275
+ int run_one_nb();
276
+ int run_one_ep();
277
+ void execute_lines(hstcpsvr_conn& conn);
278
+ void execute_line(char *start, char *finish, hstcpsvr_conn& conn);
279
+ void do_open_index(char *start, char *finish, hstcpsvr_conn& conn);
280
+ void do_exec_on_index(char *cmd_begin, char *cmd_end, char *start,
281
+ char *finish, hstcpsvr_conn& conn);
282
+ void do_authorization(char *start, char *finish, hstcpsvr_conn& conn);
283
+ };
284
+
285
+ hstcpsvr_worker::hstcpsvr_worker(const hstcpsvr_worker_arg& arg)
286
+ : cshared(*arg.cshared), vshared(*arg.vshared), worker_id(arg.worker_id),
287
+ dbctx(cshared.dbptr->create_context(cshared.for_write_flag)),
288
+ last_check_time(time(0)), accept_enabled(true), accept_balance(0)
289
+ {
290
+ #ifdef __linux__
291
+ if (cshared.sockargs.use_epoll) {
292
+ epoll_fd.reset(epoll_create(10));
293
+ if (epoll_fd.get() < 0) {
294
+ fatal_abort("epoll_create");
295
+ }
296
+ epoll_event ev = { };
297
+ ev.events = EPOLLIN;
298
+ ev.data.ptr = 0;
299
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, cshared.listen_fd.get(), &ev)
300
+ != 0) {
301
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
302
+ }
303
+ events_vec.resize(10240);
304
+ }
305
+ #endif
306
+ accept_balance = cshared.conf.get_int("accept_balance", 0);
307
+ }
308
+
309
+ namespace {
310
+
311
+ struct thr_init {
312
+ thr_init(const dbcontext_ptr& dc, volatile int& shutdown_flag) : dbctx(dc) {
313
+ dbctx->init_thread(this, shutdown_flag);
314
+ }
315
+ ~thr_init() {
316
+ dbctx->term_thread();
317
+ }
318
+ const dbcontext_ptr& dbctx;
319
+ };
320
+
321
+ }; // namespace
322
+
323
+ void
324
+ hstcpsvr_worker::run()
325
+ {
326
+ thr_init initobj(dbctx, vshared.shutdown);
327
+
328
+ #ifdef __linux__
329
+ if (cshared.sockargs.use_epoll) {
330
+ while (!vshared.shutdown && dbctx->check_alive()) {
331
+ run_one_ep();
332
+ }
333
+ } else if (cshared.sockargs.nonblocking) {
334
+ while (!vshared.shutdown && dbctx->check_alive()) {
335
+ run_one_nb();
336
+ }
337
+ } else {
338
+ /* UNUSED */
339
+ fatal_abort("run_one");
340
+ }
341
+ #else
342
+ while (!vshared.shutdown && dbctx->check_alive()) {
343
+ run_one_nb();
344
+ }
345
+ #endif
346
+ }
347
+
348
+ int
349
+ hstcpsvr_worker::run_one_nb()
350
+ {
351
+ size_t nfds = 0;
352
+ /* CLIENT SOCKETS */
353
+ for (hstcpsvr_conns_type::const_iterator i = conns.begin();
354
+ i != conns.end(); ++i) {
355
+ if (pfds.size() <= nfds) {
356
+ pfds.resize(nfds + 1);
357
+ }
358
+ pollfd& pfd = pfds[nfds++];
359
+ pfd.fd = (*i)->fd.get();
360
+ short ev = 0;
361
+ if ((*i)->cstate.writebuf.size() != 0) {
362
+ ev = POLLOUT;
363
+ } else {
364
+ ev = POLLIN;
365
+ }
366
+ pfd.events = pfd.revents = ev;
367
+ }
368
+ /* LISTENER */
369
+ {
370
+ const size_t cpt = cshared.nb_conn_per_thread;
371
+ const short ev = (cpt > nfds) ? POLLIN : 0;
372
+ if (pfds.size() <= nfds) {
373
+ pfds.resize(nfds + 1);
374
+ }
375
+ pollfd& pfd = pfds[nfds++];
376
+ pfd.fd = cshared.listen_fd.get();
377
+ pfd.events = pfd.revents = ev;
378
+ }
379
+ /* POLL */
380
+ const int npollev = poll(&pfds[0], nfds, 1 * 1000);
381
+ dbctx->set_statistics(conns.size(), npollev);
382
+ const time_t now = time(0);
383
+ size_t j = 0;
384
+ const short mask_in = ~POLLOUT;
385
+ const short mask_out = POLLOUT | POLLERR | POLLHUP | POLLNVAL;
386
+ /* READ */
387
+ for (hstcpsvr_conns_type::iterator i = conns.begin(); i != conns.end();
388
+ ++i, ++j) {
389
+ pollfd& pfd = pfds[j];
390
+ if ((pfd.revents & mask_in) == 0) {
391
+ continue;
392
+ }
393
+ hstcpsvr_conn& conn = **i;
394
+ if (conn.read_more()) {
395
+ if (conn.cstate.readbuf.size() > 0) {
396
+ const char ch = conn.cstate.readbuf.begin()[0];
397
+ if (ch == 'Q') {
398
+ vshared.shutdown = 1;
399
+ } else if (ch == '/') {
400
+ conn.cstate.readbuf.clear();
401
+ conn.cstate.find_nl_pos = 0;
402
+ conn.cstate.writebuf.clear();
403
+ conn.read_finished = true;
404
+ conn.write_finished = true;
405
+ }
406
+ }
407
+ conn.nb_last_io = now;
408
+ }
409
+ }
410
+ /* EXECUTE */
411
+ j = 0;
412
+ for (hstcpsvr_conns_type::iterator i = conns.begin(); i != conns.end();
413
+ ++i, ++j) {
414
+ pollfd& pfd = pfds[j];
415
+ if ((pfd.revents & mask_in) == 0 || (*i)->cstate.readbuf.size() == 0) {
416
+ continue;
417
+ }
418
+ execute_lines(**i);
419
+ }
420
+ /* COMMIT */
421
+ dbctx->unlock_tables_if();
422
+ const bool commit_error = dbctx->get_commit_error();
423
+ dbctx->clear_error();
424
+ /* WRITE/CLOSE */
425
+ j = 0;
426
+ for (hstcpsvr_conns_type::iterator i = conns.begin(); i != conns.end();
427
+ ++j) {
428
+ pollfd& pfd = pfds[j];
429
+ hstcpsvr_conn& conn = **i;
430
+ hstcpsvr_conns_type::iterator icur = i;
431
+ ++i;
432
+ if (commit_error) {
433
+ conn.reset();
434
+ continue;
435
+ }
436
+ if ((pfd.revents & (mask_out | mask_in)) != 0) {
437
+ if (conn.write_more()) {
438
+ conn.nb_last_io = now;
439
+ }
440
+ }
441
+ if (cshared.sockargs.timeout != 0 &&
442
+ conn.nb_last_io + cshared.sockargs.timeout < now) {
443
+ conn.reset();
444
+ }
445
+ if (conn.closed() || conn.ok_to_close()) {
446
+ conns.erase_ptr(icur);
447
+ }
448
+ }
449
+ /* ACCEPT */
450
+ {
451
+ pollfd& pfd = pfds[nfds - 1];
452
+ if ((pfd.revents & mask_in) != 0) {
453
+ std::auto_ptr<hstcpsvr_conn> c(new hstcpsvr_conn());
454
+ c->nonblocking = true;
455
+ c->readsize = cshared.readsize;
456
+ c->accept(cshared);
457
+ if (c->fd.get() >= 0) {
458
+ if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) {
459
+ fatal_abort("F_SETFL O_NONBLOCK");
460
+ }
461
+ c->nb_last_io = now;
462
+ conns.push_back_ptr(c);
463
+ } else {
464
+ /* errno == 11 (EAGAIN) is not a fatal error. */
465
+ DENA_VERBOSE(100, fprintf(stderr,
466
+ "accept failed: errno=%d (not fatal)\n", errno));
467
+ }
468
+ }
469
+ }
470
+ DENA_VERBOSE(30, fprintf(stderr, "nb: %p nfds=%zu cns=%zu\n", this, nfds,
471
+ conns.size()));
472
+ if (conns.empty()) {
473
+ dbctx->close_tables_if();
474
+ }
475
+ dbctx->set_statistics(conns.size(), 0);
476
+ return 0;
477
+ }
478
+
479
+ #ifdef __linux__
480
+ int
481
+ hstcpsvr_worker::run_one_ep()
482
+ {
483
+ epoll_event *const events = &events_vec[0];
484
+ const size_t num_events = events_vec.size();
485
+ const time_t now = time(0);
486
+ size_t in_count = 0, out_count = 0, accept_count = 0;
487
+ int nfds = epoll_wait(epoll_fd.get(), events, num_events, 1000);
488
+ /* READ/ACCEPT */
489
+ dbctx->set_statistics(conns.size(), nfds);
490
+ for (int i = 0; i < nfds; ++i) {
491
+ epoll_event& ev = events[i];
492
+ if ((ev.events & EPOLLIN) == 0) {
493
+ continue;
494
+ }
495
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
496
+ if (conn == 0) {
497
+ /* listener */
498
+ ++accept_count;
499
+ DBG_EP(fprintf(stderr, "IN listener\n"));
500
+ std::auto_ptr<hstcpsvr_conn> c(new hstcpsvr_conn());
501
+ c->nonblocking = true;
502
+ c->readsize = cshared.readsize;
503
+ c->accept(cshared);
504
+ if (c->fd.get() >= 0) {
505
+ if (fcntl(c->fd.get(), F_SETFL, O_NONBLOCK) != 0) {
506
+ fatal_abort("F_SETFL O_NONBLOCK");
507
+ }
508
+ epoll_event cev = { };
509
+ cev.events = EPOLLIN | EPOLLOUT | EPOLLET;
510
+ cev.data.ptr = c.get();
511
+ c->nb_last_io = now;
512
+ const int fd = c->fd.get();
513
+ conns.push_back_ptr(c);
514
+ conns.back()->conns_iter = --conns.end();
515
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, fd, &cev) != 0) {
516
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
517
+ }
518
+ } else {
519
+ DENA_VERBOSE(100, fprintf(stderr,
520
+ "accept failed: errno=%d (not fatal)\n", errno));
521
+ }
522
+ } else {
523
+ /* client connection */
524
+ ++in_count;
525
+ DBG_EP(fprintf(stderr, "IN client\n"));
526
+ bool more_data = false;
527
+ while (conn->read_more(&more_data)) {
528
+ DBG_EP(fprintf(stderr, "IN client read_more\n"));
529
+ conn->nb_last_io = now;
530
+ if (!more_data) {
531
+ break;
532
+ }
533
+ }
534
+ }
535
+ }
536
+ /* EXECUTE */
537
+ for (int i = 0; i < nfds; ++i) {
538
+ epoll_event& ev = events[i];
539
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
540
+ if ((ev.events & EPOLLIN) == 0 || conn == 0 ||
541
+ conn->cstate.readbuf.size() == 0) {
542
+ continue;
543
+ }
544
+ const char ch = conn->cstate.readbuf.begin()[0];
545
+ if (ch == 'Q') {
546
+ vshared.shutdown = 1;
547
+ } else if (ch == '/') {
548
+ conn->cstate.readbuf.clear();
549
+ conn->cstate.find_nl_pos = 0;
550
+ conn->cstate.writebuf.clear();
551
+ conn->read_finished = true;
552
+ conn->write_finished = true;
553
+ } else {
554
+ execute_lines(*conn);
555
+ }
556
+ }
557
+ /* COMMIT */
558
+ dbctx->unlock_tables_if();
559
+ const bool commit_error = dbctx->get_commit_error();
560
+ dbctx->clear_error();
561
+ /* WRITE */
562
+ for (int i = 0; i < nfds; ++i) {
563
+ epoll_event& ev = events[i];
564
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
565
+ if (commit_error && conn != 0) {
566
+ conn->reset();
567
+ continue;
568
+ }
569
+ if ((ev.events & EPOLLOUT) == 0) {
570
+ continue;
571
+ }
572
+ ++out_count;
573
+ if (conn == 0) {
574
+ /* listener */
575
+ DBG_EP(fprintf(stderr, "OUT listener\n"));
576
+ } else {
577
+ /* client connection */
578
+ DBG_EP(fprintf(stderr, "OUT client\n"));
579
+ bool more_data = false;
580
+ while (conn->write_more(&more_data)) {
581
+ DBG_EP(fprintf(stderr, "OUT client write_more\n"));
582
+ conn->nb_last_io = now;
583
+ if (!more_data) {
584
+ break;
585
+ }
586
+ }
587
+ }
588
+ }
589
+ /* CLOSE */
590
+ for (int i = 0; i < nfds; ++i) {
591
+ epoll_event& ev = events[i];
592
+ hstcpsvr_conn *const conn = static_cast<hstcpsvr_conn *>(ev.data.ptr);
593
+ if (conn != 0 && conn->ok_to_close()) {
594
+ DBG_EP(fprintf(stderr, "CLOSE close\n"));
595
+ conns.erase_ptr(conn->conns_iter);
596
+ }
597
+ }
598
+ /* TIMEOUT & cleanup */
599
+ if (last_check_time + 10 < now) {
600
+ for (hstcpsvr_conns_type::iterator i = conns.begin();
601
+ i != conns.end(); ) {
602
+ hstcpsvr_conns_type::iterator icur = i;
603
+ ++i;
604
+ if (cshared.sockargs.timeout != 0 &&
605
+ (*icur)->nb_last_io + cshared.sockargs.timeout < now) {
606
+ conns.erase_ptr((*icur)->conns_iter);
607
+ }
608
+ }
609
+ last_check_time = now;
610
+ DENA_VERBOSE(20, fprintf(stderr, "ep: %p nfds=%d cns=%zu\n", this, nfds,
611
+ conns.size()));
612
+ }
613
+ DENA_VERBOSE(30, fprintf(stderr, "%p in=%zu out=%zu ac=%zu, cns=%zu\n",
614
+ this, in_count, out_count, accept_count, conns.size()));
615
+ if (conns.empty()) {
616
+ dbctx->close_tables_if();
617
+ }
618
+ /* STATISTICS */
619
+ const size_t num_conns = conns.size();
620
+ dbctx->set_statistics(num_conns, 0);
621
+ /* ENABLE/DISABLE ACCEPT */
622
+ if (accept_balance != 0) {
623
+ cshared.thread_num_conns[worker_id] = num_conns;
624
+ size_t total_num_conns = 0;
625
+ for (long i = 0; i < cshared.num_threads; ++i) {
626
+ total_num_conns += cshared.thread_num_conns[i];
627
+ }
628
+ bool e_acc = false;
629
+ if (num_conns < 10 ||
630
+ total_num_conns * 2 > num_conns * cshared.num_threads) {
631
+ e_acc = true;
632
+ }
633
+ epoll_event ev = { };
634
+ ev.events = EPOLLIN;
635
+ ev.data.ptr = 0;
636
+ if (e_acc == accept_enabled) {
637
+ } else if (e_acc) {
638
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_ADD, cshared.listen_fd.get(), &ev)
639
+ != 0) {
640
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
641
+ }
642
+ } else {
643
+ if (epoll_ctl(epoll_fd.get(), EPOLL_CTL_DEL, cshared.listen_fd.get(), &ev)
644
+ != 0) {
645
+ fatal_abort("epoll_ctl EPOLL_CTL_ADD");
646
+ }
647
+ }
648
+ accept_enabled = e_acc;
649
+ }
650
+ return 0;
651
+ }
652
+ #endif
653
+
654
+ void
655
+ hstcpsvr_worker::execute_lines(hstcpsvr_conn& conn)
656
+ {
657
+ DBG_MULTI(int cnt = 0);
658
+ dbconnstate& cstate = conn.cstate;
659
+ char *buf_end = cstate.readbuf.end();
660
+ char *line_begin = cstate.readbuf.begin();
661
+ char *find_pos = line_begin + cstate.find_nl_pos;
662
+ while (true) {
663
+ char *const nl = memchr_char(find_pos, '\n', buf_end - find_pos);
664
+ if (nl == 0) {
665
+ break;
666
+ }
667
+ char *const lf = (line_begin != nl && nl[-1] == '\r') ? nl - 1 : nl;
668
+ DBG_MULTI(cnt++);
669
+ execute_line(line_begin, lf, conn);
670
+ find_pos = line_begin = nl + 1;
671
+ }
672
+ cstate.readbuf.erase_front(line_begin - cstate.readbuf.begin());
673
+ cstate.find_nl_pos = cstate.readbuf.size();
674
+ DBG_MULTI(fprintf(stderr, "cnt=%d\n", cnt));
675
+ }
676
+
677
+ void
678
+ hstcpsvr_worker::execute_line(char *start, char *finish, hstcpsvr_conn& conn)
679
+ {
680
+ /* safe to modify, safe to dereference 'finish' */
681
+ char *const cmd_begin = start;
682
+ read_token(start, finish);
683
+ char *const cmd_end = start;
684
+ skip_one(start, finish);
685
+ if (cmd_begin == cmd_end) {
686
+ return conn.dbcb_resp_short(2, "cmd");
687
+ }
688
+ if (cmd_begin + 1 == cmd_end) {
689
+ if (cmd_begin[0] == 'P') {
690
+ if (cshared.require_auth && !conn.authorized) {
691
+ return conn.dbcb_resp_short(3, "unauth");
692
+ }
693
+ return do_open_index(start, finish, conn);
694
+ }
695
+ if (cmd_begin[0] == 'A') {
696
+ return do_authorization(start, finish, conn);
697
+ }
698
+ }
699
+ if (cmd_begin[0] >= '0' && cmd_begin[0] <= '9') {
700
+ if (cshared.require_auth && !conn.authorized) {
701
+ return conn.dbcb_resp_short(3, "unauth");
702
+ }
703
+ return do_exec_on_index(cmd_begin, cmd_end, start, finish, conn);
704
+ }
705
+ return conn.dbcb_resp_short(2, "cmd");
706
+ }
707
+
708
+ void
709
+ hstcpsvr_worker::do_open_index(char *start, char *finish, hstcpsvr_conn& conn)
710
+ {
711
+ const size_t pst_id = read_ui32(start, finish);
712
+ skip_one(start, finish);
713
+ /* dbname */
714
+ char *const dbname_begin = start;
715
+ read_token(start, finish);
716
+ char *const dbname_end = start;
717
+ skip_one(start, finish);
718
+ /* tblname */
719
+ char *const tblname_begin = start;
720
+ read_token(start, finish);
721
+ char *const tblname_end = start;
722
+ skip_one(start, finish);
723
+ /* idxname */
724
+ char *const idxname_begin = start;
725
+ read_token(start, finish);
726
+ char *const idxname_end = start;
727
+ skip_one(start, finish);
728
+ /* retfields */
729
+ char *const retflds_begin = start;
730
+ read_token(start, finish);
731
+ char *const retflds_end = start;
732
+ skip_one(start, finish);
733
+ /* filfields */
734
+ char *const filflds_begin = start;
735
+ read_token(start, finish);
736
+ char *const filflds_end = start;
737
+ dbname_end[0] = 0;
738
+ tblname_end[0] = 0;
739
+ idxname_end[0] = 0;
740
+ retflds_end[0] = 0;
741
+ filflds_end[0] = 0;
742
+ cmd_open_args args;
743
+ args.pst_id = pst_id;
744
+ args.dbn = dbname_begin;
745
+ args.tbl = tblname_begin;
746
+ args.idx = idxname_begin;
747
+ args.retflds = retflds_begin;
748
+ args.filflds = filflds_begin;
749
+ return dbctx->cmd_open(conn, args);
750
+ }
751
+
752
+ void
753
+ hstcpsvr_worker::do_exec_on_index(char *cmd_begin, char *cmd_end, char *start,
754
+ char *finish, hstcpsvr_conn& conn)
755
+ {
756
+ cmd_exec_args args;
757
+ const size_t pst_id = read_ui32(cmd_begin, cmd_end);
758
+ if (pst_id >= conn.cstate.prep_stmts.size()) {
759
+ return conn.dbcb_resp_short(2, "stmtnum");
760
+ }
761
+ args.pst = &conn.cstate.prep_stmts[pst_id];
762
+ char *const op_begin = start;
763
+ read_token(start, finish);
764
+ char *const op_end = start;
765
+ args.op = string_ref(op_begin, op_end);
766
+ skip_one(start, finish);
767
+ const uint32_t fldnum = read_ui32(start, finish);
768
+ string_ref *const flds = DENA_ALLOCA_ALLOCATE(string_ref, fldnum);
769
+ auto_alloca_free<string_ref> flds_autofree(flds);
770
+ args.kvals = flds;
771
+ args.kvalslen = fldnum;
772
+ for (size_t i = 0; i < fldnum; ++i) {
773
+ skip_one(start, finish);
774
+ char *const f_begin = start;
775
+ read_token(start, finish);
776
+ char *const f_end = start;
777
+ if (is_null_expression(f_begin, f_end)) {
778
+ /* null */
779
+ flds[i] = string_ref();
780
+ } else {
781
+ /* non-null */
782
+ char *wp = f_begin;
783
+ unescape_string(wp, f_begin, f_end);
784
+ flds[i] = string_ref(f_begin, wp - f_begin);
785
+ }
786
+ }
787
+ skip_one(start, finish);
788
+ args.limit = read_ui32(start, finish);
789
+ skip_one(start, finish);
790
+ args.skip = read_ui32(start, finish);
791
+ if (start == finish) {
792
+ /* simple query */
793
+ return dbctx->cmd_exec(conn, args);
794
+ }
795
+ /* has more options */
796
+ skip_one(start, finish);
797
+ /* in-clause */
798
+ if (start[0] == '@') {
799
+ read_token(start, finish); /* '@' */
800
+ skip_one(start, finish);
801
+ args.invalues_keypart = read_ui32(start, finish);
802
+ skip_one(start, finish);
803
+ args.invalueslen = read_ui32(start, finish);
804
+ if (args.invalueslen <= 0) {
805
+ return conn.dbcb_resp_short(2, "invalueslen");
806
+ }
807
+ if (invalues_work.size() < args.invalueslen) {
808
+ invalues_work.resize(args.invalueslen);
809
+ }
810
+ args.invalues = &invalues_work[0];
811
+ for (uint32_t i = 0; i < args.invalueslen; ++i) {
812
+ skip_one(start, finish);
813
+ char *const invalue_begin = start;
814
+ read_token(start, finish);
815
+ char *const invalue_end = start;
816
+ char *wp = invalue_begin;
817
+ unescape_string(wp, invalue_begin, invalue_end);
818
+ invalues_work[i] = string_ref(invalue_begin, wp - invalue_begin);
819
+ }
820
+ skip_one(start, finish);
821
+ }
822
+ if (start == finish) {
823
+ /* no more options */
824
+ return dbctx->cmd_exec(conn, args);
825
+ }
826
+ /* filters */
827
+ size_t filters_count = 0;
828
+ while (start != finish && (start[0] == 'W' || start[0] == 'F')) {
829
+ char *const filter_type_begin = start;
830
+ read_token(start, finish);
831
+ char *const filter_type_end = start;
832
+ skip_one(start, finish);
833
+ char *const filter_op_begin = start;
834
+ read_token(start, finish);
835
+ char *const filter_op_end = start;
836
+ skip_one(start, finish);
837
+ const uint32_t ff_offset = read_ui32(start, finish);
838
+ skip_one(start, finish);
839
+ char *const filter_val_begin = start;
840
+ read_token(start, finish);
841
+ char *const filter_val_end = start;
842
+ skip_one(start, finish);
843
+ if (filters_work.size() <= filters_count) {
844
+ filters_work.resize(filters_count + 1);
845
+ }
846
+ record_filter& fi = filters_work[filters_count];
847
+ if (filter_type_end != filter_type_begin + 1) {
848
+ return conn.dbcb_resp_short(2, "filtertype");
849
+ }
850
+ fi.filter_type = (filter_type_begin[0] == 'W')
851
+ ? record_filter_type_break : record_filter_type_skip;
852
+ const uint32_t num_filflds = args.pst->get_filter_fields().size();
853
+ if (ff_offset >= num_filflds) {
854
+ return conn.dbcb_resp_short(2, "filterfld");
855
+ }
856
+ fi.op = string_ref(filter_op_begin, filter_op_end);
857
+ fi.ff_offset = ff_offset;
858
+ if (is_null_expression(filter_val_begin, filter_val_end)) {
859
+ /* null */
860
+ fi.val = string_ref();
861
+ } else {
862
+ /* non-null */
863
+ char *wp = filter_val_begin;
864
+ unescape_string(wp, filter_val_begin, filter_val_end);
865
+ fi.val = string_ref(filter_val_begin, wp - filter_val_begin);
866
+ }
867
+ ++filters_count;
868
+ }
869
+ if (filters_count > 0) {
870
+ if (filters_work.size() <= filters_count) {
871
+ filters_work.resize(filters_count + 1);
872
+ }
873
+ filters_work[filters_count].op = string_ref(); /* sentinel */
874
+ args.filters = &filters_work[0];
875
+ } else {
876
+ args.filters = 0;
877
+ }
878
+ if (start == finish) {
879
+ /* no modops */
880
+ return dbctx->cmd_exec(conn, args);
881
+ }
882
+ /* has modops */
883
+ char *const mod_op_begin = start;
884
+ read_token(start, finish);
885
+ char *const mod_op_end = start;
886
+ args.mod_op = string_ref(mod_op_begin, mod_op_end);
887
+ const size_t num_uvals = args.pst->get_ret_fields().size();
888
+ string_ref *const uflds = DENA_ALLOCA_ALLOCATE(string_ref, num_uvals);
889
+ auto_alloca_free<string_ref> uflds_autofree(uflds);
890
+ for (size_t i = 0; i < num_uvals; ++i) {
891
+ skip_one(start, finish);
892
+ char *const f_begin = start;
893
+ read_token(start, finish);
894
+ char *const f_end = start;
895
+ if (is_null_expression(f_begin, f_end)) {
896
+ /* null */
897
+ uflds[i] = string_ref();
898
+ } else {
899
+ /* non-null */
900
+ char *wp = f_begin;
901
+ unescape_string(wp, f_begin, f_end);
902
+ uflds[i] = string_ref(f_begin, wp - f_begin);
903
+ }
904
+ }
905
+ args.uvals = uflds;
906
+ return dbctx->cmd_exec(conn, args);
907
+ }
908
+
909
+ void
910
+ hstcpsvr_worker::do_authorization(char *start, char *finish,
911
+ hstcpsvr_conn& conn)
912
+ {
913
+ /* auth type */
914
+ char *const authtype_begin = start;
915
+ read_token(start, finish);
916
+ char *const authtype_end = start;
917
+ const size_t authtype_len = authtype_end - authtype_begin;
918
+ skip_one(start, finish);
919
+ /* key */
920
+ char *const key_begin = start;
921
+ read_token(start, finish);
922
+ char *const key_end = start;
923
+ const size_t key_len = key_end - key_begin;
924
+ authtype_end[0] = 0;
925
+ key_end[0] = 0;
926
+ char *wp = key_begin;
927
+ unescape_string(wp, key_begin, key_end);
928
+ if (authtype_len != 1 || authtype_begin[0] != '1') {
929
+ return conn.dbcb_resp_short(3, "authtype");
930
+ }
931
+ if (cshared.plain_secret.size() == key_len &&
932
+ memcmp(cshared.plain_secret.data(), key_begin, key_len) == 0) {
933
+ conn.authorized = true;
934
+ } else {
935
+ conn.authorized = false;
936
+ }
937
+ if (!conn.authorized) {
938
+ return conn.dbcb_resp_short(3, "unauth");
939
+ } else {
940
+ return conn.dbcb_resp_short(0, "");
941
+ }
942
+ }
943
+
944
+ hstcpsvr_worker_ptr
945
+ hstcpsvr_worker_i::create(const hstcpsvr_worker_arg& arg)
946
+ {
947
+ return hstcpsvr_worker_ptr(new hstcpsvr_worker(arg));
948
+ }
949
+
950
+ };
951
+