Skip to content
Newer
Older
100644 350 lines (291 sloc) 11.4 KB
3888b56 add hacked memcacheq
xunxin authored May 7, 2009
1 /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 * MemcacheQ - Simple Queue Service over Memcache
4 *
5 * http://memcacheq.googlecode.com
6 *
7 * The source code of MemcacheQ is most based on MemcachDB:
8 *
9 * http://memcachedb.googlecode.com
10 *
11 * Copyright 2008 Steve Chu. All rights reserved.
12 *
13 * Use and distribution licensed under the BSD license. See
14 * the LICENSE file for full text.
15 *
16 * Authors:
17 * Steve Chu <stvchu@gmail.com>
18 *
19 */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/time.h>
28 #include <netinet/in.h>
29 #include <event.h>
30 #include <netdb.h>
31 #include <db.h>
32
33 #define DATA_BUFFER_SIZE 2048
34 #define UDP_READ_BUFFER_SIZE 65536
35 #define UDP_MAX_PAYLOAD_SIZE 1400
36 #define UDP_HEADER_SIZE 8
37 #define MAX_SENDBUF_SIZE (256 * 1024 * 1024)
38 /* I'm told the max legnth of a 64-bit num converted to string is 20 bytes.
39 * Plus a few for spaces, \r\n, \0 */
40 #define SUFFIX_SIZE 24
41
42 /** Initial size of list of items being returned by "get". */
43 #define ITEM_LIST_INITIAL 200
44
45 /** Initial size of the sendmsg() scatter/gather array. */
46 #define IOV_LIST_INITIAL 400
47
48 /** Initial number of sendmsg() argument structures to allocate. */
49 #define MSG_LIST_INITIAL 10
50
51 /** High water marks for buffer shrinking */
52 #define READ_BUFFER_HIGHWAT 8192
53 #define ITEM_LIST_HIGHWAT 400
54 #define IOV_LIST_HIGHWAT 600
55 #define MSG_LIST_HIGHWAT 100
56
57 #define DBHOME "/data1/memcacheq"
58
d5b9e0e now memcacheq supported a max size per queue
xunxin authored May 25, 2009
59 #define NREAD_ADD 1
60 #define NREAD_SET 2
61
3888b56 add hacked memcacheq
xunxin authored May 7, 2009
62 /* Get a consistent bool type */
63 #if HAVE_STDBOOL_H
64 # include <stdbool.h>
65 #else
66 typedef enum {false = 0, true = 1} bool;
67 #endif
68
69 #if HAVE_STDINT_H
70 # include <stdint.h>
71 #else
72 typedef unsigned char uint8_t;
73 #endif
74
75 /* unistd.h is here */
76 #if HAVE_UNISTD_H
77 # include <unistd.h>
78 #endif
79
80 struct stats {
81 unsigned int curr_conns;
82 unsigned int total_conns;
83 unsigned int conn_structs;
84 uint64_t get_cmds;
85 uint64_t get_hits;
86 uint64_t set_cmds;
87 uint64_t set_hits;
88 time_t started; /* when the process was started */
89 uint64_t bytes_read;
90 uint64_t bytes_written;
91 };
92
93 #define MAX_VERBOSITY_LEVEL 2
94
95 struct settings {
96 int maxconns;
97 int port;
98 int udpport;
99 char *inter;
100 int verbose;
101 char *socketpath; /* path to unix socket if using local socket */
102 int access; /* access mask (a la chmod) for unix domain socket */
103 int num_threads; /* number of libevent threads to run */
104 };
105
106 extern struct stats stats;
107 extern struct settings settings;
108
109 struct bdb_version {
110 int majver;
111 int minver;
112 int patch;
113 };
114
115 struct bdb_settings {
116 char *env_home; /* db env home dir path */
117 u_int32_t cache_size; /* cache size */
118 u_int32_t txn_lg_bsize; /* transaction log buffer size */
119 u_int32_t page_size; /* underlying database pagesize*/
120 int txn_nosync; /* DB_TXN_NOSYNC flag, if 1 will lose transaction's durability for performance */
121 int dldetect_val; /* do deadlock detect every *db_lock_detect_val* millisecond, 0 for disable */
122 int chkpoint_val; /* do checkpoint every *db_chkpoint_val* second, 0 for disable */
123 int memp_trickle_val; /* do memp_trickle every *memp_trickle_val* second, 0 for disable */
124 int memp_trickle_percent; /* percent of the pages in the cache that should be clean.*/
125 u_int32_t db_flags; /* database open flags */
126 u_int32_t env_flags; /* env open flags */
127 u_int32_t re_len;
128 u_int32_t q_extentsize;
129 };
130
131 /* queue record, for updating queue length*/
132 /* added by xunxin*/
133 typedef struct {
134 DB* queue_dbp;
d5b9e0e now memcacheq supported a max size per queue
xunxin authored May 25, 2009
135 u_int32_t max_size;
136 u_int32_t size;
3888b56 add hacked memcacheq
xunxin authored May 7, 2009
137 } queue_rec_t;
138
139
140 extern struct bdb_settings bdb_settings;
141 extern struct bdb_version bdb_version;
142
143 typedef struct _stritem {
144 int nbytes; /* size of data */
145 uint8_t nsuffix; /* length of flags-and-length string */
146 uint8_t nkey; /* key length, w/terminating null and padding */
147 void * end[];
148 /* then null-terminated key */
149 /* then " flags length\r\n" (no terminating null) */
150 /* then data with terminating \r\n (no terminating null; it's binary!) */
151 } item;
152
153 typedef struct msg_queue_t {
154 int64_t length;
155 DB *dbp;
156 /*char pads[80];*/
157 } msg_queue_t;
158
159 #define ITEM_key(item) ((char*)&((item)->end[0]))
160
161 /* warning: don't use these macros with a function, as it evals its arg twice */
162 #define ITEM_suffix(item) ((char*) &((item)->end[0]) + (item)->nkey + 1)
163 #define ITEM_data(item) ((char*) &((item)->end[0]) + (item)->nkey + 1 + (item)->nsuffix)
164 #define ITEM_ntotal(item) (sizeof(struct _stritem) + (item)->nkey + 1 + (item)->nsuffix + (item)->nbytes)
165
166 enum conn_states {
167 conn_listening, /** the socket which listens for connections */
168 conn_read, /** reading in a command line */
169 conn_write, /** writing out a simple response */
170 conn_nread, /** reading in a fixed number of bytes */
171 conn_swallow, /** swallowing unnecessary bytes w/o storing */
172 conn_closing, /** closing this connection */
173 conn_mwrite, /** writing out many items sequentially */
174 };
175
176 typedef struct conn conn;
177 struct conn {
178 int sfd;
179 int state;
180 struct event event;
181 short ev_flags;
182 short which; /** which events were just triggered */
183
184 char *rbuf; /** buffer to read commands into */
185 char *rcurr; /** but if we parsed some already, this is where we stopped */
186 int rsize; /** total allocated size of rbuf */
187 int rbytes; /** how much data, starting from rcur, do we have unparsed */
188
189 char *wbuf;
190 char *wcurr;
191 int wsize;
192 int wbytes;
193 int write_and_go; /** which state to go into after finishing current write */
194 void *write_and_free; /** free this memory after finishing writing */
195
196 char *ritem; /** when we read in an item's value, it goes here */
197 int rlbytes;
198
199 /* data for the nread state */
200
201 /**
202 * item is used to hold an item structure created after reading the command
203 * line of set/add/replace commands, but before we finished reading the actual
204 * data. The data is read into ITEM_data(item) to avoid extra copying.
205 */
206
207 void *item; /* for commands set/add/replace */
208 int item_comm; /* which one is it: set/add/replace */
209
210 /* data for the swallow state */
211 int sbytes; /* how many bytes to swallow */
212
213 /* data for the mwrite state */
214 struct iovec *iov;
215 int iovsize; /* number of elements allocated in iov[] */
216 int iovused; /* number of elements used in iov[] */
217
218 struct msghdr *msglist;
219 int msgsize; /* number of elements allocated in msglist[] */
220 int msgused; /* number of elements used in msglist[] */
221 int msgcurr; /* element in msglist[] being transmitted now */
222 int msgbytes; /* number of bytes in current msg */
223
224 item **ilist; /* list of items to write out */
225 int isize;
226 item **icurr;
227 int ileft;
228
229 /* data for UDP clients */
230 bool udp; /* is this is a UDP "connection" */
231 int request_id; /* Incoming UDP request ID, if this is a UDP "connection" */
232 struct sockaddr request_addr; /* Who sent the most recent request */
233 socklen_t request_addr_size;
234 unsigned char *hdrbuf; /* udp packet headers */
235 int hdrsize; /* number of headers' worth of space is allocated */
236 conn *next; /* Used for generating a list of conn structures */
237 };
238
239 /*
240 * Functions
241 */
242
243 /* bdb management */
244 void bdb_settings_init(void);
245 void bdb_env_init(void);
246
247 void bdb_qlist_db_open(void);
248 int delete_queue_db(char *queue_name, size_t queue_name_size);
249 int print_queue_db_list(char *buf, size_t buf_size);
250 item *bdb_get(char *key, size_t nkey);
d5b9e0e now memcacheq supported a max size per queue
xunxin authored May 25, 2009
251 int bdb_add(char *key, size_t nkey, item *it);
3888b56 add hacked memcacheq
xunxin authored May 7, 2009
252 int bdb_put(char *key, size_t nkey, item *it);
253
254 void start_chkpoint_thread(void);
255 void start_memp_trickle_thread(void);
256 void start_dl_detect_thread(void);
257 void bdb_db_close(void);
258 void bdb_env_close(void);
259 void bdb_chkpoint(void);
260
261 /* ibuffer management */
262 void item_init(void);
263 item *do_item_from_freelist(void);
264 int do_item_add_to_freelist(item *it);
265 item *item_alloc1(char *key, const size_t nkey, const int flags, const int nbytes);
266 item *item_alloc2(void);
267 int item_free(item *it);
268 item *item_get(char *key, size_t nkey);
269 int item_put(char *key, size_t nkey, item *it);
270 int item_delete(char *key, size_t nkey);
271 int item_exists(char *key, size_t nkey);
272
273 /* conn management */
274 conn *do_conn_from_freelist();
275 bool do_conn_add_to_freelist(conn *c);
276 conn *conn_new(const int sfd, const int init_state, const int event_flags, const int read_buffer_size, const bool is_udp, struct event_base *base);
277
278 /*
279 * In multithreaded mode, we wrap certain functions with lock management and
280 * replace the logic of some other functions. All wrapped functions have
281 * "mt_" and "do_" variants. In multithreaded mode, the plain version of a
282 * function is #define-d to the "mt_" variant, which often just grabs a
283 * lock and calls the "do_" function. In singlethreaded mode, the "do_"
284 * function is called directly.
285 *
286 * Functions such as the libevent-related calls that need to do cross-thread
287 * communication in multithreaded mode (rather than actually doing the work
288 * in the current thread) are called via "dispatch_" frontends, which are
289 * also #define-d to directly call the underlying code in singlethreaded mode.
290 */
291 #ifdef USE_THREADS
292
293 void thread_init(int nthreads, struct event_base *main_base);
294 int dispatch_event_add(int thread, conn *c);
295 void dispatch_conn_new(int sfd, int init_state, int event_flags, int read_buffer_size, int is_udp);
296
297 /* Lock wrappers for cache functions that are called from main loop. */
298 conn *mt_conn_from_freelist(void);
299 bool mt_conn_add_to_freelist(conn *c);
300 int mt_is_listen_thread(void);
301 item *mt_item_from_freelist(void);
302 int mt_item_add_to_freelist(item *it);
303 void mt_stats_lock(void);
304 void mt_stats_unlock(void);
305 void mt_update_queue_length_lock(void);
306 void mt_update_queue_length_unlock(void);
307 int mt_store_item(item *item, int comm);
308
309 # define conn_from_freelist() mt_conn_from_freelist()
310 # define conn_add_to_freelist(x) mt_conn_add_to_freelist(x)
311 # define is_listen_thread() mt_is_listen_thread()
312 # define item_from_freelist() mt_item_from_freelist()
313 # define item_add_to_freelist(x) mt_item_add_to_freelist(x)
314 # define store_item(x,y) mt_store_item(x,y)
315
316 # define STATS_LOCK() mt_stats_lock()
317 # define STATS_UNLOCK() mt_stats_unlock()
318
319 # define UPDATE_QUEUE_LENGTH_LOCK() mt_update_queue_length_lock()
320 # define UPDATE_QUEUE_LENGTH_UNLOCK() mt_update_queue_length_unlock()
321
322 #else /* !USE_THREADS */
323
324 # define conn_from_freelist() do_conn_from_freelist()
325 # define conn_add_to_freelist(x) do_conn_add_to_freelist(x)
326 # define dispatch_conn_new(x,y,z,a,b) conn_new(x,y,z,a,b,main_base)
327 # define dispatch_event_add(t,c) event_add(&(c)->event, 0)
328 # define is_listen_thread() 1
329 # define item_from_freelist() do_item_from_freelist()
330 # define item_add_to_freelist(x) do_item_add_to_freelist(x)
331 # define store_item(x,y) do_store_item(x,y)
332 # define thread_init(x,y) 0
333
334 # define STATS_LOCK() /**/
335 # define STATS_UNLOCK() /**/
336
337 # define UPDATE_QUEUE_LENGTH_LOCK() /**/
338 # define UPDATE_QUEUE_LENGTH_UNLOCK() /**/
339
340 #endif /* !USE_THREADS */
341
342
343 #define BDB_CLEANUP_DBT() \
344 memset(&dbkey, 0, sizeof(dbkey)); \
345 memset(&dbdata, 0, sizeof(dbdata))
346
347 extern DB_ENV *envp;
348 extern DB *qlist_dbp;
349 extern int daemon_quit;
Something went wrong with that request. Please try again.