r5554 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r5553‎ | r5554 | r5555 >
Date:20:29, 26 September 2004
Author:(no author)
Status:old
Tags:
Comment:
This commit was manufactured by cvs2svn to create tag 'tug_0_1'.
Modified paths:
  • /tags/tug_0_1 (added) (history)
  • /tags/tug_0_1 (added) (history)
  • /tags/tug_0_1/CVSROOT (deleted) (history)
  • /tags/tug_0_1/Waikiki (deleted) (history)
  • /tags/tug_0_1/extensions (deleted) (history)
  • /tags/tug_0_1/flexbisonparse (deleted) (history)
  • /tags/tug_0_1/phase3 (deleted) (history)
  • /tags/tug_0_1/phpwiki (deleted) (history)
  • /tags/tug_0_1/tugelacache/.deps (replaced) (history)
  • /tags/tug_0_1/tugelacache/.deps (replaced) (history)
  • /tags/tug_0_1/tugelacache/AUTHORS (replaced) (history)
  • /tags/tug_0_1/tugelacache/AUTHORS (replaced) (history)
  • /tags/tug_0_1/tugelacache/NEWS (replaced) (history)
  • /tags/tug_0_1/tugelacache/NEWS (replaced) (history)
  • /tags/tug_0_1/wiki2xml (deleted) (history)
  • /tags/tug_0_1/wikitex (deleted) (history)
  • /tags/tug_0_1/yearbook (deleted) (history)

Diff [purge]

Index: tags/tug_0_1/tugelacache/items.c
@@ -0,0 +1,126 @@
 2+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 3+/* $Id$ */
 4+
 5+#include <sys/types.h>
 6+#include <sys/stat.h>
 7+#include <sys/time.h>
 8+#include <sys/socket.h>
 9+#include <sys/signal.h>
 10+#include <sys/resource.h>
 11+#include <fcntl.h>
 12+#include <stdlib.h>
 13+#include <stdio.h>
 14+#include <string.h>
 15+#include <unistd.h>
 16+#include <netinet/in.h>
 17+#include <errno.h>
 18+#include <time.h>
 19+#include <event.h>
 20+#include <assert.h>
 21+
 22+#include "dbcached.h"
 23+
 24+
 25+/*
 26+ * NOTE: we assume here for simplicity that slab ids are <=32. That's true in
 27+ * the powers-of-2 implementation, but if that changes this should be changed too
 28+ */
 29+
 30+#define LARGEST_ID 32
 31+static item *heads[LARGEST_ID];
 32+static item *tails[LARGEST_ID];
 33+unsigned int sizes[LARGEST_ID];
 34+
 35+void item_init(void)
 36+{
 37+ int i;
 38+ for (i = 0; i < LARGEST_ID; i++) {
 39+ heads[i] = 0;
 40+ tails[i] = 0;
 41+ sizes[i] = 0;
 42+ }
 43+}
 44+
 45+
 46+item *item_alloc(char *key, int flags, time_t exptime, int nbytes)
 47+{
 48+ int ntotal, len;
 49+ item *it = NULL;
 50+
 51+ len = strlen(key) + 1;
 52+ if (len % 4)
 53+ len += 4 - (len % 4);
 54+ ntotal = sizeof(item) + len + nbytes;
 55+
 56+ it = realloc(it, ntotal);
 57+ it->refcount = 0;
 58+ it->it_flags = 0;
 59+ it->nkey = len;
 60+ it->nbytes = nbytes;
 61+ strcpy(ITEM_key(it), key);
 62+ it->exptime = exptime;
 63+ it->flags = flags;
 64+ it->time = time(0);
 65+ return it;
 66+}
 67+
 68+void item_free(item * it)
 69+{
 70+ assert((it->it_flags & ITEM_LINKED) == 0);
 71+ assert(it->refcount == 0);
 72+
 73+ /* so slab size changer can tell later if item is already free or not */
 74+ it->it_flags |= ITEM_SLABBED;
 75+}
 76+
 77+void item_unlink(item * it)
 78+{
 79+ free(it);
 80+}
 81+
 82+void item_remove(item * it)
 83+{
 84+ free(it);
 85+}
 86+
 87+void item_update(item * it)
 88+{
 89+ it->time = time(0);
 90+}
 91+
 92+int item_replace(item * it, item * new_it)
 93+{
 94+ return 0;
 95+}
 96+
 97+char *item_cachedump(unsigned int slabs_clsid, unsigned int limit,
 98+ unsigned int *bytes)
 99+{
 100+
 101+ int memlimit = 2 * 1024 * 1024;
 102+ char *buffer;
 103+ int bufcurr;
 104+
 105+ buffer = malloc(memlimit);
 106+ if (buffer == 0)
 107+ return 0;
 108+ bufcurr = 0;
 109+ strcpy(buffer + bufcurr, "END\r\n");
 110+ bufcurr += 5;
 111+
 112+ *bytes = bufcurr;
 113+ return buffer;
 114+}
 115+
 116+void item_stats(char *buffer, int buflen)
 117+{
 118+ char *bufcurr = buffer;
 119+
 120+ if (buflen < 4096) {
 121+ strcpy(buffer, "SERVER_ERROR out of memory");
 122+ return;
 123+ }
 124+
 125+ strcpy(bufcurr, "END");
 126+ return;
 127+}
Property changes on: tags/tug_0_1/tugelacache/items.c
___________________________________________________________________
Added: svn:keywords
1128 + Author Date Id Revision
Added: svn:eol-style
2129 + native
Index: tags/tug_0_1/tugelacache/dbcached.h
@@ -0,0 +1,213 @@
 2+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 3+/* $Id$ */
 4+
 5+#define DATA_BUFFER_SIZE 2048
 6+
 7+#if defined(TCP_CORK) && !defined(TCP_NOPUSH)
 8+#define TCP_NOPUSH TCP_CORK
 9+#endif
 10+
 11+struct stats {
 12+ unsigned int curr_items;
 13+ unsigned int total_items;
 14+ unsigned long long curr_bytes;
 15+ unsigned int curr_conns;
 16+ unsigned int total_conns;
 17+ unsigned int conn_structs;
 18+ unsigned int get_cmds;
 19+ unsigned int set_cmds;
 20+ unsigned int get_hits;
 21+ unsigned int get_misses;
 22+ time_t started; /* when the process was started */
 23+ unsigned long long bytes_read;
 24+ unsigned long long bytes_written;
 25+};
 26+
 27+struct settings {
 28+ unsigned int maxbytes;
 29+ int maxconns;
 30+ int synctimer;
 31+ int port;
 32+ struct in_addr interface;
 33+ int verbose;
 34+ time_t oldest_live; /* ignore existing items older than this */
 35+ int evict_to_free;
 36+};
 37+
 38+extern struct stats stats;
 39+extern struct settings settings;
 40+
 41+#define ITEM_LINKED 1
 42+#define ITEM_DELETED 2
 43+
 44+/* temp */
 45+#define ITEM_SLABBED 4
 46+
 47+typedef struct _stritem {
 48+ unsigned short refcount;
 49+ unsigned short flags;
 50+ int nbytes; /* size of data */
 51+ time_t time; /* least recent access */
 52+ time_t exptime; /* expire time */
 53+ unsigned char it_flags; /* ITEM_* above */
 54+ unsigned char nkey; /* key length, with terminating null and padding */
 55+ unsigned char dummy1;
 56+ void *end[0];
 57+} item;
 58+
 59+#define ITEM_key(item) ((char*)&((item)->end[0]))
 60+
 61+/* warning: don't use these macros with a function, as it evals its arg twice */
 62+#define ITEM_data(item) ((char*) &((item)->end[0]) + (item)->nkey)
 63+#define ITEM_ntotal(item) (sizeof(struct _stritem) + (item)->nkey + (item)->nbytes)
 64+
 65+enum conn_states {
 66+ conn_listening, /* the socket which listens for connections */
 67+ conn_read, /* reading in a command line */
 68+ conn_write, /* writing out a simple response */
 69+ conn_nread, /* reading in a fixed number of bytes */
 70+ conn_swallow, /* swallowing unnecessary bytes w/o storing */
 71+ conn_closing, /* closing this connection */
 72+ conn_mwrite /* writing out many items sequentially */
 73+};
 74+
 75+#define NREAD_ADD 1
 76+#define NREAD_SET 2
 77+#define NREAD_REPLACE 3
 78+
 79+typedef struct {
 80+ int sfd;
 81+ int state;
 82+ struct event event;
 83+ short ev_flags;
 84+ short which; /* which events were just triggered */
 85+
 86+ char *rbuf;
 87+ int rsize;
 88+ int rbytes;
 89+
 90+ char *wbuf;
 91+ char *wcurr;
 92+ int wsize;
 93+ int wbytes;
 94+ int write_and_go; /* which state to go into after finishing current write */
 95+ void *write_and_free; /* free this memory after finishing writing */
 96+ char is_corked; /* boolean, connection is corked */
 97+
 98+ char *rcurr;
 99+ int rlbytes;
 100+
 101+ /* data for the nread state */
 102+
 103+ /*
 104+ * item is used to hold an item structure created after reading the command
 105+ * line of set/add/replace commands, but before we finished reading the actual
 106+ * data. The data is read into ITEM_data(item) to avoid extra copying.
 107+ */
 108+
 109+ void *item; /* for commands set/add/replace */
 110+ int item_comm; /* which one is it: set/add/replace */
 111+
 112+ /* data for the swallow state */
 113+ int sbytes; /* how many bytes to swallow */
 114+
 115+ /* data for the mwrite state */
 116+ item **ilist; /* list of items to write out */
 117+ int isize;
 118+ item **icurr;
 119+ int ileft;
 120+ int ipart; /* 1 if we're writing a VALUE line, 2 if we're writing data */
 121+ char ibuf[300]; /* for VALUE lines */
 122+ char *iptr;
 123+ int ibytes;
 124+
 125+} conn;
 126+
 127+/* listening socket */
 128+extern int l_socket;
 129+
 130+/* temporary hack */
 131+/* #define assert(x) if(!(x)) { printf("assert failure: %s\n", #x); pre_gdb(); }
 132+ void pre_gdb (); */
 133+
 134+/*
 135+ * Functions
 136+ */
 137+
 138+/*
 139+ * given time value that's either unix time or delta from current unix time, return
 140+ * unix time. Use the fact that delta can't exceed one month (and real time value can't
 141+ * be that low).
 142+ */
 143+
 144+time_t realtime(time_t exptime);
 145+
 146+/* slabs memory allocation */
 147+
 148+/* Init the subsystem. The argument is the limit on no. of bytes to allocate, 0 if no limit */
 149+void slabs_init(unsigned int limit);
 150+
 151+/* Given object size, return id to use when allocating/freeing memory for object */
 152+/* 0 means error: can't store such a large object */
 153+unsigned int slabs_clsid(unsigned int size);
 154+
 155+/* Allocate object of given length. 0 on error */
 156+void *slabs_alloc(unsigned int size);
 157+
 158+/* Free previously allocated object */
 159+void slabs_free(void *ptr, unsigned int size);
 160+
 161+/* Fill buffer with stats */
 162+char *slabs_stats(int *buflen);
 163+
 164+/* Request some slab be moved between classes
 165+ 1 = success
 166+ 0 = fail
 167+ -1 = tried. busy. send again shortly. */
 168+int slabs_reassign(unsigned char srcid, unsigned char dstid);
 169+
 170+/* event handling, network IO */
 171+void event_handler(int fd, short which, void *arg);
 172+conn *conn_new(int sfd, int init_state, int event_flags);
 173+void conn_close(conn * c);
 174+void conn_init(void);
 175+void drive_machine(conn * c);
 176+int new_socket(void);
 177+int server_socket(int port);
 178+int update_event(conn * c, int new_flags);
 179+int try_read_command(conn * c);
 180+int try_read_network(conn * c);
 181+void complete_nread(conn * c);
 182+void process_command(conn * c, char *command);
 183+
 184+/* stats */
 185+void stats_reset(void);
 186+void stats_init(void);
 187+
 188+/* defaults */
 189+void settings_init(void);
 190+
 191+/* associative array */
 192+void assoc_init(void);
 193+item *assoc_find(char *key);
 194+int assoc_insert(char *key, item * item);
 195+void assoc_delete(char *key);
 196+
 197+
 198+void item_init(void);
 199+item *item_alloc(char *key, int flags, time_t exptime, int nbytes);
 200+void item_free(item * it);
 201+
 202+int item_link(item * it); /* may fail if transgresses limits */
 203+void item_unlink(item * it);
 204+void item_remove(item * it);
 205+void cleanup_dbt(void);
 206+
 207+void item_update(item * it); /* update LRU time to current and reposition */
 208+int item_replace(item * it, item * new_it);
 209+char *item_cachedump(unsigned int slabs_clsid, unsigned int limit,
 210+ unsigned int *bytes);
 211+char *item_stats_sizes(int *bytes);
 212+void item_stats(char *buffer, int buflen);
 213+
 214+void syncdb(void);
Property changes on: tags/tug_0_1/tugelacache/dbcached.h
___________________________________________________________________
Added: svn:keywords
1215 + Author Date Id Revision
Added: svn:eol-style
2216 + native
Index: tags/tug_0_1/tugelacache/AUTHORS
@@ -0,0 +1,3 @@
 2+Anatoly Vorobey <mellon@pobox.com>
 3+Brad Fitzpatrick <brad@danga.com>
 4+Domas Mituzas <domas.mituzas@gmail.com>
Property changes on: tags/tug_0_1/tugelacache/AUTHORS
___________________________________________________________________
Added: svn:keywords
15 + Author Date Id Revision
Added: svn:eol-style
26 + native
Index: tags/tug_0_1/tugelacache/.deps/dbcached.pp
@@ -0,0 +1,17 @@
 2+dbcached.o: dbcached.c config.h /usr/include/sys/types.h \
 3+ /usr/include/sys/cdefs.h /usr/include/sys/inttypes.h \
 4+ /usr/include/machine/ansi.h /usr/include/machine/types.h \
 5+ /usr/include/machine/endian.h /usr/include/sys/stat.h \
 6+ /usr/include/sys/time.h /usr/include/time.h /usr/include/sys/_posix.h \
 7+ /usr/include/sys/socket.h /usr/include/machine/param.h \
 8+ /usr/include/sys/signal.h /usr/include/machine/signal.h \
 9+ /usr/include/machine/trap.h /usr/include/sys/ucontext.h \
 10+ /usr/include/machine/ucontext.h /usr/include/sys/resource.h \
 11+ /usr/include/pwd.h /usr/include/sys/mman.h /usr/include/fcntl.h \
 12+ /usr/include/stdlib.h /usr/include/stdio.h /usr/include/string.h \
 13+ /usr/include/unistd.h /usr/include/sys/unistd.h \
 14+ /usr/include/netinet/in.h /usr/include/netinet6/in6.h \
 15+ /usr/include/netinet/tcp.h /usr/include/arpa/inet.h \
 16+ /usr/include/errno.h /usr/local/include/event.h /usr/include/assert.h \
 17+ /usr/include/db.h /usr/include/limits.h /usr/include/machine/limits.h \
 18+ /usr/include/sys/syslimits.h /usr/include/malloc.h dbcached.h
Property changes on: tags/tug_0_1/tugelacache/.deps/dbcached.pp
___________________________________________________________________
Added: svn:keywords
119 + Author Date Id Revision
Added: svn:eol-style
220 + native
Index: tags/tug_0_1/tugelacache/assoc.c
@@ -0,0 +1,168 @@
 2+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 3+/*
 4+ * Hash table
 5+ *
 6+ * The hash function used here is by Bob Jenkins, 1996:
 7+ * <http://burtleburtle.net/bob/hash/doobs.html>
 8+ * "By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net.
 9+ * You may use this code any way you wish, private, educational,
 10+ * or commercial. It's free."
 11+ *
 12+ * The rest of the file is licensed under the BSD license. See LICENSE.
 13+ *
 14+ * $Id$
 15+ */
 16+
 17+#include <sys/types.h>
 18+#include <sys/stat.h>
 19+#include <sys/time.h>
 20+#include <sys/socket.h>
 21+#include <sys/signal.h>
 22+#include <sys/resource.h>
 23+#include <fcntl.h>
 24+#include <stdlib.h>
 25+#include <stdio.h>
 26+#include <string.h>
 27+#include <unistd.h>
 28+#include <netinet/in.h>
 29+#include <errno.h>
 30+#include <event.h>
 31+#include <assert.h>
 32+
 33+#include "dbcached.h"
 34+
 35+typedef unsigned long int ub4; /* unsigned 4-byte quantities */
 36+typedef unsigned char ub1; /* unsigned 1-byte quantities */
 37+
 38+/* hard-code one million buckets, for now (2**20 == 4MB hash) */
 39+#define HASHPOWER 20
 40+
 41+#define hashsize(n) ((ub4)1<<(n))
 42+#define hashmask(n) (hashsize(n)-1)
 43+
 44+#define mix(a,b,c) \
 45+{ \
 46+ a -= b; a -= c; a ^= (c>>13); \
 47+ b -= c; b -= a; b ^= (a<<8); \
 48+ c -= a; c -= b; c ^= (b>>13); \
 49+ a -= b; a -= c; a ^= (c>>12); \
 50+ b -= c; b -= a; b ^= (a<<16); \
 51+ c -= a; c -= b; c ^= (b>>5); \
 52+ a -= b; a -= c; a ^= (c>>3); \
 53+ b -= c; b -= a; b ^= (a<<10); \
 54+ c -= a; c -= b; c ^= (b>>15); \
 55+}
 56+
 57+/*
 58+--------------------------------------------------------------------
 59+hash() -- hash a variable-length key into a 32-bit value
 60+ k : the key (the unaligned variable-length array of bytes)
 61+ len : the length of the key, counting by bytes
 62+ initval : can be any 4-byte value
 63+Returns a 32-bit value. Every bit of the key affects every bit of
 64+the return value. Every 1-bit and 2-bit delta achieves avalanche.
 65+About 6*len+35 instructions.
 66+
 67+The best hash table sizes are powers of 2. There is no need to do
 68+mod a prime (mod is sooo slow!). If you need less than 32 bits,
 69+use a bitmask. For example, if you need only 10 bits, do
 70+ h = (h & hashmask(10));
 71+In which case, the hash table should have hashsize(10) elements.
 72+
 73+If you are hashing n strings (ub1 **)k, do it like this:
 74+ for (i=0, h=0; i<n; ++i) h = hash( k[i], len[i], h);
 75+
 76+By Bob Jenkins, 1996. bob_jenkins@burtleburtle.net. You may use this
 77+code any way you wish, private, educational, or commercial. It's free.
 78+
 79+See http://burtleburtle.net/bob/hash/evahash.html
 80+Use for hash table lookup, or anything where one collision in 2^^32 is
 81+acceptable. Do NOT use for cryptographic purposes.
 82+--------------------------------------------------------------------
 83+*/
 84+
 85+ub4 hash(k, length, initval)
 86+register ub1 *k; /* the key */
 87+register ub4 length; /* the length of the key */
 88+register ub4 initval; /* the previous hash, or an arbitrary value */
 89+{
 90+ register ub4 a, b, c, len;
 91+
 92+ /* Set up the internal state */
 93+ len = length;
 94+ a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
 95+ c = initval; /* the previous hash value */
 96+
 97+ /*---------------------------------------- handle most of the key */
 98+ while (len >= 12) {
 99+ a += (k[0] + ((ub4) k[1] << 8) + ((ub4) k[2] << 16) +
 100+ ((ub4) k[3] << 24));
 101+ b += (k[4] + ((ub4) k[5] << 8) + ((ub4) k[6] << 16) +
 102+ ((ub4) k[7] << 24));
 103+ c += (k[8] + ((ub4) k[9] << 8) + ((ub4) k[10] << 16) +
 104+ ((ub4) k[11] << 24));
 105+ mix(a, b, c);
 106+ k += 12;
 107+ len -= 12;
 108+ }
 109+
 110+ /*------------------------------------- handle the last 11 bytes */
 111+ c += length;
 112+ switch (len) { /* all the case statements fall through */
 113+ case 11:
 114+ c += ((ub4) k[10] << 24);
 115+ case 10:
 116+ c += ((ub4) k[9] << 16);
 117+ case 9:
 118+ c += ((ub4) k[8] << 8);
 119+ /* the first byte of c is reserved for the length */
 120+ case 8:
 121+ b += ((ub4) k[7] << 24);
 122+ case 7:
 123+ b += ((ub4) k[6] << 16);
 124+ case 6:
 125+ b += ((ub4) k[5] << 8);
 126+ case 5:
 127+ b += k[4];
 128+ case 4:
 129+ a += ((ub4) k[3] << 24);
 130+ case 3:
 131+ a += ((ub4) k[2] << 16);
 132+ case 2:
 133+ a += ((ub4) k[1] << 8);
 134+ case 1:
 135+ a += k[0];
 136+ /* case 0: nothing left to add */
 137+ }
 138+ mix(a, b, c);
 139+ /*-------------------------------------------- report the result */
 140+ return c;
 141+}
 142+
 143+static item **hashtable = 0;
 144+
 145+void assoc_init(void)
 146+{
 147+ unsigned int hash_size = hashsize(HASHPOWER) * sizeof(void *);
 148+ hashtable = malloc(hash_size);
 149+ if (!hashtable) {
 150+ fprintf(stderr, "Failed to init hashtable.\n");
 151+ exit(1);
 152+ }
 153+ memset(hashtable, 0, hash_size);
 154+}
 155+
 156+item *assoc_find(char *key)
 157+{
 158+ return 0;
 159+}
 160+
 161+/* Note: this isn't an assoc_update. The key must not already exist to call this */
 162+int assoc_insert(char *key, item * it)
 163+{
 164+ return 0;
 165+}
 166+
 167+void assoc_delete(char *key)
 168+{
 169+}
Property changes on: tags/tug_0_1/tugelacache/assoc.c
___________________________________________________________________
Added: svn:keywords
1170 + Author Date Id Revision
Added: svn:eol-style
2171 + native
Index: tags/tug_0_1/tugelacache/config.h
@@ -0,0 +1,68 @@
 2+/* default path of database */
 3+/* #undef DBFILE */
 4+
 5+/* Define to 1 if you have the <inttypes.h> header file. */
 6+#define HAVE_INTTYPES_H 1
 7+
 8+/* Define to 1 if you have the `db41' library (-ldb41). */
 9+/* #undef HAVE_LIBDB41 */
 10+
 11+/* Define to 1 if you have the `event' library (-levent). */
 12+#define HAVE_LIBEVENT 1
 13+
 14+/* Define to 1 if you have the <memory.h> header file. */
 15+#define HAVE_MEMORY_H 1
 16+
 17+/* Define to 1 if you have the `mlockall' function. */
 18+/* #undef HAVE_MLOCKALL */
 19+
 20+/* Define to 1 if you have the <stdint.h> header file. */
 21+/* #undef HAVE_STDINT_H */
 22+
 23+/* Define to 1 if you have the <stdlib.h> header file. */
 24+#define HAVE_STDLIB_H 1
 25+
 26+/* Define to 1 if you have the <strings.h> header file. */
 27+#define HAVE_STRINGS_H 1
 28+
 29+/* Define to 1 if you have the <string.h> header file. */
 30+#define HAVE_STRING_H 1
 31+
 32+/* do we have stuct mallinfo? */
 33+/* #undef HAVE_STRUCT_MALLINFO */
 34+
 35+/* Define to 1 if you have the <sys/stat.h> header file. */
 36+#define HAVE_SYS_STAT_H 1
 37+
 38+/* Define to 1 if you have the <sys/types.h> header file. */
 39+#define HAVE_SYS_TYPES_H 1
 40+
 41+/* Define to 1 if you have the <unistd.h> header file. */
 42+#define HAVE_UNISTD_H 1
 43+
 44+/* Name of package */
 45+#define PACKAGE "tugela"
 46+
 47+/* Define to the address where bug reports for this package should be sent. */
 48+#define PACKAGE_BUGREPORT "domas.mituzas@gmail.com"
 49+
 50+/* Define to the full name of this package. */
 51+#define PACKAGE_NAME "tugela object store daemon"
 52+
 53+/* Define to the full name and version of this package. */
 54+#define PACKAGE_STRING "tugela 0.1"
 55+
 56+/* Define to the one symbol short name of this package. */
 57+#define PACKAGE_TARNAME "tugela"
 58+
 59+/* Define to the version of this package. */
 60+#define PACKAGE_VERSION "0.1"
 61+
 62+/* Define to 1 if you have the ANSI C header files. */
 63+#define STDC_HEADERS 1
 64+
 65+/* Version number of package */
 66+#define VERSION "0.1"
 67+
 68+/* define to int if socklen_t not available */
 69+/* #undef socklen_t */
Property changes on: tags/tug_0_1/tugelacache/config.h
___________________________________________________________________
Added: svn:keywords
170 + Author Date Id Revision
Added: svn:eol-style
271 + native
Index: tags/tug_0_1/tugelacache/NEWS
Property changes on: tags/tug_0_1/tugelacache/NEWS
___________________________________________________________________
Added: svn:keywords
372 + Author Date Id Revision
Added: svn:eol-style
473 + native
Index: tags/tug_0_1/tugelacache/.cvsignore
@@ -0,0 +1,5 @@
 2+*~
 3+*.o
 4+tugela
 5+dbcache
 6+tugela-expire
Property changes on: tags/tug_0_1/tugelacache/.cvsignore
___________________________________________________________________
Added: svn:keywords
17 + Author Date Id Revision
Added: svn:eol-style
28 + native
Index: tags/tug_0_1/tugelacache/Makefile
@@ -0,0 +1,28 @@
 2+# $Id$
 3+#
 4+# It is not a real makefile, but sometimes it does work, and it is a place
 5+# where you should change one thing or another :)
 6+
 7+# Default path for a database
 8+DBFILE='"/var/db/dbcache"'
 9+
 10+# change it into your installed db3/db4{0,1,2} library name
 11+DBLIB=db41
 12+
 13+# FreeBSD file locations
 14+LIBS=-l${DBLIB} -levent
 15+DBLIBPATH=/usr/local/lib/${DBLIB}/
 16+DBINCPATH=/usr/local/include/${DBLIB}/
 17+
 18+LDFLAGS= -L/usr/local/lib/ -L${DBLIBPATH}
 19+CFLAGS = -O -pipe -I/usr/local/include -I${DBINCPATH} -DDBFILE=${DBFILE}
 20+
 21+all: tugela tugela-expire
 22+
 23+tugela: dbcached.o items.o assoc.o
 24+ cc -o tugela ${LDFLAGS} dbcached.o items.o assoc.o ${LIBS}
 25+
 26+tugela-expire: expire.c
 27+ cc -o tugela-expire ${LDFLAGS} ${LIBS} ${CFLAGS} expire.c
 28+clean:
 29+ rm -f -- *.o tugela tugela-expire *~ *.bak *core
Property changes on: tags/tug_0_1/tugelacache/Makefile
___________________________________________________________________
Added: svn:keywords
130 + Author Date Id Revision
Added: svn:eol-style
231 + native
Index: tags/tug_0_1/tugelacache/README
@@ -0,0 +1,3 @@
 2+simple berkeleydb hack from memcached
 3+more information can be found at:
 4+http://meta.wikimedia.org/wiki/Tugela_Cache
Property changes on: tags/tug_0_1/tugelacache/README
___________________________________________________________________
Added: svn:keywords
15 + Author Date Id Revision
Added: svn:eol-style
26 + native
Index: tags/tug_0_1/tugelacache/expire.c
@@ -0,0 +1,106 @@
 2+/* $Id$
 3+
 4+ Simple database cleanup script, gives out a feed of delete commands to standard output,
 5+ suitable for redirection to tugela cache.
 6+
 7+ TODO: Make it work with network. More run-time tuning params.
 8+
 9+*/
 10+#include <sys/types.h>
 11+#include <sys/time.h>
 12+#include <sys/socket.h>
 13+#include <pwd.h>
 14+#include <fcntl.h>
 15+#include <stdlib.h>
 16+#include <stdio.h>
 17+#include <string.h>
 18+#include <unistd.h>
 19+#include <netinet/in.h>
 20+#include <netinet/tcp.h>
 21+#include <arpa/inet.h>
 22+#include <errno.h>
 23+#include <time.h>
 24+#include <event.h>
 25+#include <db.h>
 26+#include "dbcached.h"
 27+
 28+#define PARTSIZE 40;
 29+
 30+void usage();
 31+
 32+int main(int argc, char **argv)
 33+{
 34+ DB *dbp;
 35+ DBC *dbcp;
 36+ DBT key, data;
 37+ char *dbfile = DBFILE;
 38+ char *prefix = NULL;
 39+ size_t prefixlen = 0;
 40+ int ret;
 41+ item *it;
 42+ time_t oldest = 0;
 43+ time_t now;
 44+ int c;
 45+
 46+ now = time(NULL);
 47+ while ((c = getopt(argc, argv, "f:ho:p:")) != -1) {
 48+ switch (c) {
 49+ case 'f':
 50+ dbfile = optarg;
 51+ break;
 52+ case 'o':
 53+ oldest = now - (86400 * atoi(optarg));
 54+ break;
 55+ case 'p':
 56+ prefix = optarg;
 57+ prefixlen = strlen(prefix);
 58+ break;
 59+ default:
 60+ usage();
 61+ exit(1);
 62+ }
 63+ }
 64+
 65+ db_create(&dbp, NULL, 0);
 66+ if ((ret = dbp->open(dbp, NULL, dbfile, NULL,
 67+ DB_BTREE, DB_RDONLY, 0644)) != 0) {
 68+ dbp->err(dbp, ret, "%s", dbfile);
 69+ exit(1);
 70+ }
 71+
 72+ if ((ret = dbp->cursor(dbp, NULL, &dbcp, 0)) != 0) {
 73+ dbp->err(dbp, ret, "DB->cursor");
 74+ exit(1);
 75+ }
 76+
 77+ memset(&key, 0, sizeof(key));
 78+ memset(&data, 0, sizeof(data));
 79+ data.flags = DB_DBT_PARTIAL;
 80+ data.doff = 0;
 81+ data.dlen = PARTSIZE;
 82+
 83+ while ((ret = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
 84+ it = data.data;
 85+ if (prefix
 86+ && (key.size < prefixlen
 87+ || strncmp(prefix, key.data, prefixlen)))
 88+ continue;
 89+ if ((it->exptime && it->exptime <= now) || it->time < oldest)
 90+ printf("delete %.*s\n",
 91+ (int) key.size, (char *) key.data, it->exptime);
 92+ }
 93+ if (ret != DB_NOTFOUND) {
 94+ dbp->err(dbp, ret, "DBcursor->get");
 95+ exit(1);
 96+ }
 97+ exit(0);
 98+}
 99+
 100+void usage()
 101+{
 102+ printf("-f file database file\n");
 103+ printf("-p prefix key prefix\n");
 104+ printf
 105+ ("-o days remove items older than specified (default: no limit)\n");
 106+
 107+}
Property changes on: tags/tug_0_1/tugelacache/expire.c
___________________________________________________________________
Added: svn:keywords
1108 + Author Date Id Revision
Added: svn:eol-style
2109 + native
Index: tags/tug_0_1/tugelacache/dbcached.c
@@ -0,0 +1,1497 @@
 2+/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
 3+/*
 4+ * dbcached - object store daemon
 5+ *
 6+ * Copyright 2003 Danga Interactive, Inc. All rights reserved.
 7+ * Copyright 2004 Domas Mituzas. All rights reserved.
 8+ *
 9+ * Use and distribution licensed under the BSD license. See
 10+ * the LICENSE file for full text.
 11+ *
 12+ * Authors:
 13+ * Anatoly Vorobey <mellon@pobox.com>
 14+ * Brad Fitzpatrick <brad@danga.com>
 15+ * Domas Mituzas <domas.mituzas@gmail.com>
 16+ *
 17+ * $Id$
 18+ */
 19+
 20+#include "config.h"
 21+#include <sys/types.h>
 22+#include <sys/stat.h>
 23+#include <sys/time.h>
 24+#include <sys/socket.h>
 25+#include <sys/resource.h>
 26+/* some POSIX systems need the following definition
 27+ * to get mlockall flags out of sys/mman.h. */
 28+#ifndef _P1003_1B_VISIBLE
 29+#define _P1003_1B_VISIBLE
 30+#endif
 31+#include <pwd.h>
 32+#include <sys/mman.h>
 33+#include <fcntl.h>
 34+#include <stdlib.h>
 35+#include <stdio.h>
 36+#include <string.h>
 37+#include <unistd.h>
 38+#include <netinet/in.h>
 39+#include <netinet/tcp.h>
 40+#include <arpa/inet.h>
 41+#include <errno.h>
 42+#include <time.h>
 43+#include <event.h>
 44+#include <assert.h>
 45+#include <db.h>
 46+#include <signal.h>
 47+
 48+
 49+#ifdef HAVE_MALLOC_H
 50+#include <malloc.h>
 51+#endif
 52+
 53+#include "dbcached.h"
 54+
 55+struct stats stats;
 56+struct settings settings;
 57+
 58+DB *dbp;
 59+DBT dbkey, dbdata;
 60+
 61+time_t realtime(time_t exptime)
 62+{
 63+ time_t now;
 64+
 65+ /* no. of seconds in 30 days - largest possible delta exptime */
 66+#define REALTIME_MAXDELTA 60*60*24*30
 67+
 68+ if (exptime == 0)
 69+ return 0; /* 0 means never expire */
 70+
 71+ if (exptime > REALTIME_MAXDELTA)
 72+ return exptime;
 73+ else {
 74+ now = time(0);
 75+ return exptime + now;
 76+ }
 77+}
 78+
 79+void stats_init(void)
 80+{
 81+ stats.curr_items = stats.total_items = stats.curr_conns =
 82+ stats.total_conns = stats.conn_structs = 0;
 83+ stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses =
 84+ 0;
 85+ stats.curr_bytes = stats.bytes_read = stats.bytes_written = 0;
 86+ stats.started = time(0);
 87+}
 88+
 89+void stats_reset(void)
 90+{
 91+ stats.total_items = stats.total_conns = 0;
 92+ stats.get_cmds = stats.set_cmds = stats.get_hits = stats.get_misses =
 93+ 0;
 94+ stats.bytes_read = stats.bytes_written = 0;
 95+}
 96+
 97+void settings_init(void)
 98+{
 99+ settings.port = 11211;
 100+ settings.interface.s_addr = htonl(INADDR_ANY);
 101+ settings.maxbytes = 64 * 1024 * 1024; /* default is 64MB */
 102+ settings.maxconns = 1024; /* to limit connections-related memory to about 5MB */
 103+ settings.synctimer = 66;
 104+ settings.verbose = 0;
 105+ settings.oldest_live = 0;
 106+}
 107+
 108+conn **freeconns;
 109+int freetotal;
 110+int freecurr;
 111+
 112+void set_cork(conn * c, int val)
 113+{
 114+ if (c->is_corked == val)
 115+ return;
 116+ c->is_corked = val;
 117+#ifdef TCP_NOPUSH
 118+ setsockopt(c->sfd, IPPROTO_TCP, TCP_NOPUSH, &val, sizeof(val));
 119+#endif
 120+}
 121+
 122+void conn_init(void)
 123+{
 124+ freetotal = 200;
 125+ freecurr = 0;
 126+ freeconns = (conn **) malloc(sizeof(conn *) * freetotal);
 127+ return;
 128+}
 129+
 130+conn *conn_new(int sfd, int init_state, int event_flags)
 131+{
 132+ conn *c;
 133+
 134+ /* do we have a free conn structure from a previous close? */
 135+ if (freecurr > 0) {
 136+ c = freeconns[--freecurr];
 137+ } else { /* allocate a new one */
 138+ if (!(c = (conn *) malloc(sizeof(conn)))) {
 139+ perror("malloc()");
 140+ return 0;
 141+ }
 142+ c->rbuf = c->wbuf = 0;
 143+ c->ilist = 0;
 144+
 145+ c->rbuf = (char *) malloc(DATA_BUFFER_SIZE);
 146+ c->wbuf = (char *) malloc(DATA_BUFFER_SIZE);
 147+ c->ilist = (item **) malloc(sizeof(item *) * 200);
 148+
 149+ if (c->rbuf == 0 || c->wbuf == 0 || c->ilist == 0) {
 150+ if (c->rbuf != 0)
 151+ free(c->rbuf);
 152+ if (c->wbuf != 0)
 153+ free(c->wbuf);
 154+ if (c->ilist != 0)
 155+ free(c->ilist);
 156+ free(c);
 157+ perror("malloc()");
 158+ return 0;
 159+ }
 160+ c->rsize = c->wsize = DATA_BUFFER_SIZE;
 161+ c->isize = 200;
 162+ stats.conn_structs++;
 163+ }
 164+
 165+ if (settings.verbose > 1) {
 166+ if (init_state == conn_listening)
 167+ fprintf(stderr, "<%d server listening\n", sfd);
 168+ else
 169+ fprintf(stderr, "<%d new client connection\n", sfd);
 170+ }
 171+
 172+ c->sfd = sfd;
 173+ c->state = init_state;
 174+ c->rlbytes = 0;
 175+ c->rbytes = c->wbytes = 0;
 176+ c->wcurr = c->wbuf;
 177+ c->rcurr = c->rbuf;
 178+ c->icurr = c->ilist;
 179+ c->ileft = 0;
 180+ c->iptr = c->ibuf;
 181+ c->ibytes = 0;
 182+
 183+ c->write_and_go = conn_read;
 184+ c->write_and_free = 0;
 185+ c->item = 0;
 186+
 187+ c->is_corked = 0;
 188+
 189+ event_set(&c->event, sfd, event_flags, event_handler, (void *) c);
 190+ c->ev_flags = event_flags;
 191+
 192+ if (event_add(&c->event, 0) == -1) {
 193+ free(c);
 194+ return 0;
 195+ }
 196+
 197+ stats.curr_conns++;
 198+ stats.total_conns++;
 199+
 200+ return c;
 201+}
 202+
 203+void conn_close(conn * c)
 204+{
 205+ /* delete the event, the socket and the conn */
 206+ event_del(&c->event);
 207+
 208+ if (settings.verbose > 1)
 209+ fprintf(stderr, "<%d connection closed.\n", c->sfd);
 210+
 211+ close(c->sfd);
 212+
 213+ if (c->item) {
 214+ item_free(c->item);
 215+ }
 216+
 217+ if (c->ileft) {
 218+ for (; c->ileft > 0; c->ileft--, c->icurr++) {
 219+ item_remove(*(c->icurr));
 220+ }
 221+ }
 222+
 223+ if (c->write_and_free) {
 224+ free(c->write_and_free);
 225+ }
 226+
 227+ /* if we have enough space in the free connections array, put the structure there */
 228+ if (freecurr < freetotal) {
 229+ freeconns[freecurr++] = c;
 230+ } else {
 231+ /* try to enlarge free connections array */
 232+ conn **new_freeconns =
 233+ realloc(freeconns, sizeof(conn *) * freetotal * 2);
 234+ if (new_freeconns) {
 235+ freetotal *= 2;
 236+ freeconns = new_freeconns;
 237+ freeconns[freecurr++] = c;
 238+ } else {
 239+ free(c->rbuf);
 240+ free(c->wbuf);
 241+ free(c->ilist);
 242+ free(c);
 243+ }
 244+ }
 245+
 246+ stats.curr_conns--;
 247+
 248+ return;
 249+}
 250+
 251+void out_string(conn * c, char *str)
 252+{
 253+ int len;
 254+
 255+ if (settings.verbose > 1)
 256+ fprintf(stderr, ">%d %s\n", c->sfd, str);
 257+
 258+ len = strlen(str);
 259+ if (len + 2 > c->wsize) {
 260+ /* ought to be always enough. just fail for simplicity */
 261+ str = "SERVER_ERROR output line too long";
 262+ len = strlen(str);
 263+ }
 264+
 265+ strcpy(c->wbuf, str);
 266+ strcat(c->wbuf, "\r\n");
 267+ c->wbytes = len + 2;
 268+ c->wcurr = c->wbuf;
 269+
 270+ c->state = conn_write;
 271+ c->write_and_go = conn_read;
 272+ return;
 273+}
 274+
 275+/*
 276+ * we get here after reading the value in set/add/replace commands. The command
 277+ * has been stored in c->item_comm, and the item is ready in c->item.
 278+ */
 279+
 280+void complete_nread(conn * c)
 281+{
 282+ item *it = c->item, *testit = NULL;
 283+ time_t now;
 284+ int comm = c->item_comm;
 285+ u_int32_t dbflags = 0;
 286+ int ret;
 287+
 288+ stats.set_cmds++;
 289+ now = time(0);
 290+
 291+ while (1) {
 292+ if (strncmp(ITEM_data(it) + it->nbytes - 2, "\r\n", 2) != 0) {
 293+ out_string(c, "CLIENT_ERROR bad data chunk");
 294+ break;
 295+ }
 296+
 297+ cleanup_dbt();
 298+ if (comm == NREAD_ADD || comm == NREAD_REPLACE) {
 299+ dbkey.data = ITEM_key(it);
 300+ dbkey.size = strlen(ITEM_key(it));
 301+ dbkey.dlen = 40;
 302+ if ((ret = dbp->get(dbp, NULL, &dbkey, &dbdata, 0)) == 0) {
 303+ /* old data exists */
 304+ testit = dbdata.data;
 305+ if (testit && testit->exptime && testit->exptime < now) {
 306+ /* expired */
 307+ if (comm == NREAD_REPLACE) {
 308+ /* remove on replace, return */
 309+ dbp->del(dbp, NULL, &dbkey, 0);
 310+ out_string(c, "NOT STORED");
 311+ break;
 312+ }
 313+ } else if (comm == NREAD_ADD) {
 314+ /* don't overwrite not expired data */
 315+ dbflags |= DB_NOOVERWRITE;
 316+ }
 317+ } else if (comm == NREAD_REPLACE) {
 318+ out_string(c, "NOT STORED");
 319+ break;
 320+ }
 321+ }
 322+
 323+ cleanup_dbt();
 324+ dbkey.data = ITEM_key(it);
 325+ dbkey.size = strlen(ITEM_key(it));
 326+ dbdata.data = it;
 327+ dbdata.size = ITEM_ntotal(it);
 328+ if ((ret = dbp->put(dbp, NULL, &dbkey, &dbdata, dbflags)) == 0) {
 329+ /* some future code? */
 330+ out_string(c, "STORED");
 331+
 332+ } else {
 333+ out_string(c, "NOT STORED");
 334+ }
 335+ free(c->item);
 336+ c->item = 0;
 337+ return;
 338+ }
 339+
 340+ item_free(it);
 341+ c->item = 0;
 342+ return;
 343+}
 344+
 345+void process_stat(conn * c, char *command)
 346+{
 347+ time_t now = time(0);
 348+
 349+ if (strcmp(command, "stats") == 0) {
 350+ char temp[1024];
 351+ pid_t pid = getpid();
 352+ char *pos = temp;
 353+ struct rusage usage;
 354+
 355+ getrusage(RUSAGE_SELF, &usage);
 356+
 357+ pos += sprintf(pos, "STAT pid %u\r\n", pid);
 358+ pos += sprintf(pos, "STAT uptime %lu\r\n", now - stats.started);
 359+ pos += sprintf(pos, "STAT time %u\r\n", (unsigned int) now);
 360+ pos += sprintf(pos, "STAT version " VERSION "\r\n");
 361+ pos +=
 362+ sprintf(pos, "STAT rusage_user %u:%u\r\n",
 363+ (unsigned int) usage.ru_utime.tv_sec,
 364+ (unsigned int) usage.ru_utime.tv_usec);
 365+ pos +=
 366+ sprintf(pos, "STAT rusage_system %u:%u\r\n",
 367+ (unsigned int) usage.ru_stime.tv_sec,
 368+ (unsigned int) usage.ru_stime.tv_usec);
 369+ pos += sprintf(pos, "STAT curr_items %u\r\n", stats.curr_items);
 370+ pos += sprintf(pos, "STAT total_items %u\r\n", stats.total_items);
 371+ pos += sprintf(pos, "STAT bytes %llu\r\n", stats.curr_bytes);
 372+ pos += sprintf(pos, "STAT curr_connections %u\r\n", stats.curr_conns - 1); /* ignore listening conn */
 373+ pos +=
 374+ sprintf(pos, "STAT total_connections %u\r\n",
 375+ stats.total_conns);
 376+ pos +=
 377+ sprintf(pos, "STAT connection_structures %u\r\n",
 378+ stats.conn_structs);
 379+ pos += sprintf(pos, "STAT cmd_get %u\r\n", stats.get_cmds);
 380+ pos += sprintf(pos, "STAT cmd_set %u\r\n", stats.set_cmds);
 381+ pos += sprintf(pos, "STAT get_hits %u\r\n", stats.get_hits);
 382+ pos += sprintf(pos, "STAT get_misses %u\r\n", stats.get_misses);
 383+ pos += sprintf(pos, "STAT bytes_read %llu\r\n", stats.bytes_read);
 384+ pos +=
 385+ sprintf(pos, "STAT bytes_written %llu\r\n",
 386+ stats.bytes_written);
 387+ pos +=
 388+ sprintf(pos, "STAT limit_maxbytes %u\r\n", settings.maxbytes);
 389+ pos += sprintf(pos, "END");
 390+ out_string(c, temp);
 391+ return;
 392+ }
 393+
 394+ if (strcmp(command, "stats reset") == 0) {
 395+ stats_reset();
 396+ out_string(c, "RESET");
 397+ return;
 398+ }
 399+#ifdef HAVE_MALLOC_H
 400+#ifdef HAVE_STRUCT_MALLINFO
 401+ if (strcmp(command, "stats malloc") == 0) {
 402+ char temp[512];
 403+ struct mallinfo info;
 404+ char *pos = temp;
 405+
 406+ info = mallinfo();
 407+ pos += sprintf(pos, "STAT arena_size %d\r\n", info.arena);
 408+ pos += sprintf(pos, "STAT free_chunks %d\r\n", info.ordblks);
 409+ pos += sprintf(pos, "STAT fastbin_blocks %d\r\n", info.smblks);
 410+ pos += sprintf(pos, "STAT mmapped_regions %d\r\n", info.hblks);
 411+ pos += sprintf(pos, "STAT mmapped_space %d\r\n", info.hblkhd);
 412+ pos += sprintf(pos, "STAT max_total_alloc %d\r\n", info.usmblks);
 413+ pos += sprintf(pos, "STAT fastbin_space %d\r\n", info.fsmblks);
 414+ pos += sprintf(pos, "STAT total_alloc %d\r\n", info.uordblks);
 415+ pos += sprintf(pos, "STAT total_free %d\r\n", info.fordblks);
 416+ pos +=
 417+ sprintf(pos, "STAT releasable_space %d\r\nEND", info.keepcost);
 418+ out_string(c, temp);
 419+ return;
 420+ }
 421+#endif /* HAVE_STRUCT_MALLINFO */
 422+#endif /* HAVE_MALLOC_H */
 423+
 424+ if (strcmp(command, "stats maps") == 0) {
 425+ char *wbuf;
 426+ int wsize = 8192; /* should be enough */
 427+ int fd;
 428+ int res;
 429+
 430+ wbuf = (char *) malloc(wsize);
 431+ if (wbuf == 0) {
 432+ out_string(c, "SERVER_ERROR out of memory");
 433+ return;
 434+ }
 435+
 436+ fd = open("/proc/self/maps", O_RDONLY);
 437+ if (fd == -1) {
 438+ out_string(c, "SERVER_ERROR cannot open the maps file");
 439+ free(wbuf);
 440+ return;
 441+ }
 442+
 443+ res = read(fd, wbuf, wsize - 6); /* 6 = END\r\n\0 */
 444+ if (res == wsize - 6) {
 445+ out_string(c, "SERVER_ERROR buffer overflow");
 446+ free(wbuf);
 447+ close(fd);
 448+ return;
 449+ }
 450+ if (res == 0 || res == -1) {
 451+ out_string(c, "SERVER_ERROR can't read the maps file");
 452+ free(wbuf);
 453+ close(fd);
 454+ return;
 455+ }
 456+ strcpy(wbuf + res, "END\r\n");
 457+ c->write_and_free = wbuf;
 458+ c->wcurr = wbuf;
 459+ c->wbytes = res + 6;
 460+ c->state = conn_write;
 461+ c->write_and_go = conn_read;
 462+ close(fd);
 463+ return;
 464+ }
 465+
 466+ if (strncmp(command, "stats cachedump", 15) == 0) {
 467+ char *buf;
 468+ unsigned int bytes, id, limit = 0;
 469+ char *start = command + 15;
 470+ if (sscanf(start, "%u %u\r\n", &id, &limit) < 1) {
 471+ out_string(c, "CLIENT_ERROR bad command line");
 472+ return;
 473+ }
 474+
 475+ buf = item_cachedump(id, limit, &bytes);
 476+ if (buf == 0) {
 477+ out_string(c, "SERVER_ERROR out of memory");
 478+ return;
 479+ }
 480+
 481+ c->write_and_free = buf;
 482+ c->wcurr = buf;
 483+ c->wbytes = bytes;
 484+ c->state = conn_write;
 485+ c->write_and_go = conn_read;
 486+ return;
 487+ }
 488+
 489+ if (strcmp(command, "stats sizes") == 0) {
 490+ out_string(c, "SERVER_ERROR unimplemented");
 491+ }
 492+
 493+ out_string(c, "ERROR");
 494+}
 495+
 496+void process_command(conn * c, char *command)
 497+{
 498+
 499+ int comm = 0;
 500+ int incr = 0;
 501+
 502+ /*
 503+ * for commands set/add/replace, we build an item and read the data
 504+ * directly into it, then continue in nread_complete().
 505+ */
 506+
 507+ if (settings.verbose > 1)
 508+ fprintf(stderr, "<%d %s\n", c->sfd, command);
 509+
 510+ /* All incoming commands will require a response, so we cork at the beginning,
 511+ and uncork at the very end (usually by means of out_string) */
 512+ set_cork(c, 1);
 513+
 514+ if ((strncmp(command, "add ", 4) == 0 && (comm = NREAD_ADD)) ||
 515+ (strncmp(command, "set ", 4) == 0 && (comm = NREAD_SET)) ||
 516+ (strncmp(command, "replace ", 8) == 0 && (comm = NREAD_REPLACE))) {
 517+
 518+ char key[251];
 519+ int flags;
 520+ time_t expire;
 521+ int len, res;
 522+ item *it;
 523+
 524+ res =
 525+ sscanf(command, "%*s %250s %u %lu %d\n", key, &flags, &expire,
 526+ &len);
 527+ if (res != 4 || strlen(key) == 0) {
 528+ out_string(c, "CLIENT_ERROR bad command line format");
 529+ return;
 530+ }
 531+ expire = realtime(expire);
 532+ it = item_alloc(key, flags, expire, len + 2);
 533+ if (it == 0) {
 534+ out_string(c, "SERVER_ERROR out of memory");
 535+ /* swallow the data line */
 536+ c->write_and_go = conn_swallow;
 537+ c->sbytes = len + 2;
 538+ return;
 539+ }
 540+
 541+ c->item_comm = comm;
 542+ c->item = it;
 543+ c->rcurr = ITEM_data(it);
 544+ c->rlbytes = it->nbytes;
 545+ c->state = conn_nread;
 546+ return;
 547+ }
 548+
 549+ if ((strncmp(command, "incr ", 5) == 0 && (incr = 1)) ||
 550+ (strncmp(command, "decr ", 5) == 0)) {
 551+ char temp[32];
 552+ unsigned int value;
 553+ item *it, *newit = NULL, *putit = NULL;
 554+ unsigned int delta;
 555+ char key[251];
 556+ int res, ret;
 557+ char *ptr;
 558+
 559+ res = sscanf(command, "%*s %250s %u\n", key, &delta);
 560+ if (res != 2 || strlen(key) == 0) {
 561+ out_string(c, "CLIENT_ERROR bad command line format");
 562+ return;
 563+ }
 564+
 565+ cleanup_dbt();
 566+ dbkey.data = key;
 567+ dbkey.size = strlen(key);
 568+ if ((ret = dbp->get(dbp, NULL, &dbkey, &dbdata, 0)) == 0) {
 569+ it = dbdata.data;
 570+ } else {
 571+ it = 0;
 572+ }
 573+
 574+ if (!it) {
 575+ out_string(c, "NOT_FOUND");
 576+ return;
 577+ }
 578+
 579+ ptr = ITEM_data(it);
 580+ while (*ptr && (*ptr < '0' && *ptr > '9'))
 581+ ptr++;
 582+
 583+ value = atoi(ptr);
 584+
 585+ if (incr)
 586+ value += delta;
 587+ else {
 588+ if (delta >= value)
 589+ value = 0;
 590+ else
 591+ value -= delta;
 592+ }
 593+
 594+ sprintf(temp, "%u", value);
 595+ res = strlen(temp);
 596+ it->time=time(0);
 597+ if (res + 2 > it->nbytes) {
 598+ newit =
 599+ item_alloc(ITEM_key(it), it->flags, it->exptime, res + 2);
 600+ memcpy(ITEM_data(newit), temp, res);
 601+ memcpy(ITEM_data(newit) + res, "\r\n", 2);
 602+ putit = newit;
 603+ } else {
 604+ memcpy(ITEM_data(it), temp, res);
 605+ memset(ITEM_data(it) + res, ' ', it->nbytes - res - 2);
 606+ putit = it;
 607+ }
 608+ cleanup_dbt();
 609+ dbkey.data = key;
 610+ dbkey.size = strlen(key);
 611+ dbdata.data = putit;
 612+ dbdata.size = ITEM_ntotal(putit);
 613+ dbp->put(dbp, NULL, &dbkey, &dbdata, 0);
 614+ if (newit)
 615+ free(newit);
 616+ out_string(c, temp);
 617+ return;
 618+ }
 619+
 620+ if (strncmp(command, "get ", 4) == 0) {
 621+
 622+ char *start = command + 4;
 623+ char key[251];
 624+ int next;
 625+ int i = 0;
 626+ int ret;
 627+ item *it;
 628+ time_t now = time(0);
 629+
 630+ while (sscanf(start, " %250s%n", key, &next) >= 1) {
 631+ start += next;
 632+ stats.get_cmds++;
 633+ cleanup_dbt();
 634+ dbkey.data = key;
 635+ dbkey.size = strlen(key);
 636+ dbdata.flags |= DB_DBT_MALLOC;
 637+ if ((ret = dbp->get(dbp, NULL, &dbkey, &dbdata, 0)) == 0) {
 638+ it = dbdata.data;
 639+ } else {
 640+ it = 0;
 641+ }
 642+ if (settings.oldest_live && it &&
 643+ it->time <= settings.oldest_live) {
 644+ dbp->del(dbp, NULL, &dbkey, 0);
 645+ free(it);
 646+ it = 0;
 647+ }
 648+ if (it && it->exptime && it->exptime < now) {
 649+ dbp->del(dbp, NULL, &dbkey, 0);
 650+ free(it);
 651+ it = 0;
 652+ }
 653+ if (it) {
 654+ stats.get_hits++;
 655+ it->refcount++;
 656+ *(c->ilist + i) = it;
 657+ i++;
 658+ if (i > c->isize) {
 659+ c->isize *= 2;
 660+ c->ilist =
 661+ realloc(c->ilist, sizeof(item *) * c->isize);
 662+ }
 663+ } else
 664+ stats.get_misses++;
 665+ }
 666+ c->icurr = c->ilist;
 667+ c->ileft = i;
 668+ if (c->ileft) {
 669+ c->ipart = 0;
 670+ c->state = conn_mwrite;
 671+ c->ibytes = 0;
 672+ return;
 673+ } else {
 674+ out_string(c, "END");
 675+ return;
 676+ }
 677+ }
 678+
 679+ if (strncmp(command, "delete ", 7) == 0) {
 680+ char key[251];
 681+ int res;
 682+ int ret;
 683+ time_t exptime = 0;
 684+
 685+ res = sscanf(command, "%*s %250s %d", key, (int *) &exptime);
 686+ cleanup_dbt();
 687+ dbkey.data = key;
 688+ dbkey.size = strlen(key);
 689+ if ((ret = dbp->del(dbp, NULL, &dbkey, 0)) == 0) {
 690+ out_string(c, "DELETED");
 691+ } else {
 692+ out_string(c, "NOT_FOUND");
 693+ }
 694+ return;
 695+ }
 696+
 697+ if (strncmp(command, "stats", 5) == 0) {
 698+ process_stat(c, command);
 699+ return;
 700+ }
 701+
 702+ if (strcmp(command, "flush_all") == 0) {
 703+ settings.oldest_live = time(0);
 704+ out_string(c, "OK");
 705+ return;
 706+ }
 707+
 708+ if (strcmp(command, "version") == 0) {
 709+ out_string(c, "VERSION " VERSION);
 710+ return;
 711+ }
 712+
 713+ if (strcmp(command, "sync") == 0) {
 714+ dbp->sync(dbp, 0);
 715+ out_string(c, "OK");
 716+ return;
 717+ }
 718+
 719+ if (strcmp(command, "quit") == 0) {
 720+ c->state = conn_closing;
 721+ return;
 722+ }
 723+
 724+ out_string(c, "ERROR");
 725+ return;
 726+}
 727+
 728+/*
 729+ * if we have a complete line in the buffer, process it and move whatever
 730+ * remains in the buffer to its beginning.
 731+ */
 732+int try_read_command(conn * c)
 733+{
 734+ char *el, *cont;
 735+
 736+ if (!c->rbytes)
 737+ return 0;
 738+ el = memchr(c->rbuf, '\n', c->rbytes);
 739+ if (!el)
 740+ return 0;
 741+ cont = el + 1;
 742+ if (el - c->rbuf > 1 && *(el - 1) == '\r') {
 743+ el--;
 744+ }
 745+ *el = '\0';
 746+
 747+ process_command(c, c->rbuf);
 748+
 749+ if (cont - c->rbuf < c->rbytes) { /* more stuff in the buffer */
 750+ memmove(c->rbuf, cont, c->rbytes - (cont - c->rbuf));
 751+ }
 752+ c->rbytes -= (cont - c->rbuf);
 753+ return 1;
 754+}
 755+
 756+/*
 757+ * read from network as much as we can, handle buffer overflow and connection
 758+ * close.
 759+ * return 0 if there's nothing to read on the first read.
 760+ */
 761+int try_read_network(conn * c)
 762+{
 763+ int gotdata = 0;
 764+ int res;
 765+ while (1) {
 766+ if (c->rbytes >= c->rsize) {
 767+ char *new_rbuf = realloc(c->rbuf, c->rsize * 2);
 768+ if (!new_rbuf) {
 769+ if (settings.verbose > 0)
 770+ fprintf(stderr, "Couldn't realloc input buffer\n");
 771+ c->rbytes = 0; /* ignore what we read */
 772+ out_string(c, "SERVER_ERROR out of memory");
 773+ c->write_and_go = conn_closing;
 774+ return 1;
 775+ }
 776+ c->rbuf = new_rbuf;
 777+ c->rsize *= 2;
 778+ }
 779+ res = read(c->sfd, c->rbuf + c->rbytes, c->rsize - c->rbytes);
 780+ if (res > 0) {
 781+ stats.bytes_read += res;
 782+ gotdata = 1;
 783+ c->rbytes += res;
 784+ continue;
 785+ }
 786+ if (res == 0) {
 787+ /* connection closed */
 788+ c->state = conn_closing;
 789+ return 1;
 790+ }
 791+ if (res == -1) {
 792+ if (errno == EAGAIN || errno == EWOULDBLOCK)
 793+ break;
 794+ else
 795+ return 0;
 796+ }
 797+ }
 798+ return gotdata;
 799+}
 800+
 801+int update_event(conn * c, int new_flags)
 802+{
 803+ if (c->ev_flags == new_flags)
 804+ return 1;
 805+ if (event_del(&c->event) == -1)
 806+ return 0;
 807+ event_set(&c->event, c->sfd, new_flags, event_handler, (void *) c);
 808+ c->ev_flags = new_flags;
 809+ if (event_add(&c->event, 0) == -1)
 810+ return 0;
 811+ return 1;
 812+}
 813+
 814+void drive_machine(conn * c)
 815+{
 816+
 817+ int exit = 0;
 818+ int sfd, flags = 1;
 819+ socklen_t addrlen;
 820+ struct sockaddr addr;
 821+ conn *newc;
 822+ int res;
 823+
 824+ while (!exit) {
 825+ /* printf("state %d\n", c->state); */
 826+ switch (c->state) {
 827+ case conn_listening:
 828+ addrlen = sizeof(addr);
 829+ if ((sfd = accept(c->sfd, &addr, &addrlen)) == -1) {
 830+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
 831+ exit = 1;
 832+ break;
 833+ } else {
 834+ perror("accept()");
 835+ }
 836+ break;
 837+ }
 838+ if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
 839+ fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
 840+ perror("setting O_NONBLOCK");
 841+ close(sfd);
 842+ break;
 843+ }
 844+ newc = conn_new(sfd, conn_read, EV_READ | EV_PERSIST);
 845+ if (!newc) {
 846+ if (settings.verbose > 0)
 847+ fprintf(stderr, "couldn't create new connection\n");
 848+ close(sfd);
 849+ break;
 850+ }
 851+
 852+ break;
 853+
 854+ case conn_read:
 855+ if (try_read_command(c)) {
 856+ continue;
 857+ }
 858+ if (try_read_network(c)) {
 859+ continue;
 860+ }
 861+ /* we have no command line and no data to read from network */
 862+ if (!update_event(c, EV_READ | EV_PERSIST)) {
 863+ if (settings.verbose > 0)
 864+ fprintf(stderr, "Couldn't update event\n");
 865+ c->state = conn_closing;
 866+ break;
 867+ }
 868+ exit = 1;
 869+ break;
 870+
 871+ case conn_nread:
 872+ /* we are reading rlbytes into rcurr; */
 873+ if (c->rlbytes == 0) {
 874+ complete_nread(c);
 875+ break;
 876+ }
 877+ /* first check if we have leftovers in the conn_read buffer */
 878+ if (c->rbytes > 0) {
 879+ int tocopy =
 880+ c->rbytes > c->rlbytes ? c->rlbytes : c->rbytes;
 881+ memcpy(c->rcurr, c->rbuf, tocopy);
 882+ c->rcurr += tocopy;
 883+ c->rlbytes -= tocopy;
 884+ if (c->rbytes > tocopy) {
 885+ memmove(c->rbuf, c->rbuf + tocopy, c->rbytes - tocopy);
 886+ }
 887+ c->rbytes -= tocopy;
 888+ break;
 889+ }
 890+
 891+ /* now try reading from the socket */
 892+ res = read(c->sfd, c->rcurr, c->rlbytes);
 893+ if (res > 0) {
 894+ stats.bytes_read += res;
 895+ c->rcurr += res;
 896+ c->rlbytes -= res;
 897+ break;
 898+ }
 899+ if (res == 0) { /* end of stream */
 900+ c->state = conn_closing;
 901+ break;
 902+ }
 903+ if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 904+ if (!update_event(c, EV_READ | EV_PERSIST)) {
 905+ if (settings.verbose > 0)
 906+ fprintf(stderr, "Couldn't update event\n");
 907+ c->state = conn_closing;
 908+ break;
 909+ }
 910+ exit = 1;
 911+ break;
 912+ }
 913+ /* otherwise we have a real error, on which we close the connection */
 914+ if (settings.verbose > 0)
 915+ fprintf(stderr,
 916+ "Failed to read, and not due to blocking\n");
 917+ c->state = conn_closing;
 918+ break;
 919+
 920+ case conn_swallow:
 921+ /* we are reading sbytes and throwing them away */
 922+ if (c->sbytes == 0) {
 923+ c->state = conn_read;
 924+ break;
 925+ }
 926+
 927+ /* first check if we have leftovers in the conn_read buffer */
 928+ if (c->rbytes > 0) {
 929+ int tocopy = c->rbytes > c->sbytes ? c->sbytes : c->rbytes;
 930+ c->sbytes -= tocopy;
 931+ if (c->rbytes > tocopy) {
 932+ memmove(c->rbuf, c->rbuf + tocopy, c->rbytes - tocopy);
 933+ }
 934+ c->rbytes -= tocopy;
 935+ break;
 936+ }
 937+
 938+ /* now try reading from the socket */
 939+ res =
 940+ read(c->sfd, c->rbuf,
 941+ c->rsize > c->sbytes ? c->sbytes : c->rsize);
 942+ if (res > 0) {
 943+ stats.bytes_read += res;
 944+ c->sbytes -= res;
 945+ break;
 946+ }
 947+ if (res == 0) { /* end of stream */
 948+ c->state = conn_closing;
 949+ break;
 950+ }
 951+ if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 952+ if (!update_event(c, EV_READ | EV_PERSIST)) {
 953+ if (settings.verbose > 0)
 954+ fprintf(stderr, "Couldn't update event\n");
 955+ c->state = conn_closing;
 956+ break;
 957+ }
 958+ exit = 1;
 959+ break;
 960+ }
 961+ /* otherwise we have a real error, on which we close the connection */
 962+ if (settings.verbose > 0)
 963+ fprintf(stderr,
 964+ "Failed to read, and not due to blocking\n");
 965+ c->state = conn_closing;
 966+ break;
 967+
 968+ case conn_write:
 969+ /* we are writing wbytes bytes starting from wcurr */
 970+ if (c->wbytes == 0) {
 971+ if (c->write_and_free) {
 972+ free(c->write_and_free);
 973+ c->write_and_free = 0;
 974+ }
 975+ c->state = c->write_and_go;
 976+ if (c->state == conn_read)
 977+ set_cork(c, 0);
 978+ break;
 979+ }
 980+ res = write(c->sfd, c->wcurr, c->wbytes);
 981+ if (res > 0) {
 982+ stats.bytes_written += res;
 983+ c->wcurr += res;
 984+ c->wbytes -= res;
 985+ break;
 986+ }
 987+ if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 988+ if (!update_event(c, EV_WRITE | EV_PERSIST)) {
 989+ if (settings.verbose > 0)
 990+ fprintf(stderr, "Couldn't update event\n");
 991+ c->state = conn_closing;
 992+ break;
 993+ }
 994+ exit = 1;
 995+ break;
 996+ }
 997+ /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK,
 998+ we have a real error, on which we close the connection */
 999+ if (settings.verbose > 0)
 1000+ fprintf(stderr,
 1001+ "Failed to write, and not due to blocking\n");
 1002+ c->state = conn_closing;
 1003+ break;
 1004+ case conn_mwrite:
 1005+ /*
 1006+ * we're writing ibytes bytes from iptr. iptr alternates between
 1007+ * ibuf, where we build a string "VALUE...", and ITEM_data(it) for the
 1008+ * current item. When we finish a chunk, we choose the next one using
 1009+ * ipart, which has the following semantics: 0 - start the loop, 1 -
 1010+ * we finished ibuf, go to current ITEM_data(it); 2 - we finished ITEM_data(it),
 1011+ * move to the next item and build its ibuf; 3 - we finished all items,
 1012+ * write "END".
 1013+ */
 1014+ if (c->ibytes > 0) {
 1015+ res = write(c->sfd, c->iptr, c->ibytes);
 1016+ if (res > 0) {
 1017+ stats.bytes_written += res;
 1018+ c->iptr += res;
 1019+ c->ibytes -= res;
 1020+ break;
 1021+ }
 1022+ if (res == -1 && (errno == EAGAIN || errno == EWOULDBLOCK)) {
 1023+ if (!update_event(c, EV_WRITE | EV_PERSIST)) {
 1024+ if (settings.verbose > 0)
 1025+ fprintf(stderr, "Couldn't update event\n");
 1026+ c->state = conn_closing;
 1027+ break;
 1028+ }
 1029+ exit = 1;
 1030+ break;
 1031+ }
 1032+ /* if res==0 or res==-1 and error is not EAGAIN or EWOULDBLOCK,
 1033+ we have a real error, on which we close the connection */
 1034+ if (settings.verbose > 0)
 1035+ fprintf(stderr,
 1036+ "Failed to write, and not due to blocking\n");
 1037+ c->state = conn_closing;
 1038+ break;
 1039+ } else {
 1040+ item *it;
 1041+ /* we finished a chunk, decide what to do next */
 1042+ switch (c->ipart) {
 1043+ case 1:
 1044+ it = *(c->icurr);
 1045+ assert((it->it_flags & ITEM_SLABBED) == 0);
 1046+ c->iptr = ITEM_data(it);
 1047+ c->ibytes = it->nbytes;
 1048+ c->ipart = 2;
 1049+ break;
 1050+ case 2:
 1051+ it = *(c->icurr);
 1052+ free(it);
 1053+ c->ileft--;
 1054+ if (c->ileft <= 0) {
 1055+ c->ipart = 3;
 1056+ break;
 1057+ } else {
 1058+ c->icurr++;
 1059+ }
 1060+ /* FALL THROUGH */
 1061+ case 0:
 1062+ it = *(c->icurr);
 1063+ sprintf(c->ibuf, "VALUE %s %u %u\r\n", ITEM_key(it),
 1064+ it->flags, it->nbytes - 2);
 1065+ if (settings.verbose > 1)
 1066+ fprintf(stderr, ">%d sending key %s\n", c->sfd,
 1067+ ITEM_key(it));
 1068+ c->iptr = c->ibuf;
 1069+ c->ibytes = strlen(c->iptr);
 1070+ c->ipart = 1;
 1071+ break;
 1072+ case 3:
 1073+ out_string(c, "END");
 1074+ break;
 1075+ }
 1076+ }
 1077+ break;
 1078+
 1079+ case conn_closing:
 1080+ conn_close(c);
 1081+ exit = 1;
 1082+ break;
 1083+ }
 1084+
 1085+ }
 1086+
 1087+ return;
 1088+}
 1089+
 1090+
 1091+void event_handler(int fd, short which, void *arg)
 1092+{
 1093+ conn *c;
 1094+
 1095+ c = (conn *) arg;
 1096+ c->which = which;
 1097+
 1098+ /* sanity */
 1099+ if (fd != c->sfd) {
 1100+ if (settings.verbose > 0)
 1101+ fprintf(stderr,
 1102+ "Catastrophic: event fd doesn't match conn fd!\n");
 1103+ conn_close(c);
 1104+ return;
 1105+ }
 1106+
 1107+ /* do as much I/O as possible until we block */
 1108+ drive_machine(c);
 1109+
 1110+ /* wait for next event */
 1111+ return;
 1112+}
 1113+
 1114+int new_socket(void)
 1115+{
 1116+ int sfd;
 1117+ int flags;
 1118+
 1119+ if ((sfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
 1120+ perror("socket()");
 1121+ return -1;
 1122+ }
 1123+
 1124+ if ((flags = fcntl(sfd, F_GETFL, 0)) < 0 ||
 1125+ fcntl(sfd, F_SETFL, flags | O_NONBLOCK) < 0) {
 1126+ perror("setting O_NONBLOCK");
 1127+ close(sfd);
 1128+ return -1;
 1129+ }
 1130+ return sfd;
 1131+}
 1132+
 1133+int server_socket(int port)
 1134+{
 1135+ int sfd;
 1136+ struct linger ling = { 0, 0 };
 1137+ struct sockaddr_in addr;
 1138+ int flags = 1;
 1139+
 1140+ if ((sfd = new_socket()) == -1) {
 1141+ return -1;
 1142+ }
 1143+
 1144+ setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &flags, sizeof(flags));
 1145+ setsockopt(sfd, SOL_SOCKET, SO_KEEPALIVE, &flags, sizeof(flags));
 1146+ setsockopt(sfd, SOL_SOCKET, SO_LINGER, &ling, sizeof(ling));
 1147+#if !defined(TCP_NOPUSH)
 1148+ setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, &flags, sizeof(flags));
 1149+#endif
 1150+
 1151+ addr.sin_family = AF_INET;
 1152+ addr.sin_port = htons(port);
 1153+ addr.sin_addr = settings.interface;
 1154+ if (bind(sfd, (struct sockaddr *) &addr, sizeof(addr)) == -1) {
 1155+ perror("bind()");
 1156+ close(sfd);
 1157+ return -1;
 1158+ }
 1159+ if (listen(sfd, 1024) == -1) {
 1160+ perror("listen()");
 1161+ close(sfd);
 1162+ return -1;
 1163+ }
 1164+ return sfd;
 1165+}
 1166+
 1167+/* invoke right before gdb is called, on assert */
 1168+void pre_gdb()
 1169+{
 1170+ int i = 0;
 1171+ if (l_socket)
 1172+ close(l_socket);
 1173+ for (i = 3; i <= 500; i++)
 1174+ close(i); /* so lame */
 1175+ kill(getpid(), SIGABRT);
 1176+}
 1177+
 1178+struct event syncevent;
 1179+
 1180+void sync_handler(int fd, short which, void *arg)
 1181+{
 1182+ struct timeval t;
 1183+
 1184+ evtimer_del(&syncevent);
 1185+ evtimer_set(&syncevent, sync_handler, 0);
 1186+ t.tv_sec = settings.synctimer;
 1187+ t.tv_usec = 0;
 1188+ evtimer_add(&syncevent, &t);
 1189+ dbp->sync(dbp, 0);
 1190+ return;
 1191+}
 1192+
 1193+void usage(void)
 1194+{
 1195+ printf(PACKAGE " " VERSION "\n");
 1196+ printf("-p <num> port number to listen on\n");
 1197+ printf("-l <ip_addr> interface to listen on, default is INDRR_ANY\n");
 1198+ printf("-d run as a daemon\n");
 1199+ printf("-r maximize core file limit\n");
 1200+ printf
 1201+ ("-u <username> assume identity of <username> (only when run as root)\n");
 1202+ printf
 1203+ ("-m <num> cache memory to use for items in megabytes, default is 64 MB\n");
 1204+ printf
 1205+ ("-c <num> max simultaneous connections, default is 1024\n");
 1206+ printf("-f <file filename of database\n");
 1207+ printf("-s <num> sync this often seconds\n");
 1208+ printf
 1209+ ("-v verbose (print errors/warnings while in event loop)\n");
 1210+ printf
 1211+ ("-vv very verbose (also print client commands/reponses)\n");
 1212+ printf("-h print this help and exit\n");
 1213+ printf("-i print dbcached and libevent license\n");
 1214+ return;
 1215+}
 1216+
 1217+void usage_license(void)
 1218+{
 1219+ printf(PACKAGE " " VERSION "\n\n");
 1220+ printf
 1221+ ("Copyright (c) 2003, Danga Interactive, Inc. <http://www.danga.com/>\n"
 1222+ "All rights reserved.\n" "\n"
 1223+ "Redistribution and use in source and binary forms, with or without\n"
 1224+ "modification, are permitted provided that the following conditions are\n"
 1225+ "met:\n" "\n"
 1226+ " * Redistributions of source code must retain the above copyright\n"
 1227+ "notice, this list of conditions and the following disclaimer.\n"
 1228+ "\n"
 1229+ " * Redistributions in binary form must reproduce the above\n"
 1230+ "copyright notice, this list of conditions and the following disclaimer\n"
 1231+ "in the documentation and/or other materials provided with the\n"
 1232+ "distribution.\n" "\n"
 1233+ " * Neither the name of the Danga Interactive nor the names of its\n"
 1234+ "contributors may be used to endorse or promote products derived from\n"
 1235+ "this software without specific prior written permission.\n" "\n"
 1236+ "THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
 1237+ "\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
 1238+ "LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
 1239+ "A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
 1240+ "OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
 1241+ "SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
 1242+ "LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
 1243+ "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
 1244+ "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
 1245+ "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
 1246+ "OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
 1247+ "\n" "\n"
 1248+ "This product includes software developed by Niels Provos.\n" "\n"
 1249+ "[ libevent ]\n" "\n"
 1250+ "Copyright 2000-2003 Niels Provos <provos@citi.umich.edu>\n"
 1251+ "All rights reserved.\n" "\n"
 1252+ "Redistribution and use in source and binary forms, with or without\n"
 1253+ "modification, are permitted provided that the following conditions\n"
 1254+ "are met:\n"
 1255+ "1. Redistributions of source code must retain the above copyright\n"
 1256+ " notice, this list of conditions and the following disclaimer.\n"
 1257+ "2. Redistributions in binary form must reproduce the above copyright\n"
 1258+ " notice, this list of conditions and the following disclaimer in the\n"
 1259+ " documentation and/or other materials provided with the distribution.\n"
 1260+ "3. All advertising materials mentioning features or use of this software\n"
 1261+ " must display the following acknowledgement:\n"
 1262+ " This product includes software developed by Niels Provos.\n"
 1263+ "4. The name of the author may not be used to endorse or promote products\n"
 1264+ " derived from this software without specific prior written permission.\n"
 1265+ "\n"
 1266+ "THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR\n"
 1267+ "IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n"
 1268+ "OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\n"
 1269+ "IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,\n"
 1270+ "INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n"
 1271+ "NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
 1272+ "DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
 1273+ "THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
 1274+ "(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\n"
 1275+ "THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n");
 1276+
 1277+ return;
 1278+}
 1279+
 1280+int l_socket = 0;
 1281+
 1282+int main(int argc, char **argv)
 1283+{
 1284+ int c;
 1285+ conn *l_conn;
 1286+ struct in_addr addr;
 1287+ char *dbfile = DBFILE;
 1288+ int daemonize = 0;
 1289+ int maxcore = 0;
 1290+ char *username = 0;
 1291+ struct passwd *pw;
 1292+ struct sigaction sa;
 1293+ struct rlimit rlim;
 1294+ int ret;
 1295+
 1296+ /* init settings */
 1297+ settings_init();
 1298+
 1299+ /* process arguments */
 1300+ while ((c = getopt(argc, argv, "p:m:Mc:khirvdl:u:f:s:")) != -1) {
 1301+ switch (c) {
 1302+ case 'p':
 1303+ settings.port = atoi(optarg);
 1304+ break;
 1305+ case 'm':
 1306+ settings.maxbytes = atoi(optarg) * 1024 * 1024;
 1307+ break;
 1308+ case 'c':
 1309+ settings.maxconns = atoi(optarg);
 1310+ break;
 1311+ case 'h':
 1312+ usage();
 1313+ exit(0);
 1314+ case 's':
 1315+ settings.synctimer = atoi(optarg);
 1316+ break;
 1317+ case 'i':
 1318+ usage_license();
 1319+ exit(0);
 1320+ case 'f':
 1321+ dbfile = optarg;
 1322+ case 'v':
 1323+ settings.verbose++;
 1324+ break;
 1325+ case 'l':
 1326+ if (!inet_aton(optarg, &addr)) {
 1327+ fprintf(stderr, "Illegal address: %s\n", optarg);
 1328+ return 1;
 1329+ } else {
 1330+ settings.interface = addr;
 1331+ }
 1332+ break;
 1333+ case 'd':
 1334+ daemonize = 1;
 1335+ break;
 1336+ case 'r':
 1337+ maxcore = 1;
 1338+ break;
 1339+ case 'u':
 1340+ username = optarg;
 1341+ break;
 1342+ default:
 1343+ fprintf(stderr, "Illegal argument \"%c\"\n", c);
 1344+ return 1;
 1345+ }
 1346+ }
 1347+
 1348+ if (maxcore) {
 1349+ struct rlimit rlim_new;
 1350+ /*
 1351+ * First try raising to infinity; if that fails, try bringing
 1352+ * the soft limit to the hard.
 1353+ */
 1354+ if (getrlimit(RLIMIT_CORE, &rlim) == 0) {
 1355+ rlim_new.rlim_cur = rlim_new.rlim_max = RLIM_INFINITY;
 1356+ if (setrlimit(RLIMIT_CORE, &rlim_new) != 0) {
 1357+ /* failed. try raising just to the old max */
 1358+ rlim_new.rlim_cur = rlim_new.rlim_max = rlim.rlim_max;
 1359+ (void) setrlimit(RLIMIT_CORE, &rlim_new);
 1360+ }
 1361+ }
 1362+ /*
 1363+ * getrlimit again to see what we ended up with. Only fail if
 1364+ * the soft limit ends up 0, because then no core files will be
 1365+ * created at all.
 1366+ */
 1367+
 1368+ if ((getrlimit(RLIMIT_CORE, &rlim) != 0) || rlim.rlim_cur == 0) {
 1369+ fprintf(stderr, "failed to ensure corefile creation\n");
 1370+ exit(1);
 1371+ }
 1372+ }
 1373+
 1374+ /*
 1375+ * If needed, increase rlimits to allow as many connections
 1376+ * as needed.
 1377+ */
 1378+
 1379+ if (getrlimit(RLIMIT_NOFILE, &rlim) != 0) {
 1380+ fprintf(stderr, "failed to getrlimit number of files\n");
 1381+ exit(1);
 1382+ } else {
 1383+ int maxfiles = settings.maxconns;
 1384+ if (rlim.rlim_cur < maxfiles)
 1385+ rlim.rlim_cur = maxfiles + 3;
 1386+ if (rlim.rlim_max < rlim.rlim_cur)
 1387+ rlim.rlim_max = rlim.rlim_cur;
 1388+ if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
 1389+ fprintf(stderr,
 1390+ "failed to set rlimit for open files. Try running as root or requesting smaller maxconns value.\n");
 1391+ exit(1);
 1392+ }
 1393+ }
 1394+
 1395+ /*
 1396+ * initialization order: first create the listening socket
 1397+ * (may need root on low ports), then drop root if needed,
 1398+ * then daemonise if needed, then init libevent (in some cases
 1399+ * descriptors created by libevent wouldn't survive forking).
 1400+ */
 1401+
 1402+ if ((ret = db_create(&dbp, NULL, 0)) != 0) {
 1403+ fprintf(stderr, "db_create: %s\n", db_strerror(ret));
 1404+ exit(1);
 1405+ }
 1406+ dbp->set_cachesize(dbp, 0, settings.maxbytes, 0);
 1407+
 1408+ if ((ret = dbp->open(dbp,
 1409+ NULL, dbfile, NULL, DB_BTREE, DB_CREATE,
 1410+ 0664)) != 0) {
 1411+ dbp->err(dbp, ret, "%s", dbfile);
 1412+ exit(1);
 1413+ }
 1414+
 1415+ atexit(syncdb);
 1416+
 1417+ /* create the listening socket and bind it */
 1418+ l_socket = server_socket(settings.port);
 1419+ if (l_socket == -1) {
 1420+ fprintf(stderr, "failed to listen\n");
 1421+ exit(1);
 1422+ }
 1423+
 1424+ /* lose root privileges if we have them */
 1425+ if (getuid() == 0 || geteuid() == 0) {
 1426+ if (username == 0 || *username == '\0') {
 1427+ fprintf(stderr, "can't run as root without the -u switch\n");
 1428+ return 1;
 1429+ }
 1430+ if ((pw = getpwnam(username)) == 0) {
 1431+ fprintf(stderr, "can't find the user %s to switch to\n",
 1432+ username);
 1433+ return 1;
 1434+ }
 1435+ if (setgid(pw->pw_gid) < 0 || setuid(pw->pw_uid) < 0) {
 1436+ fprintf(stderr, "failed to assume identity of user %s\n",
 1437+ username);
 1438+ return 1;
 1439+ }
 1440+ }
 1441+
 1442+ /* daemonize if requested */
 1443+ /* if we want to ensure our ability to dump core, don't chdir to / */
 1444+ if (daemonize) {
 1445+ int res;
 1446+ res = daemon(maxcore, settings.verbose);
 1447+ if (res == -1) {
 1448+ fprintf(stderr, "failed to daemon() in order to daemonize\n");
 1449+ return 1;
 1450+ }
 1451+ }
 1452+
 1453+
 1454+ /* initialize other stuff */
 1455+ item_init();
 1456+ event_init();
 1457+ stats_init();
 1458+ assoc_init();
 1459+ conn_init();
 1460+
 1461+ /*
 1462+ * ignore SIGPIPE signals; we can use errno==EPIPE if we
 1463+ * need that information
 1464+ */
 1465+ sa.sa_handler = SIG_IGN;
 1466+ sa.sa_flags = 0;
 1467+ if (sigemptyset(&sa.sa_mask) == -1 || sigaction(SIGPIPE, &sa, 0) == -1) {
 1468+ perror("failed to ignore SIGPIPE; sigaction");
 1469+ exit(1);
 1470+ }
 1471+
 1472+ /* create the initial listening connection */
 1473+ if (!
 1474+ (l_conn =
 1475+ conn_new(l_socket, conn_listening, EV_READ | EV_PERSIST))) {
 1476+ fprintf(stderr, "failed to create listening connection");
 1477+ exit(1);
 1478+ }
 1479+
 1480+ /* initialise deletion array and timer event */
 1481+ sync_handler(0, 0, 0); /* sets up the event */
 1482+
 1483+ /* enter the loop */
 1484+ event_loop(0);
 1485+
 1486+ return 0;
 1487+}
 1488+
 1489+void cleanup_dbt()
 1490+{
 1491+ memset(&dbkey, 0, sizeof(dbkey));
 1492+ memset(&dbdata, 0, sizeof(dbdata));
 1493+}
 1494+
 1495+void syncdb()
 1496+{
 1497+ dbp->sync(dbp, 0);
 1498+}
Property changes on: tags/tug_0_1/tugelacache/dbcached.c
___________________________________________________________________
Added: svn:keywords
11499 + Author Date Id Revision
Added: svn:eol-style
21500 + native
Property changes on: tags/tug_0_1/tugelacache
___________________________________________________________________
Added: svn:ignore
31501 + *~
*.o
tugela
dbcache
tugela-expire

Status & tagging log