├── TODO ├── doc ├── Makefile.am ├── rget.txt ├── Makefile.in └── protocol.txt ├── tools ├── Makefile.am ├── mdbtest.py ├── mdbtop.py ├── mcben.py └── Makefile.in ├── conf ├── Makefile.am ├── DB_CONFIG.example └── Makefile.in ├── AUTHORS ├── autogen.sh ├── run.sh ├── Makefile.am ├── CREDITS ├── README ├── INSTALL ├── stats.c ├── config.h.in ├── compile ├── mdbaux.c ├── configure.ac ├── LICENSE ├── item.c ├── ChangeLog ├── memcachedb.h ├── missing ├── thread.c ├── install-sh ├── depcomp └── Makefile.in /TODO: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = *.txt 2 | -------------------------------------------------------------------------------- /tools/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = *.py 2 | -------------------------------------------------------------------------------- /conf/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = DB_CONFIG.example 2 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Howard Chu 2 | Steve Chu 3 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | 4 | echo "autoreconf --install" 5 | autoreconf --install 6 | -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ./memcachedb -p21201 -d -r -H ./testenv -N -E -v >log 2>&1 4 | #./memcachedb -p21201 -d -r -H ./testenv0 -N -R 127.0.0.1:31201 -M -n 2 -v >log_m 2>&1 5 | #sleep 5 6 | #./memcachedb -p21202 -d -r -H ./testenv1 -N -R 127.0.0.1:31202 -O 127.0.0.1:31201 -S -n 2 -v >log_s 2>&1 7 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | bin_PROGRAMS = memcachedb 2 | memcachedb_SOURCES = memcachedb.c item.c memcachedb.h thread.c mdbaux.c stats.c 3 | 4 | SUBDIRS = doc tools conf 5 | EXTRA_DIST = doc tools conf CREDITS AUTHORS LICENSE 6 | 7 | dist-hook: 8 | rm -rf $(distdir)/doc/.svn/ 9 | rm -rf $(distdir)/tools/.svn/ 10 | rm -rf $(distdir)/conf/.svn/ 11 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | Special thanks go to people who have volunteered their time, effort, 2 | and ideas to make this software available. (Words quoted from squid) 3 | 4 | * Great Memcached community! The code of memcachedb is most based on 5 | Memcached . Memcachedb 1.0.x is 6 | based on Memcached 1.2.x, and the preview version 0.1.x is based 7 | on Memcached 1.1.x. 8 | 9 | * Some of 0.1.x version code is inspired from Tugela Cache 10 | . 11 | 12 | * Novey Donar contributed some code of 0.1.x 13 | version. 14 | 15 | * Caokai contributed some code of replication. 16 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | What is MemcacheDB? 2 | ******************* 3 | MemcacheDB is a distributed key-value storage system designed for persistence. It is NOT a cache solution, but a persistent storage engine for fast and reliable key-value based object storage and retrieval. It conforms to memcache protocol(not completed, see below), so any memcached client can have connectivity with it. MemcacheDB uses OpenLDAP MDB as a storing backend, which provides full 4 | transaction support. 5 | 6 | Features 7 | ******** 8 | * High performance read/write for a key-value based object 9 | * High reliable persistent storage with transaction 10 | * Memcache protocol compatibility 11 | 12 | Supported memcache commands 13 | *************************** 14 | get(also mutiple get) 15 | set, add, replace 16 | append/prepend 17 | incr, decr 18 | delete 19 | stats 20 | 21 | Private commands 22 | **************** 23 | rget 24 | db_checkpoint 25 | 26 | Some Warning 27 | ************ 28 | Expire time has been discarded in MemcacheDB(we are for persistence:p), so you should not use any corresponding features of clients. The daemon does nothing while you give a expire time to an item. 29 | 30 | For more info, see: https://github.com/LMDB/memcachedb 31 | 32 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Dependencies 2 | ============ 3 | Before deploying Memcachedb, make sure the following packages are installed: 4 | 5 | OpenLDAP 2.4.33 or later libmdb 6 | ------------------------- 7 | http://www.openldap.org 8 | 9 | How to install MDB: 10 | 11 | $tar xvzf openldap-2.4.33.tgz 12 | $cd openldap=2.4.33/libraries/libmdb 13 | $make 14 | $sudo cp mdb.h /usr/local/include 15 | $sudo cp libmdb.* /usr/local/lib 16 | 17 | 18 | libevent 1.3e or later 19 | ------------------------- 20 | http://monkey.org/~provos/libevent/ 21 | 22 | How to install libevent: 23 | 24 | $tar xvzf libevent-1.3e.tar.gz 25 | $cd libevent-1.3e 26 | $./configure 27 | $make 28 | $sudo make install 29 | 30 | Load .so file by adding a line in /etc/ld.so.conf: 31 | 32 | /usr/local/lib 33 | 34 | Then, run 'ldconfig'. 35 | 36 | Installation 37 | ============ 38 | $tar xvzf memcachedb-X.Y.Z.tar.gz 39 | $cd memcachedb-X.Y.Z 40 | $./configure --enable-threads 41 | $make 42 | $sudo make install 43 | 44 | Getting Started 45 | =============== 46 | 47 | use "-h" option to get started. 48 | 49 | Running Examples: 50 | 51 | 1. run as a single daemon 52 | 53 | memcachedb -p21201 -d -r -H /data1/21201 -N -v >/data1/21201.log 2>&1 54 | 55 | Have fun :) 56 | -------------------------------------------------------------------------------- /conf/DB_CONFIG.example: -------------------------------------------------------------------------------- 1 | # This is example config file for tuning BerkeleyDB(The MemcacheDB backend), 2 | # put this file in your database home environment directory 3 | 4 | # initial file created by Steve Chu (stvchu@gmail.com) 5 | 6 | # ================ Environment ===================== 7 | #set_data_dir ./testenv_db 8 | #set_lg_dir ./testenv_log 9 | #set_flags DB_TXN_NOSYNC 10 | #set_verbose DB_VERB_FILEOPS_ALL 11 | #set_verbose DB_VERB_DEADLOCK 12 | #set_verbose DB_VERB_RECOVERY 13 | #set_verbose DB_VERB_REPLICATION 14 | 15 | # ================ Logging Subsystem ===================== 16 | #set_lg_max 10485760 17 | #set_lg_bsize 65536 18 | 19 | # ================ Memory Pool ===================== 20 | #set_cachesize 0 67108864 0 21 | 22 | # ================ Locking Subsystem ===================== 23 | #set_lk_detect DB_LOCK_OLDEST 24 | #set_lk_max_lockers 300000 25 | #set_lk_max_locks 300000 26 | #set_lk_max_objects 300000 27 | #set_lk_partitions 1 28 | 29 | # ================ Replication Subsystem ===================== 30 | #rep_set_nsites 2 31 | #rep_set_priority 100 32 | #rep_set_request 40000 1280000 33 | #repmgr_set_ack_policy DB_REPMGR_ACKS_ALL 34 | 35 | #rep_set_config DB_REP_CONF_BULK 36 | #rep_set_config DB_REP_CONF_DELAYCLIENT 37 | #rep_set_config DB_REP_CONF_LEASE 38 | #rep_set_config DB_REP_CONF_NOAUTOINIT 39 | #rep_set_config DB_REP_CONF_NOWAIT 40 | #rep_set_config DB_REPMGR_CONF_2SITE_STRICT 41 | 42 | #rep_set_timeout DB_REP_ACK_TIMEOUT 15000000 43 | #rep_set_timeout DB_REP_CHECKPOINT_DELAY 0 44 | #rep_set_timeout DB_REP_CONNECTION_RETRY 15000000 45 | #rep_set_timeout DB_REP_ELECTION_TIMEOUT 2000000 46 | #rep_set_timeout DB_REP_ELECTION_RETRY 10000000 47 | #rep_set_timeout DB_REP_FULL_ELECTION_TIMEOUT 0 48 | #rep_set_timeout DB_REP_HEARTBEAT_MONITOR 0 49 | #rep_set_timeout DB_REP_HEARTBEAT_SEND 0 50 | #rep_set_timeout DB_REP_LEASE_TIMEOUT 0 51 | -------------------------------------------------------------------------------- /stats.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MemcacheDB - A distributed key-value storage system designed for persistence: 3 | * 4 | * https://gitorious.org/mdb/memcachedb 5 | * 6 | * Based on the BerkeleyDB version at: 7 | * 8 | * http://memcachedb.googlecode.com 9 | * 10 | * The source code of Memcachedb is most based on Memcached: 11 | * 12 | * http://danga.com/memcached/ 13 | * 14 | * Copyright 2012 Howard Chu. All rights reserved. 15 | * Copyright 2008 Steve Chu. All rights reserved. 16 | * 17 | * Use and distribution licensed under the BSD license. See 18 | * the LICENSE file for full text. 19 | * 20 | * Authors: 21 | * Steve Chu 22 | * Howard Chu 23 | * 24 | */ 25 | 26 | #include "memcachedb.h" 27 | #include 28 | #include 29 | 30 | void stats_mdb(char *temp){ 31 | char *pos = temp; 32 | int ret; 33 | u_int32_t gbytes = 0; 34 | u_int32_t bytes = 0; 35 | int ncache = 0; 36 | MDB_stat mstat; 37 | 38 | char *env_home; 39 | 40 | /* get mdb version */ 41 | pos += sprintf(pos, "STAT db_ver %s\r\n", mdb_version(NULL, NULL, NULL)); 42 | 43 | /* get env stats */ 44 | mdb_env_stat(env, &mstat); 45 | pos += sprintf(pos, "STAT page_size %u\r\n", mstat.ms_psize); 46 | pos += sprintf(pos, "STAT branch_pages %"PRIuS"\r\n", mstat.ms_branch_pages); 47 | pos += sprintf(pos, "STAT leaf_pages %"PRIuS"\r\n", mstat.ms_leaf_pages); 48 | pos += sprintf(pos, "STAT overflow_pages %"PRIuS"\r\n", mstat.ms_overflow_pages); 49 | pos += sprintf(pos, "STAT items %"PRIuS"\r\n", mstat.ms_entries); 50 | 51 | /* get env dir */ 52 | if((ret = mdb_env_get_path(env, (const char **)&env_home)) == 0){ 53 | pos += sprintf(pos, "STAT env_home %s\r\n", env_home); 54 | } 55 | 56 | /* get cache size */ 57 | pos += sprintf(pos, "STAT cache_size %" PRIu64"\r\n", mdb_settings.cache_size); 58 | 59 | pos += sprintf(pos, "STAT txn_nosync %d\r\n", mdb_settings.txn_nosync); 60 | pos += sprintf(pos, "STAT chkpoint_val %d\r\n", mdb_settings.chkpoint_val); 61 | pos += sprintf(pos, "END"); 62 | } 63 | -------------------------------------------------------------------------------- /config.h.in: -------------------------------------------------------------------------------- 1 | /* config.h.in. Generated from configure.ac by autoheader. */ 2 | 3 | /* Define this if you have daemon() */ 4 | #undef HAVE_DAEMON 5 | 6 | /* Define to 1 if you have the header file. */ 7 | #undef HAVE_INTTYPES_H 8 | 9 | /* Define to 1 if you have the `lmdb' library (-llmdb). */ 10 | #undef HAVE_LIBLMDB 11 | 12 | /* do we have malloc.h? */ 13 | #undef HAVE_MALLOC_H 14 | 15 | /* Define to 1 if you have the header file. */ 16 | #undef HAVE_MEMORY_H 17 | 18 | /* Define to 1 if stdbool.h conforms to C99. */ 19 | #undef HAVE_STDBOOL_H 20 | 21 | /* Define to 1 if you have the header file. */ 22 | #undef HAVE_STDINT_H 23 | 24 | /* Define to 1 if you have the header file. */ 25 | #undef HAVE_STDLIB_H 26 | 27 | /* Define to 1 if you have the header file. */ 28 | #undef HAVE_STRINGS_H 29 | 30 | /* Define to 1 if you have the header file. */ 31 | #undef HAVE_STRING_H 32 | 33 | /* do we have stuct mallinfo? */ 34 | #undef HAVE_STRUCT_MALLINFO 35 | 36 | /* Define to 1 if you have the header file. */ 37 | #undef HAVE_SYS_STAT_H 38 | 39 | /* Define to 1 if you have the header file. */ 40 | #undef HAVE_SYS_TYPES_H 41 | 42 | /* Define to 1 if you have the header file. */ 43 | #undef HAVE_UNISTD_H 44 | 45 | /* Define to 1 if the system has the type `_Bool'. */ 46 | #undef HAVE__BOOL 47 | 48 | /* Define to 1 if your C compiler doesn't accept -c and -o together. */ 49 | #undef NO_MINUS_C_MINUS_O 50 | 51 | /* Name of package */ 52 | #undef PACKAGE 53 | 54 | /* Define to the address where bug reports for this package should be sent. */ 55 | #undef PACKAGE_BUGREPORT 56 | 57 | /* Define to the full name of this package. */ 58 | #undef PACKAGE_NAME 59 | 60 | /* Define to the full name and version of this package. */ 61 | #undef PACKAGE_STRING 62 | 63 | /* Define to the one symbol short name of this package. */ 64 | #undef PACKAGE_TARNAME 65 | 66 | /* Define to the home page for this package. */ 67 | #undef PACKAGE_URL 68 | 69 | /* Define to the version of this package. */ 70 | #undef PACKAGE_VERSION 71 | 72 | /* Define to 1 if you have the ANSI C header files. */ 73 | #undef STDC_HEADERS 74 | 75 | /* Define this if you want to use pthreads */ 76 | #undef USE_THREADS 77 | 78 | /* Version number of package */ 79 | #undef VERSION 80 | 81 | /* Define to empty if `const' does not conform to ANSI C. */ 82 | #undef const 83 | 84 | /* define to int if socklen_t not available */ 85 | #undef socklen_t 86 | -------------------------------------------------------------------------------- /doc/rget.txt: -------------------------------------------------------------------------------- 1 | ================================== 2 | 'rget' - range query based on keys 3 | ================================== 4 | 5 | Command Specification 6 | ===================== 7 | 8 | rget \r\n 9 | 10 | - where the query starts. 11 | - where the query ends. 12 | - indicates the openness of left side, 0 means the result includes , while 1 means not. 13 | - indicates the openness of right side, 0 means the result includes , while 1 means not. 14 | - how many items at most return, max is 100. 15 | 16 | After this command, the client expects zero or more items, each of 17 | which is received as a text line followed by a data block. After all 18 | the items have been transmitted, the server sends the string 19 | 20 | "END\r\n" 21 | 22 | to indicate the end of response. 23 | 24 | Each item sent by the server looks like this: 25 | 26 | VALUE \r\n 27 | \r\n 28 | 29 | - is the key for the item being sent 30 | 31 | - is the flags value set by the storage command 32 | 33 | - is the length of the data block to follow, *not* including 34 | its delimiting \r\n 35 | 36 | - is the data for this item. 37 | 38 | Notice: all keys in MemcacheDB is sorted alphabetically, so is the return of query result. 39 | 40 | 41 | Sample Code 42 | ============ 43 | 44 | Notice: Here we use patched libmemcached, please see: http://memcachedb.googlecode.com/svn/clients/ 45 | 46 | #include 47 | /* other includes.. */ 48 | 49 | int main(int argc, char *argv[]){ 50 | memcached_st *memc; 51 | memcached_server_st *servers; 52 | memcached_return rc; 53 | 54 | char *hostname[] = {"127.0.0.1"}; 55 | unsigned int port[] = {21201}; 56 | 57 | char key[MEMCACHED_MAX_KEY]; 58 | char value[1024]; 59 | 60 | char return_key[MEMCACHED_MAX_KEY]; 61 | char *return_value; 62 | size_t return_key_length; 63 | size_t return_value_length; 64 | uint32_t flags; 65 | 66 | memc = memcached_create(NULL); 67 | servers = memcached_server_list_append(NULL, hostname[0], port[0], &rc); 68 | if (MEMCACHED_SUCCESS != rc){ 69 | /* error */ 70 | } 71 | rc = memcached_server_push(memc, servers); 72 | if (MEMCACHED_SUCCESS != rc){ 73 | /* error */ 74 | } 75 | 76 | /* mget-like api */ 77 | rc= memcached_rget(memc, "0", 1, "z", 1, 0, 0, 4); 78 | assert(rc == MEMCACHED_SUCCESS); 79 | 80 | while ((return_value= memcached_fetch(memc, return_key, &return_key_length, 81 | &return_value_length, &flags, &rc))) 82 | { 83 | assert(rc == MEMCACHED_SUCCESS); 84 | memcpy(key, return_key, return_key_length); 85 | key[return_key_length] = '\0'; 86 | memcpy(value, return_value, return_value_length); 87 | value[return_value_length] = '\0'; 88 | /* other things */ 89 | free(return_value); 90 | } 91 | 92 | memcached_server_list_free(servers); 93 | memcached_free(memc); 94 | exit(EXIT_SUCCESS); 95 | } 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /tools/mdbtest.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2008 Steve Chu. All rights reserved. 5 | # 6 | # Use and distribution licensed under the BSD license. See 7 | # the LICENSE file for full text. 8 | # 9 | # Authors: 10 | # Steve Chu 11 | 12 | """Test suit for MemcacheDB 13 | 14 | """ 15 | 16 | import unittest 17 | import memcache 18 | 19 | class MemcacheDBTestCase(unittest.TestCase): 20 | def setUp(self): 21 | self.mc = memcache.Client(['127.0.0.1:21201'], debug=1) 22 | 23 | def tearDown(self): 24 | self.mc.disconnect_all() 25 | 26 | def testSetCmd(self): 27 | self.assert_(self.mc.set("testkey_set", "testvalue_set")) 28 | 29 | def testGetCmd(self): 30 | self.assert_(self.mc.set("testkey_get", "testvalue_get")) 31 | self.assertEqual(self.mc.get("testkey_get"), "testvalue_get") 32 | 33 | def testMultiGetCmd(self): 34 | self.assert_(self.mc.set("testkey1_mget", "testvalue1_mget")) 35 | self.assert_(self.mc.set("testkey2_mget", "testvalue2_mget")) 36 | self.assertEqual(self.mc.get_multi(["testkey1_mget", "testkey2_mget"]), 37 | {"testkey1_mget": "testvalue1_mget", "testkey2_mget": "testvalue2_mget"}) 38 | 39 | def testAddCmd(self): 40 | self.mc.delete("testkey_add") 41 | self.assert_(self.mc.add("testkey_add", "testvalue_add")) 42 | self.assert_(not self.mc.add("testkey_add", "testvalue_add")) 43 | 44 | def testReplaceCmd(self): 45 | self.mc.delete("testkey_replace") 46 | self.assert_(not self.mc.replace("testkey_replace", "testvalue_replace")) 47 | self.assert_(self.mc.set("testkey_replace", "testvalue_replace")) 48 | self.assert_(self.mc.replace("testkey_replace", "testvalue_replace")) 49 | 50 | def testAppendCmd(self): 51 | self.mc.delete("testkey_append") 52 | self.assert_(not self.mc.append("testkey_append", "testvalue_append")) 53 | self.assert_(self.mc.set("testkey_append", "testvalue_append")) 54 | self.assert_(self.mc.append("testkey_append", "testvalue_append")) 55 | 56 | def testPrependCmd(self): 57 | self.mc.delete("testkey_prepend") 58 | self.assert_(not self.mc.append("testkey_prepend", "testvalue_prepend")) 59 | self.assert_(self.mc.set("testkey_prepend", "testvalue_prepend")) 60 | self.assert_(self.mc.append("testkey_prepend", "testvalue_prepend")) 61 | 62 | def testDeleteCmd(self): 63 | #delete in memcache.py dose not have a good return value 64 | # self.assert_(not self.mc.delete("testkey_delete")) 65 | # self.assert_(self.mc.set("testkey_delete", "testvalue_delete")) 66 | # self.assert_(self.mc.delete("testkey_delete")) 67 | pass 68 | 69 | def testDbArchiveCmd(self): 70 | self.assert_(self.mc.db_archive()) 71 | 72 | def testDbCheckpointCmd(self): 73 | self.assert_(self.mc.db_checkpoint()) 74 | 75 | def testRepSetPriorityCmd(self): 76 | self.assert_(self.mc.rep_set_priority(200)) 77 | 78 | def testRepSetAckPolicy(self): 79 | self.assert_(self.mc.rep_set_ack_policy(5)) 80 | 81 | def testRgetCmd(self): 82 | self.assert_(self.mc.set("prefix_abcs", "1111")) 83 | self.assert_(self.mc.set("prefix_abds", "2222")) 84 | self.assert_(self.mc.set("prefix_abes", "3333")) 85 | self.assert_(self.mc.set("prefix_abfs", "4444")) 86 | self.assertEqual(self.mc.rget('prefix_', 'prefix_z', 0, 0, 2), 87 | [("prefix_abcs", "1111"), ("prefix_abds", "2222")]) 88 | self.assertEqual(self.mc.rget('prefix_abds', 'prefix_z', 1, 0, 20), 89 | [("prefix_abes", "3333"), ("prefix_abfs", "4444")]) 90 | 91 | 92 | if __name__ == '__main__': 93 | suite = unittest.TestLoader().loadTestsFromTestCase(MemcacheDBTestCase) 94 | unittest.TextTestRunner(verbosity=2).run(suite) -------------------------------------------------------------------------------- /tools/mdbtop.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2008 Steve Chu. All rights reserved. 5 | # 6 | # Use and distribution licensed under the BSD license. See 7 | # the LICENSE file for full text. 8 | # 9 | # Authors: 10 | # Steve Chu 11 | 12 | """a unix top style stat tool for MemcacheDB 13 | 14 | """ 15 | 16 | import sys 17 | import time 18 | import signal 19 | import curses 20 | import memcache 21 | import getopt 22 | 23 | class TopDisplayer(object): 24 | def __init__(self): 25 | # initialize the curse 26 | self.stdscr = curses.initscr() 27 | curses.noecho() 28 | curses.cbreak() 29 | 30 | def close(self): 31 | # finalize the curse 32 | curses.nocbreak() 33 | self.stdscr.keypad(0) 34 | curses.echo() 35 | curses.endwin() 36 | 37 | def display(self, y, x, text): 38 | self.stdscr.addstr(y, x, text) 39 | self.stdscr.refresh() 40 | 41 | 42 | def main(server, interval): 43 | # connect to mdb 44 | mc = memcache.Client([server], debug=0) 45 | 46 | # display header 47 | top.display(0, 0, "Press Ctrl+C to quit.") 48 | top.display(1, 0, "%-20s %10s %10s %10s %10s %10s %10s" % ("Server:", "Uptime", "Conns", "read/sec", "wrtn/sec", "sets/sec", "gets/sec")) 49 | 50 | read_per_sec = 0 51 | wrtn_per_sec = 0 52 | gets_per_sec = 0 53 | sets_per_sec = 0 54 | 55 | # get the initial value 56 | stats = mc.get_stats() 57 | if stats == []: 58 | return 59 | stats_dict = stats[0][1] 60 | conns = int(stats_dict["curr_connections"]) 61 | uptime = int(stats_dict["uptime"]) 62 | bytes_read = int(stats_dict["bytes_read"]) 63 | bytes_written = int(stats_dict["bytes_written"]) 64 | cmd_gets = int(stats_dict["cmd_get"]) 65 | cmd_sets = int(stats_dict["cmd_set"]) 66 | 67 | while True: 68 | stats = mc.get_stats() 69 | if stats == []: 70 | continue 71 | stats_dict = stats[0][1] 72 | conns = int(stats_dict["curr_connections"]) 73 | uptime = int(stats_dict["uptime"]) 74 | read_per_sec = (int(stats_dict["bytes_read"]) - bytes_read)/interval 75 | bytes_read = int(stats_dict["bytes_read"]) 76 | wrtn_per_sec = (int(stats_dict["bytes_written"]) - bytes_written)/interval 77 | bytes_written = int(stats_dict["bytes_written"]) 78 | gets_per_sec = (int(stats_dict["cmd_get"]) - cmd_gets)/interval 79 | cmd_gets = int(stats_dict["cmd_get"]) 80 | sets_per_sec = (int(stats_dict["cmd_set"]) - cmd_sets)/interval 81 | cmd_sets = int(stats_dict["cmd_set"]) 82 | top.display(2, 0, "%-20s %10d %10d %10d %10d %10d %10d" % (server, uptime, conns, read_per_sec, wrtn_per_sec, sets_per_sec, gets_per_sec)) 83 | time.sleep(interval) 84 | 85 | # close the connection 86 | mc.disconnect_all() 87 | 88 | def usage(): 89 | print 'Usage: python mdbben.py [options]' 90 | print 'Options are:' 91 | print ' --server=, -s Server that connects to, default is \'127.0.0.1:21201\'' 92 | print ' --interval=, -i Number of threads to run the benchmark, default is 2' 93 | print ' --help, -h Display usage information (this message)' 94 | print 95 | 96 | def handler(signum, frame): 97 | top.close() 98 | sys.exit(0) 99 | 100 | if __name__ == "__main__": 101 | signal.signal(signal.SIGTERM, handler) 102 | signal.signal(signal.SIGQUIT, handler) 103 | signal.signal(signal.SIGINT, handler) 104 | 105 | top_cfg = {'server': '127.0.0.1:21201', 106 | 'interval': 2} 107 | try: 108 | opts, args = getopt.getopt(sys.argv[1:], "s:i:h", 109 | ["server=", "interval=", "help"]) 110 | except getopt.GetoptError, err: 111 | print str(err) 112 | usage() 113 | sys.exit(2) 114 | 115 | for o, a in opts: 116 | if o in ("-s", "--server"): 117 | top_cfg["server"] = a 118 | elif o in ("-i", "--interval"): 119 | top_cfg["interval"] = int(a) 120 | elif o in ("-h", "--help"): 121 | usage() 122 | sys.exit() 123 | else: 124 | assert False, "unhandled option" 125 | 126 | top = TopDisplayer() 127 | main(top_cfg["server"], top_cfg["interval"]) 128 | top.close() 129 | -------------------------------------------------------------------------------- /compile: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Wrapper for compilers which do not understand `-c -o'. 3 | 4 | scriptversion=2005-05-14.22 5 | 6 | # Copyright (C) 1999, 2000, 2003, 2004, 2005 Free Software Foundation, Inc. 7 | # Written by Tom Tromey . 8 | # 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | # 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | # 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program; if not, write to the Free Software 21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 22 | 23 | # As a special exception to the GNU General Public License, if you 24 | # distribute this file as part of a program that contains a 25 | # configuration script generated by Autoconf, you may include it under 26 | # the same distribution terms that you use for the rest of that program. 27 | 28 | # This file is maintained in Automake, please report 29 | # bugs to or send patches to 30 | # . 31 | 32 | case $1 in 33 | '') 34 | echo "$0: No command. Try \`$0 --help' for more information." 1>&2 35 | exit 1; 36 | ;; 37 | -h | --h*) 38 | cat <<\EOF 39 | Usage: compile [--help] [--version] PROGRAM [ARGS] 40 | 41 | Wrapper for compilers which do not understand `-c -o'. 42 | Remove `-o dest.o' from ARGS, run PROGRAM with the remaining 43 | arguments, and rename the output as expected. 44 | 45 | If you are trying to build a whole package this is not the 46 | right script to run: please start by reading the file `INSTALL'. 47 | 48 | Report bugs to . 49 | EOF 50 | exit $? 51 | ;; 52 | -v | --v*) 53 | echo "compile $scriptversion" 54 | exit $? 55 | ;; 56 | esac 57 | 58 | ofile= 59 | cfile= 60 | eat= 61 | 62 | for arg 63 | do 64 | if test -n "$eat"; then 65 | eat= 66 | else 67 | case $1 in 68 | -o) 69 | # configure might choose to run compile as `compile cc -o foo foo.c'. 70 | # So we strip `-o arg' only if arg is an object. 71 | eat=1 72 | case $2 in 73 | *.o | *.obj) 74 | ofile=$2 75 | ;; 76 | *) 77 | set x "$@" -o "$2" 78 | shift 79 | ;; 80 | esac 81 | ;; 82 | *.c) 83 | cfile=$1 84 | set x "$@" "$1" 85 | shift 86 | ;; 87 | *) 88 | set x "$@" "$1" 89 | shift 90 | ;; 91 | esac 92 | fi 93 | shift 94 | done 95 | 96 | if test -z "$ofile" || test -z "$cfile"; then 97 | # If no `-o' option was seen then we might have been invoked from a 98 | # pattern rule where we don't need one. That is ok -- this is a 99 | # normal compilation that the losing compiler can handle. If no 100 | # `.c' file was seen then we are probably linking. That is also 101 | # ok. 102 | exec "$@" 103 | fi 104 | 105 | # Name of file we expect compiler to create. 106 | cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'` 107 | 108 | # Create the lock directory. 109 | # Note: use `[/.-]' here to ensure that we don't use the same name 110 | # that we are using for the .o file. Also, base the name on the expected 111 | # object file name, since that is what matters with a parallel build. 112 | lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d 113 | while true; do 114 | if mkdir "$lockdir" >/dev/null 2>&1; then 115 | break 116 | fi 117 | sleep 1 118 | done 119 | # FIXME: race condition here if user kills between mkdir and trap. 120 | trap "rmdir '$lockdir'; exit 1" 1 2 15 121 | 122 | # Run the compile. 123 | "$@" 124 | ret=$? 125 | 126 | if test -f "$cofile"; then 127 | mv "$cofile" "$ofile" 128 | elif test -f "${cofile}bj"; then 129 | mv "${cofile}bj" "$ofile" 130 | fi 131 | 132 | rmdir "$lockdir" 133 | exit $ret 134 | 135 | # Local Variables: 136 | # mode: shell-script 137 | # sh-indentation: 2 138 | # eval: (add-hook 'write-file-hooks 'time-stamp) 139 | # time-stamp-start: "scriptversion=" 140 | # time-stamp-format: "%:y-%02m-%02d.%02H" 141 | # time-stamp-end: "$" 142 | # End: 143 | -------------------------------------------------------------------------------- /mdbaux.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | /* 3 | * Copyright 2012 Howard Chu. All rights reserved. 4 | * 5 | * Use and distribution licensed under the BSD license. See 6 | * the LICENSE file for full text. 7 | * 8 | * Authors: 9 | * Howard Chu 10 | */ 11 | 12 | #include "memcachedb.h" 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | static void *mdb_chkpoint_thread __P((void *)); 25 | 26 | 27 | static pthread_t chk_ptid; 28 | 29 | void mdb_settings_init(void) 30 | { 31 | mdb_settings.env_home = DBHOME; 32 | mdb_settings.cache_size = 1 * 1024 * 1024 * 1024; /* default is 1GB */ 33 | mdb_settings.txn_nosync = 0; /* default DB_TXN_NOSYNC is off */ 34 | mdb_settings.chkpoint_val = 60 * 5; 35 | mdb_settings.env_flags = MDB_WRITEMAP; 36 | } 37 | 38 | void mdb_setup(void){ 39 | int ret; 40 | unsigned int readers; 41 | MDB_txn *txn; 42 | 43 | /* db env init */ 44 | if ((ret = mdb_env_create(&env)) != 0) { 45 | fprintf(stderr, "mdb_env_create: %s\n", mdb_strerror(ret)); 46 | exit(EXIT_FAILURE); 47 | } 48 | 49 | /* set map size */ 50 | if (sizeof(void *) == 4 && mdb_settings.cache_size > (1024uLL * 1024uLL * 1024uLL * 2uLL)) { 51 | fprintf(stderr, "32bit box only max 2GB memory pool allowed\n"); 52 | exit(EXIT_FAILURE); 53 | } 54 | ret = mdb_env_set_mapsize(env, mdb_settings.cache_size); 55 | 56 | /* check readers */ 57 | mdb_env_get_maxreaders(env, &readers); 58 | if (settings.num_threads > readers) { 59 | readers = settings.num_threads; 60 | ret = mdb_env_set_maxreaders(env, readers); 61 | } 62 | 63 | 64 | /* if no home dir existed, we create it */ 65 | if (0 != access(mdb_settings.env_home, F_OK)) { 66 | if (0 != mkdir(mdb_settings.env_home, 0750)) { 67 | fprintf(stderr, "mkdir env_home error:[%s]\n", mdb_settings.env_home); 68 | exit(EXIT_FAILURE); 69 | } 70 | } 71 | 72 | if ((ret = mdb_env_open(env, mdb_settings.env_home, mdb_settings.env_flags, 0640)) != 0) { 73 | fprintf(stderr, "mdb_env_open: %s\n", mdb_strerror(ret)); 74 | exit(EXIT_FAILURE); 75 | } 76 | 77 | /* set DB_TXN_NOSYNC flag */ 78 | if (mdb_settings.txn_nosync){ 79 | mdb_env_set_flags(env, MDB_NOSYNC, 1); 80 | } 81 | 82 | if ((ret = mdb_txn_begin(env, NULL, 0, &txn)) != 0) { 83 | fprintf(stderr, "mdb_txn_begin: %s\n", mdb_strerror(ret)); 84 | exit(EXIT_FAILURE); 85 | } 86 | 87 | if ((ret = mdb_open(txn, NULL, 0, &dbi)) != 0) { 88 | fprintf(stderr, "mdb_open: %s\n", mdb_strerror(ret)); 89 | exit(EXIT_FAILURE); 90 | } 91 | mdb_txn_commit(txn); 92 | } 93 | 94 | 95 | void start_chkpoint_thread(void){ 96 | if (mdb_settings.chkpoint_val > 0){ 97 | /* Start a checkpoint thread. */ 98 | if ((errno = pthread_create( 99 | &chk_ptid, NULL, mdb_chkpoint_thread, (void *)env)) != 0) { 100 | fprintf(stderr, 101 | "failed spawning checkpoint thread: %s\n", 102 | strerror(errno)); 103 | exit(EXIT_FAILURE); 104 | } 105 | } 106 | } 107 | 108 | 109 | static void *mdb_chkpoint_thread(void *arg) 110 | { 111 | MDB_env *dbenv; 112 | int ret; 113 | dbenv = arg; 114 | if (settings.verbose > 1) { 115 | fprintf(stderr, "checkpoint thread created: %lu, every %d seconds\n", 116 | (u_long)pthread_self(), mdb_settings.chkpoint_val); 117 | } 118 | for (;; sleep(mdb_settings.chkpoint_val)) { 119 | if ((ret = mdb_env_sync(dbenv, 1)) != 0) { 120 | fprintf(stderr, "checkpoint thread: %s\n", mdb_strerror(ret)); 121 | } 122 | fprintf(stderr, "checkpoint thread: a checkpoint is done\n"); 123 | } 124 | return (NULL); 125 | } 126 | 127 | /* for atexit cleanup */ 128 | void mdb_shutdown(void){ 129 | if (env != NULL) { 130 | mdb_env_close(env); 131 | env = NULL; 132 | } 133 | } 134 | 135 | /* for atexit cleanup */ 136 | void mdb_chkpoint(void) 137 | { 138 | int ret = 0; 139 | if (env != NULL){ 140 | ret = mdb_env_sync(env, 1); 141 | if (0 != ret){ 142 | fprintf(stderr, "mdb_env_sync: %s\n", mdb_strerror(ret)); 143 | }else{ 144 | fprintf(stderr, "mdb_env_sync: OK\n"); 145 | } 146 | } 147 | } 148 | 149 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_PREREQ(2.61) 2 | AC_INIT([memcachedb], [2.0.0], [hyc@symas.com]) 3 | AM_INIT_AUTOMAKE([-Wall -Werror foreign]) 4 | AC_PROG_CC 5 | AM_PROG_CC_C_O 6 | AC_CONFIG_HEADERS([config.h]) 7 | 8 | trylibeventdir="" 9 | AC_ARG_WITH(libevent, 10 | [ --with-libevent=PATH Specify path to libevent installation ], 11 | [ 12 | if test "x$withval" != "xno" ; then 13 | trylibeventdir=$withval 14 | fi 15 | ] 16 | ) 17 | 18 | dnl ------------------------------------------------------ 19 | dnl libevent detection. swiped from Tor. modified a bit. 20 | 21 | LIBEVENT_URL=http://www.monkey.org/~provos/libevent/ 22 | 23 | AC_CACHE_CHECK([for libevent directory], ac_cv_libevent_dir, [ 24 | saved_LIBS="$LIBS" 25 | saved_LDFLAGS="$LDFLAGS" 26 | saved_CPPFLAGS="$CPPFLAGS" 27 | le_found=no 28 | for ledir in $trylibeventdir "" $prefix /usr/local ; do 29 | LDFLAGS="$saved_LDFLAGS" 30 | LIBS="$saved_LIBS -levent" 31 | 32 | # Skip the directory if it isn't there. 33 | if test ! -z "$ledir" -a ! -d "$ledir" ; then 34 | continue; 35 | fi 36 | if test ! -z "$ledir" ; then 37 | if test -d "$ledir/lib" ; then 38 | LDFLAGS="-L$ledir/lib $LDFLAGS" 39 | else 40 | LDFLAGS="-L$ledir $LDFLAGS" 41 | fi 42 | if test -d "$ledir/include" ; then 43 | CPPFLAGS="-I$ledir/include $CPPFLAGS" 44 | else 45 | CPPFLAGS="-I$ledir $CPPFLAGS" 46 | fi 47 | fi 48 | # Can I compile and link it? 49 | AC_TRY_LINK([#include 50 | #include 51 | #include ], [ event_init(); ], 52 | [ libevent_linked=yes ], [ libevent_linked=no ]) 53 | if test $libevent_linked = yes; then 54 | if test ! -z "$ledir" ; then 55 | ac_cv_libevent_dir=$ledir 56 | else 57 | ac_cv_libevent_dir="(system)" 58 | fi 59 | le_found=yes 60 | break 61 | fi 62 | done 63 | LIBS="$saved_LIBS" 64 | LDFLAGS="$saved_LDFLAGS" 65 | CPPFLAGS="$saved_CPPFLAGS" 66 | if test $le_found = no ; then 67 | AC_MSG_ERROR([libevent is required. You can get it from $LIBEVENT_URL 68 | 69 | If it's already installed, specify its path using --with-libevent=/dir/ 70 | ]) 71 | fi 72 | ]) 73 | # ' 74 | LIBS="$LIBS -levent" 75 | if test $ac_cv_libevent_dir != "(system)"; then 76 | if test -d "$ac_cv_libevent_dir/lib" ; then 77 | LDFLAGS="-L$ac_cv_libevent_dir/lib $LDFLAGS" 78 | le_libdir="$ac_cv_libevent_dir/lib" 79 | else 80 | LDFLAGS="-L$ac_cv_libevent_dir $LDFLAGS" 81 | le_libdir="$ac_cv_libevent_dir" 82 | fi 83 | if test -d "$ac_cv_libevent_dir/include" ; then 84 | CPPFLAGS="-I$ac_cv_libevent_dir/include $CPPFLAGS" 85 | else 86 | CPPFLAGS="-I$ac_cv_libevent_dir $CPPFLAGS" 87 | fi 88 | fi 89 | 90 | dnl Check OpenLDAP LMDB lib and header 91 | AC_CHECK_HEADER(lmdb.h, [ 92 | AC_CHECK_LIB(lmdb, mdb_env_create, [], AC_MSG_ERROR(cannot find liblmdb.so))], 93 | AC_MSG_ERROR(cannot find lmdb.h)) 94 | 95 | dnl ---------------------------------------------------------------------------- 96 | 97 | AC_SEARCH_LIBS(socket, socket) 98 | AC_SEARCH_LIBS(gethostbyname, nsl) 99 | AC_SEARCH_LIBS(mallinfo, malloc) 100 | 101 | AC_CHECK_FUNC(daemon,AC_DEFINE([HAVE_DAEMON],,[Define this if you have daemon()]),[AC_LIBOBJ(daemon)]) 102 | 103 | AC_HEADER_STDBOOL 104 | AC_C_CONST 105 | AC_CHECK_HEADER(malloc.h, AC_DEFINE(HAVE_MALLOC_H,,[do we have malloc.h?])) 106 | AC_CHECK_MEMBER([struct mallinfo.arena], [ 107 | AC_DEFINE(HAVE_STRUCT_MALLINFO,,[do we have stuct mallinfo?]) 108 | ], ,[ 109 | # include 110 | ] 111 | ) 112 | 113 | dnl From licq: Copyright (c) 2000 Dirk Mueller 114 | dnl Check if the type socklen_t is defined anywhere 115 | AC_DEFUN([AC_C_SOCKLEN_T], 116 | [AC_CACHE_CHECK(for socklen_t, ac_cv_c_socklen_t, 117 | [ 118 | AC_TRY_COMPILE([ 119 | #include 120 | #include 121 | ],[ 122 | socklen_t foo; 123 | ],[ 124 | ac_cv_c_socklen_t=yes 125 | ],[ 126 | ac_cv_c_socklen_t=no 127 | ]) 128 | ]) 129 | if test $ac_cv_c_socklen_t = no; then 130 | AC_DEFINE(socklen_t, int, [define to int if socklen_t not available]) 131 | fi 132 | ]) 133 | 134 | AC_C_SOCKLEN_T 135 | 136 | dnl Check whether the user wants threads or not 137 | AC_ARG_ENABLE(threads, 138 | [AS_HELP_STRING([--enable-threads],[support multithreaded execution])]) 139 | if test "x$enable_threads" == "xyes"; then 140 | AC_SEARCH_LIBS([pthread_create], [pthread], [AC_DEFINE([USE_THREADS],,[Define this if you want to use pthreads])] ,[AC_MSG_ERROR(cannot find libpthread.so)]) 141 | fi 142 | 143 | AC_CONFIG_FILES([Makefile doc/Makefile tools/Makefile conf/Makefile]) 144 | AC_OUTPUT 145 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012, Howard Chu. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are 6 | met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following disclaimer 13 | in the documentation and/or other materials provided with the 14 | distribution. 15 | 16 | * Neither the name of the Danga Interactive nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | 32 | 33 | This software is derived from MemcacheDB by Steve Chu: 34 | 35 | [memcachedb] 36 | 37 | Copyright (c) 2008, Steve Chu. 38 | All rights reserved. 39 | 40 | Redistribution and use in source and binary forms, with or without 41 | modification, are permitted provided that the following conditions are 42 | met: 43 | 44 | * Redistributions of source code must retain the above copyright 45 | notice, this list of conditions and the following disclaimer. 46 | 47 | * Redistributions in binary form must reproduce the above 48 | copyright notice, this list of conditions and the following disclaimer 49 | in the documentation and/or other materials provided with the 50 | distribution. 51 | 52 | * Neither the name of the Danga Interactive nor the names of its 53 | contributors may be used to endorse or promote products derived from 54 | this software without specific prior written permission. 55 | 56 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 57 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 58 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 59 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 60 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 61 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 62 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 63 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 64 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 65 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 66 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 67 | 68 | 69 | This product includes software developed by Danga Interactive, Inc. 70 | 71 | [ memcached ] 72 | 73 | Copyright (c) 2003, Danga Interactive, Inc. 74 | All rights reserved. 75 | 76 | Redistribution and use in source and binary forms, with or without 77 | modification, are permitted provided that the following conditions are 78 | met: 79 | 80 | * Redistributions of source code must retain the above copyright 81 | notice, this list of conditions and the following disclaimer. 82 | 83 | * Redistributions in binary form must reproduce the above 84 | copyright notice, this list of conditions and the following disclaimer 85 | in the documentation and/or other materials provided with the 86 | distribution. 87 | 88 | * Neither the name of the Danga Interactive nor the names of its 89 | contributors may be used to endorse or promote products derived from 90 | this software without specific prior written permission. 91 | 92 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 93 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 94 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 95 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 96 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 97 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 98 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 99 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 100 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 101 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 102 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 103 | 104 | 105 | This product includes software developed by Niels Provos. 106 | 107 | [ libevent ] 108 | 109 | Copyright 2000-2003 Niels Provos 110 | All rights reserved. 111 | 112 | Redistribution and use in source and binary forms, with or without 113 | modification, are permitted provided that the following conditions 114 | are met: 115 | 1. Redistributions of source code must retain the above copyright 116 | notice, this list of conditions and the following disclaimer. 117 | 2. Redistributions in binary form must reproduce the above copyright 118 | notice, this list of conditions and the following disclaimer in the 119 | documentation and/or other materials provided with the distribution. 120 | 3. All advertising materials mentioning features or use of this software 121 | must display the following acknowledgement: 122 | This product includes software developed by Niels Provos. 123 | 4. The name of the author may not be used to endorse or promote products 124 | derived from this software without specific prior written permission. 125 | 126 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 127 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 128 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 129 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 130 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 131 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 132 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 133 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 134 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 135 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 136 | -------------------------------------------------------------------------------- /tools/mcben.py: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # Copyright 2008 Steve Chu. All rights reserved. 5 | # 6 | # Use and distribution licensed under the BSD license. See 7 | # the LICENSE file for full text. 8 | # 9 | # Authors: 10 | # Steve Chu 11 | 12 | """Benchmark suit for MemcacheD/MemcacheDB 13 | 14 | This is a multiple-threads benchmark suit for daemon over memcache protocol 15 | """ 16 | 17 | import memcache 18 | import random 19 | import time 20 | import sys 21 | import threading 22 | import thread 23 | import getopt 24 | 25 | ben_result = [] 26 | ben_result_mutex = thread.allocate_lock( ) 27 | 28 | class MemcacheBenchCase(object): 29 | def __init__(self, ben_cfg): 30 | self.threads_ = [] 31 | self.ben_cfg_ = ben_cfg 32 | 33 | def run(self): 34 | print 'Benchmarking (be patient).....' 35 | for i in range(self.ben_cfg_['threads']): 36 | if self.ben_cfg_['command'] == 'SET': 37 | thread = Setter(self.ben_cfg_['server'], self.ben_cfg_['requests'], self.ben_cfg_['length']) 38 | elif self.ben_cfg_['command'] == 'GET': 39 | thread = Getter(self.ben_cfg_['server'], self.ben_cfg_['requests'], self.ben_cfg_['length']) 40 | else: 41 | print 'unknown command' 42 | sys.exit(1) 43 | thread.start() 44 | self.threads_.append(thread) 45 | 46 | def join(self): 47 | for thread in self.threads_: 48 | thread.join() 49 | self.print_result() 50 | 51 | def print_result(self): 52 | total_time_cost = 0.0 53 | total_errors = 0 54 | total_threads = self.ben_cfg_['threads'] 55 | requests_per_thread = self.ben_cfg_['requests'] 56 | total_requests = total_threads * requests_per_thread 57 | value_length = self.ben_cfg_['length'] 58 | 59 | # stats the total 60 | for (thread_name, time_cost_per_thread, errors_per_thread) in ben_result: 61 | total_time_cost = total_time_cost + time_cost_per_thread 62 | total_errors = total_errors + errors_per_thread 63 | 64 | # calculate all fields 65 | avg_time_cost = total_time_cost / total_threads 66 | throughout = total_requests * (value_length + 16) / avg_time_cost / 1024 67 | requests_per_second = total_requests / avg_time_cost 68 | time_cost_per_request = avg_time_cost / total_requests * 1000 69 | 70 | # print out 71 | print 'done.' 72 | print 73 | print 'Server name: %s' % self.ben_cfg_['server'] 74 | print 'Command: %s' % self.ben_cfg_['command'] 75 | print 'Thread number: %d' % total_threads 76 | print 'Requests per thread: %d' % requests_per_thread 77 | print 'Value Length: %d bytes' % value_length 78 | print 'Avg. time cost per thread: %f seconds' % avg_time_cost 79 | print 'Throughout: %d kbytes/sec' % throughout 80 | print 'Requests per second: %d req/sec' % requests_per_second 81 | print 'Time cost per request: %f ms' % time_cost_per_request 82 | print 'Total requests: %d' % total_requests 83 | print 'Total errors: %d' % total_errors 84 | 85 | class Setter(threading.Thread): 86 | def __init__(self, server, requests, value_length): 87 | self.mc_ = memcache.Client([server], debug=1) 88 | self.requests_ = requests 89 | self.value_length_ = value_length 90 | threading.Thread.__init__(self) 91 | 92 | def run(self): 93 | begin = time.time() 94 | errors = 0 95 | for i in range(self.requests_): 96 | ret = self.mc_.set("test-%011d" % (i,), "*" * self.value_length_) 97 | if not ret: 98 | errors = errors + 1 99 | end = time.time() 100 | # print 'ok, time cost: %d' % (end - begin) 101 | ben_result_mutex.acquire() 102 | ben_result.append((self.getName(), end - begin, errors)) 103 | ben_result_mutex.release() 104 | print 'Thread name: %s; Time cost: %f seconds; Requests: %d; Errors: %d' % (self.getName(), 105 | end - begin, self.requests_, errors) 106 | 107 | def __del__(self): 108 | self.mc_.disconnect_all() 109 | 110 | class Getter(threading.Thread): 111 | def __init__(self, server, requests, value_length): 112 | self.mc_ = memcache.Client([server], debug=0) 113 | self.requests_ = requests 114 | self.value_length_ = value_length 115 | threading.Thread.__init__(self) 116 | 117 | def run(self): 118 | begin = time.time() 119 | errors = 0 120 | for i in range(self.requests_): 121 | ret = self.mc_.get("test-%011d" % (i,)) 122 | if ret == None or len(ret) != self.value_length_: 123 | errors = errors + 1; 124 | end = time.time() 125 | ben_result_mutex.acquire() 126 | ben_result.append((self.getName(), end - begin, errors)) 127 | ben_result_mutex.release() 128 | print 'Thread name: %s; Time cost: %f seconds; Requests: %d; Errors: %d' % (self.getName(), 129 | end - begin, self.requests_, errors) 130 | 131 | def __del__(self): 132 | self.mc_.disconnect_all() 133 | 134 | def usage(): 135 | print 'Usage: python mdbben.py [options]' 136 | print 'Options are:' 137 | print ' --server=, -s Server that the suit connects to, default is \'127.0.0.1:21201\'' 138 | print ' --command=, -c Operation that intends to run, \'SET\' or \'GET\', default is \'SET\'' 139 | print ' --threads=, -t Number of threads to run the benchmark, default is 4' 140 | print ' --requests=, -n Number of requests to perform, default is 100000 per thread' 141 | print ' --length=, -l ' 142 | print ' Length of an object value, default is 100 btyes' 143 | print ' --help, -h Display usage information (this message)' 144 | print 145 | 146 | def main(args): 147 | ben_cfg = {'server': '127.0.0.1:21201', 148 | 'command': 'SET', 149 | 'threads': 4, 150 | 'requests': 100000, 151 | 'length': 100} 152 | try: 153 | opts, args = getopt.getopt(sys.argv[1:], "s:c:t:n:l:h", 154 | ["server=", "command=", "threads=", "requests=", "length=", "help"]) 155 | except getopt.GetoptError, err: 156 | print str(err) 157 | usage() 158 | sys.exit(2) 159 | 160 | for o, a in opts: 161 | if o in ("-s", "--server"): 162 | ben_cfg["server"] = a 163 | elif o in ("-c", "--command"): 164 | ben_cfg["command"] = a 165 | elif o in ("-t", "--threads"): 166 | ben_cfg["threads"] = int(a) 167 | elif o in ("-n", "--requests"): 168 | ben_cfg["requests"] = int(a) 169 | elif o in ("-l", "--length"): 170 | ben_cfg["length"] = int(a) 171 | elif o in ("-h", "--help"): 172 | usage() 173 | sys.exit() 174 | else: 175 | assert False, "unhandled option" 176 | 177 | bench = MemcacheBenchCase(ben_cfg) 178 | bench.run() 179 | bench.join() 180 | 181 | if __name__ == '__main__': 182 | main(sys.argv) 183 | -------------------------------------------------------------------------------- /item.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MemcacheDB - A distributed key-value storage system designed for persistence: 3 | * 4 | * https://gitorious.org/mdb/memcachedb 5 | * 6 | * Based on the BerkeleyDB version at: 7 | * 8 | * http://memcachedb.googlecode.com 9 | * 10 | * The source code of Memcachedb is most based on Memcached: 11 | * 12 | * http://danga.com/memcached/ 13 | * 14 | * Copyright 2012 Howard Chu. All rights reserved. 15 | * Copyright 2008 Steve Chu. All rights reserved. 16 | * 17 | * Use and distribution licensed under the BSD license. See 18 | * the LICENSE file for full text. 19 | * 20 | * Authors: 21 | * Steve Chu 22 | * Howard Chu 23 | * 24 | */ 25 | 26 | #include "memcachedb.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | #define MAX_ITEM_FREELIST_LENGTH 4000 38 | #define INIT_ITEM_FREELIST_LENGTH 500 39 | 40 | static size_t item_make_header(const uint8_t nkey, const int flags, const int nbytes, char *suffix, uint8_t *nsuffix); 41 | 42 | static item **freeitem; 43 | static int freeitemtotal; 44 | static int freeitemcurr; 45 | 46 | void item_init(void) { 47 | freeitemtotal = INIT_ITEM_FREELIST_LENGTH; 48 | freeitemcurr = 0; 49 | 50 | freeitem = (item **)malloc( sizeof(item *) * freeitemtotal ); 51 | if (freeitem == NULL) { 52 | perror("malloc()"); 53 | } 54 | return; 55 | } 56 | 57 | /* 58 | * Returns a item buffer from the freelist, if any. Sholud call 59 | * item_from_freelist for thread safty. 60 | * */ 61 | item *do_item_from_freelist(void) { 62 | item *s; 63 | 64 | if (freeitemcurr > 0) { 65 | s = freeitem[--freeitemcurr]; 66 | } else { 67 | /* If malloc fails, let the logic fall through without spamming 68 | * STDERR on the server. */ 69 | s = (item *)malloc( settings.item_buf_size ); 70 | if (s != NULL){ 71 | memset(s, 0, settings.item_buf_size); 72 | } 73 | } 74 | 75 | return s; 76 | } 77 | 78 | /* 79 | * Adds a item to the freelist. Should call 80 | * item_add_to_freelist for thread safty. 81 | */ 82 | int do_item_add_to_freelist(item *it) { 83 | if (freeitemcurr < freeitemtotal) { 84 | freeitem[freeitemcurr++] = it; 85 | return 0; 86 | } else { 87 | if (freeitemtotal >= MAX_ITEM_FREELIST_LENGTH){ 88 | return 1; 89 | } 90 | /* try to enlarge free item buffer array */ 91 | item **new_freeitem = (item **)realloc(freeitem, sizeof(item *) * freeitemtotal * 2); 92 | if (new_freeitem) { 93 | freeitemtotal *= 2; 94 | freeitem = new_freeitem; 95 | freeitem[freeitemcurr++] = it; 96 | return 0; 97 | } 98 | } 99 | return 1; 100 | } 101 | 102 | #define SUFFLEN 40 103 | 104 | /** 105 | * Generates the variable-sized part of the header for an object. 106 | * 107 | * key - The key 108 | * nkey - The length of the key 109 | * flags - key flags 110 | * nbytes - Number of bytes to hold value and addition CRLF terminator 111 | * suffix - Buffer for the "VALUE" line suffix (flags, size). 112 | * nsuffix - The length of the suffix is stored here. 113 | * 114 | * Returns the total size of the header. 115 | */ 116 | static size_t item_make_header(const uint8_t nkey, const int flags, const int nbytes, 117 | char *suffix, uint8_t *nsuffix) { 118 | *nsuffix = (uint8_t) snprintf(suffix, SUFFLEN, " %d %d\r\n", flags, nbytes - 2); 119 | return sizeof(item) + nkey + *nsuffix + nbytes + 1; 120 | } 121 | 122 | /* 123 | * alloc a item buffer, and init it. 124 | */ 125 | item *item_alloc1(MDB_val *key, const int flags, const int nbytes) { 126 | uint8_t nsuffix; 127 | item *it; 128 | char suffix[SUFFLEN]; 129 | size_t ntotal = item_make_header(key->mv_size + 1, flags, nbytes, suffix, &nsuffix); 130 | 131 | if (ntotal > settings.item_buf_size){ 132 | it = (item *)malloc(ntotal); 133 | if (it == NULL){ 134 | return NULL; 135 | } 136 | memset(it, 0, ntotal); 137 | if (settings.verbose > 1) { 138 | fprintf(stderr, "alloc a item buffer from malloc.\n"); 139 | } 140 | }else{ 141 | it = item_from_freelist(); 142 | if (it == NULL){ 143 | return NULL; 144 | } 145 | if (settings.verbose > 1) { 146 | fprintf(stderr, "alloc a item buffer from freelist.\n"); 147 | } 148 | } 149 | 150 | it->key.mv_size = key->mv_size; 151 | it->key.mv_data = (void *)(it+1); 152 | it->data.mv_size = nbytes + nsuffix + 1; 153 | it->data.mv_data = (char *)it->key.mv_data + key->mv_size+1; 154 | strcpy(ITEM_key(it), key->mv_data); 155 | memcpy(ITEM_suffix(it), suffix, (size_t)nsuffix); 156 | ITEM_suflen(it) = nsuffix; 157 | return it; 158 | } 159 | 160 | /* 161 | * alloc a item buffer only. 162 | */ 163 | item *item_alloc2(size_t ntotal) { 164 | item *it; 165 | if (ntotal > settings.item_buf_size){ 166 | it = (item *)malloc(ntotal); 167 | if (it == NULL){ 168 | return NULL; 169 | } 170 | memset(it, 0, ntotal); 171 | if (settings.verbose > 1) { 172 | fprintf(stderr, "alloc a item buffer from malloc.\n"); 173 | } 174 | }else{ 175 | it = item_from_freelist(); 176 | if (it == NULL){ 177 | return NULL; 178 | } 179 | if (settings.verbose > 1) { 180 | fprintf(stderr, "alloc a item buffer from freelist.\n"); 181 | } 182 | } 183 | 184 | return it; 185 | } 186 | 187 | /* 188 | * alloc a item buffer, and init it. 189 | */ 190 | int item_alloc_put(MDB_txn *txn, MDB_val *key, const int flags, const int nbytes, item *it) { 191 | uint8_t nsuffix; 192 | char suffix[SUFFLEN]; 193 | int ret; 194 | 195 | it->key = *key; 196 | it->data.mv_size = item_make_header(0, flags, nbytes, suffix, &nsuffix) - sizeof(item); 197 | ret = mdb_put(txn, dbi, key, &it->data, MDB_RESERVE); 198 | if (!ret) { 199 | memcpy(ITEM_suffix(it), suffix, (size_t)nsuffix); 200 | ITEM_suflen(it) = nsuffix; 201 | } 202 | return ret; 203 | } 204 | 205 | /* 206 | * alloc a item buffer only. 207 | */ 208 | /* 209 | * free a item buffer. here 'it' must be a full item. 210 | */ 211 | 212 | int item_free(item *it) { 213 | size_t ntotal = 0; 214 | if (NULL == it) 215 | return 0; 216 | 217 | /* ntotal may be wrong, if 'it' is not a full item. */ 218 | ntotal = it->data.mv_size; 219 | if (ntotal > settings.item_buf_size){ 220 | if (settings.verbose > 1) { 221 | fprintf(stderr, "ntotal: %"PRIuS", use free() directly.\n", ntotal); 222 | } 223 | free(it); 224 | }else{ 225 | if (0 != item_add_to_freelist(it)) { 226 | if (settings.verbose > 1) { 227 | fprintf(stderr, "ntotal: %"PRIuS", add a item buffer to freelist fail, use free() directly.\n", ntotal); 228 | } 229 | free(it); 230 | }else{ 231 | if (settings.verbose > 1) { 232 | fprintf(stderr, "ntotal: %"PRIuS", add a item buffer to freelist.\n", ntotal); 233 | } 234 | } 235 | } 236 | return 0; 237 | } 238 | 239 | int item_get(MDB_txn *txn, MDB_val *key, item *it) { 240 | int ret; 241 | 242 | /* try to get a item from mdb */ 243 | ret = mdb_get(txn, dbi, key, &it->data); 244 | if (!ret) { 245 | it->key = *key; 246 | return 0; 247 | } 248 | if (ret == MDB_NOTFOUND) 249 | return 1; 250 | if (settings.verbose > 1) { 251 | fprintf(stderr, "mdb_get: %s\n", mdb_strerror(ret)); 252 | } 253 | return -1; 254 | } 255 | 256 | int item_cget(MDB_cursor *cursorp, MDB_val *key, item *it, u_int32_t flags){ 257 | int ret; 258 | /* try to get a item from mdb */ 259 | ret = mdb_cursor_get(cursorp, key, &it->data, flags); 260 | if (!ret) { 261 | it->key = *key; 262 | return 0; 263 | } 264 | if (ret == MDB_NOTFOUND) 265 | return 1; 266 | if (settings.verbose > 1) { 267 | fprintf(stderr, "mdb_cursor_get: %s\n", mdb_strerror(ret)); 268 | } 269 | return -1; 270 | } 271 | 272 | /* 0 for Success 273 | -1 for SERVER_ERROR 274 | */ 275 | int item_put(MDB_txn *txn, item *it){ 276 | int ret; 277 | ret = mdb_put(txn, dbi, &it->key, &it->data, 0); 278 | if (!ret) 279 | return 0; 280 | if (settings.verbose > 1) { 281 | fprintf(stderr, "mdb_put: %s\n", mdb_strerror(ret)); 282 | } 283 | return -1; 284 | } 285 | 286 | /* 0 for Success 287 | 1 for NOT_FOUND 288 | -1 for SERVER_ERROR 289 | */ 290 | int item_delete(MDB_txn *txn, MDB_val *key) { 291 | int ret; 292 | ret = mdb_del(txn, dbi, key, NULL); 293 | if (ret == 0) 294 | return 0; 295 | if(ret == MDB_NOTFOUND) 296 | return 1; 297 | if (settings.verbose > 1) { 298 | fprintf(stderr, "mdb_del: %s\n", mdb_strerror(ret)); 299 | } 300 | return -1; 301 | } 302 | 303 | /* 304 | 1 for exists 305 | 0 for non-exist 306 | */ 307 | int item_exists(MDB_txn *txn, MDB_val *key) { 308 | int ret; 309 | MDB_val data; 310 | 311 | ret = mdb_get(txn, dbi, key, &data); 312 | if (ret == 0){ 313 | return 1; 314 | } 315 | return 0; 316 | } 317 | -------------------------------------------------------------------------------- /doc/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.11.3 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 5 | # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software 6 | # Foundation, Inc. 7 | # This Makefile.in is free software; the Free Software Foundation 8 | # gives unlimited permission to copy and/or distribute it, 9 | # with or without modifications, as long as this notice is preserved. 10 | 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 13 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | # PARTICULAR PURPOSE. 15 | 16 | @SET_MAKE@ 17 | VPATH = @srcdir@ 18 | pkgdatadir = $(datadir)/@PACKAGE@ 19 | pkgincludedir = $(includedir)/@PACKAGE@ 20 | pkglibdir = $(libdir)/@PACKAGE@ 21 | pkglibexecdir = $(libexecdir)/@PACKAGE@ 22 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 23 | install_sh_DATA = $(install_sh) -c -m 644 24 | install_sh_PROGRAM = $(install_sh) -c 25 | install_sh_SCRIPT = $(install_sh) -c 26 | INSTALL_HEADER = $(INSTALL_DATA) 27 | transform = $(program_transform_name) 28 | NORMAL_INSTALL = : 29 | PRE_INSTALL = : 30 | POST_INSTALL = : 31 | NORMAL_UNINSTALL = : 32 | PRE_UNINSTALL = : 33 | POST_UNINSTALL = : 34 | subdir = doc 35 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in 36 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 37 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 38 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 39 | $(ACLOCAL_M4) 40 | mkinstalldirs = $(install_sh) -d 41 | CONFIG_HEADER = $(top_builddir)/config.h 42 | CONFIG_CLEAN_FILES = 43 | CONFIG_CLEAN_VPATH_FILES = 44 | SOURCES = 45 | DIST_SOURCES = 46 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 47 | ACLOCAL = @ACLOCAL@ 48 | AMTAR = @AMTAR@ 49 | AUTOCONF = @AUTOCONF@ 50 | AUTOHEADER = @AUTOHEADER@ 51 | AUTOMAKE = @AUTOMAKE@ 52 | AWK = @AWK@ 53 | CC = @CC@ 54 | CCDEPMODE = @CCDEPMODE@ 55 | CFLAGS = @CFLAGS@ 56 | CPP = @CPP@ 57 | CPPFLAGS = @CPPFLAGS@ 58 | CYGPATH_W = @CYGPATH_W@ 59 | DEFS = @DEFS@ 60 | DEPDIR = @DEPDIR@ 61 | ECHO_C = @ECHO_C@ 62 | ECHO_N = @ECHO_N@ 63 | ECHO_T = @ECHO_T@ 64 | EGREP = @EGREP@ 65 | EXEEXT = @EXEEXT@ 66 | GREP = @GREP@ 67 | INSTALL = @INSTALL@ 68 | INSTALL_DATA = @INSTALL_DATA@ 69 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 70 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 71 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 72 | LDFLAGS = @LDFLAGS@ 73 | LIBOBJS = @LIBOBJS@ 74 | LIBS = @LIBS@ 75 | LTLIBOBJS = @LTLIBOBJS@ 76 | MAKEINFO = @MAKEINFO@ 77 | MKDIR_P = @MKDIR_P@ 78 | OBJEXT = @OBJEXT@ 79 | PACKAGE = @PACKAGE@ 80 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 81 | PACKAGE_NAME = @PACKAGE_NAME@ 82 | PACKAGE_STRING = @PACKAGE_STRING@ 83 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 84 | PACKAGE_URL = @PACKAGE_URL@ 85 | PACKAGE_VERSION = @PACKAGE_VERSION@ 86 | PATH_SEPARATOR = @PATH_SEPARATOR@ 87 | SET_MAKE = @SET_MAKE@ 88 | SHELL = @SHELL@ 89 | STRIP = @STRIP@ 90 | VERSION = @VERSION@ 91 | abs_builddir = @abs_builddir@ 92 | abs_srcdir = @abs_srcdir@ 93 | abs_top_builddir = @abs_top_builddir@ 94 | abs_top_srcdir = @abs_top_srcdir@ 95 | ac_ct_CC = @ac_ct_CC@ 96 | am__include = @am__include@ 97 | am__leading_dot = @am__leading_dot@ 98 | am__quote = @am__quote@ 99 | am__tar = @am__tar@ 100 | am__untar = @am__untar@ 101 | bindir = @bindir@ 102 | build_alias = @build_alias@ 103 | builddir = @builddir@ 104 | datadir = @datadir@ 105 | datarootdir = @datarootdir@ 106 | docdir = @docdir@ 107 | dvidir = @dvidir@ 108 | exec_prefix = @exec_prefix@ 109 | host_alias = @host_alias@ 110 | htmldir = @htmldir@ 111 | includedir = @includedir@ 112 | infodir = @infodir@ 113 | install_sh = @install_sh@ 114 | libdir = @libdir@ 115 | libexecdir = @libexecdir@ 116 | localedir = @localedir@ 117 | localstatedir = @localstatedir@ 118 | mandir = @mandir@ 119 | mkdir_p = @mkdir_p@ 120 | oldincludedir = @oldincludedir@ 121 | pdfdir = @pdfdir@ 122 | prefix = @prefix@ 123 | program_transform_name = @program_transform_name@ 124 | psdir = @psdir@ 125 | sbindir = @sbindir@ 126 | sharedstatedir = @sharedstatedir@ 127 | srcdir = @srcdir@ 128 | sysconfdir = @sysconfdir@ 129 | target_alias = @target_alias@ 130 | top_build_prefix = @top_build_prefix@ 131 | top_builddir = @top_builddir@ 132 | top_srcdir = @top_srcdir@ 133 | EXTRA_DIST = *.txt 134 | all: all-am 135 | 136 | .SUFFIXES: 137 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) 138 | @for dep in $?; do \ 139 | case '$(am__configure_deps)' in \ 140 | *$$dep*) \ 141 | ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ 142 | && { if test -f $@; then exit 0; else break; fi; }; \ 143 | exit 1;; \ 144 | esac; \ 145 | done; \ 146 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign doc/Makefile'; \ 147 | $(am__cd) $(top_srcdir) && \ 148 | $(AUTOMAKE) --foreign doc/Makefile 149 | .PRECIOUS: Makefile 150 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 151 | @case '$?' in \ 152 | *config.status*) \ 153 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ 154 | *) \ 155 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ 156 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ 157 | esac; 158 | 159 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 160 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 161 | 162 | $(top_srcdir)/configure: $(am__configure_deps) 163 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 164 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) 165 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 166 | $(am__aclocal_m4_deps): 167 | tags: TAGS 168 | TAGS: 169 | 170 | ctags: CTAGS 171 | CTAGS: 172 | 173 | 174 | distdir: $(DISTFILES) 175 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 176 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 177 | list='$(DISTFILES)'; \ 178 | dist_files=`for file in $$list; do echo $$file; done | \ 179 | sed -e "s|^$$srcdirstrip/||;t" \ 180 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 181 | case $$dist_files in \ 182 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 183 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 184 | sort -u` ;; \ 185 | esac; \ 186 | for file in $$dist_files; do \ 187 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 188 | if test -d $$d/$$file; then \ 189 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 190 | if test -d "$(distdir)/$$file"; then \ 191 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 192 | fi; \ 193 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 194 | cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ 195 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 196 | fi; \ 197 | cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ 198 | else \ 199 | test -f "$(distdir)/$$file" \ 200 | || cp -p $$d/$$file "$(distdir)/$$file" \ 201 | || exit 1; \ 202 | fi; \ 203 | done 204 | check-am: all-am 205 | check: check-am 206 | all-am: Makefile 207 | installdirs: 208 | install: install-am 209 | install-exec: install-exec-am 210 | install-data: install-data-am 211 | uninstall: uninstall-am 212 | 213 | install-am: all-am 214 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 215 | 216 | installcheck: installcheck-am 217 | install-strip: 218 | if test -z '$(STRIP)'; then \ 219 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 220 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 221 | install; \ 222 | else \ 223 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 224 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 225 | "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ 226 | fi 227 | mostlyclean-generic: 228 | 229 | clean-generic: 230 | 231 | distclean-generic: 232 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 233 | -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) 234 | 235 | maintainer-clean-generic: 236 | @echo "This command is intended for maintainers to use" 237 | @echo "it deletes files that may require special tools to rebuild." 238 | clean: clean-am 239 | 240 | clean-am: clean-generic mostlyclean-am 241 | 242 | distclean: distclean-am 243 | -rm -f Makefile 244 | distclean-am: clean-am distclean-generic 245 | 246 | dvi: dvi-am 247 | 248 | dvi-am: 249 | 250 | html: html-am 251 | 252 | html-am: 253 | 254 | info: info-am 255 | 256 | info-am: 257 | 258 | install-data-am: 259 | 260 | install-dvi: install-dvi-am 261 | 262 | install-dvi-am: 263 | 264 | install-exec-am: 265 | 266 | install-html: install-html-am 267 | 268 | install-html-am: 269 | 270 | install-info: install-info-am 271 | 272 | install-info-am: 273 | 274 | install-man: 275 | 276 | install-pdf: install-pdf-am 277 | 278 | install-pdf-am: 279 | 280 | install-ps: install-ps-am 281 | 282 | install-ps-am: 283 | 284 | installcheck-am: 285 | 286 | maintainer-clean: maintainer-clean-am 287 | -rm -f Makefile 288 | maintainer-clean-am: distclean-am maintainer-clean-generic 289 | 290 | mostlyclean: mostlyclean-am 291 | 292 | mostlyclean-am: mostlyclean-generic 293 | 294 | pdf: pdf-am 295 | 296 | pdf-am: 297 | 298 | ps: ps-am 299 | 300 | ps-am: 301 | 302 | uninstall-am: 303 | 304 | .MAKE: install-am install-strip 305 | 306 | .PHONY: all all-am check check-am clean clean-generic distclean \ 307 | distclean-generic distdir dvi dvi-am html html-am info info-am \ 308 | install install-am install-data install-data-am install-dvi \ 309 | install-dvi-am install-exec install-exec-am install-html \ 310 | install-html-am install-info install-info-am install-man \ 311 | install-pdf install-pdf-am install-ps install-ps-am \ 312 | install-strip installcheck installcheck-am installdirs \ 313 | maintainer-clean maintainer-clean-generic mostlyclean \ 314 | mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am 315 | 316 | 317 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 318 | # Otherwise a system limit (for SysV at least) may be exceeded. 319 | .NOEXPORT: 320 | -------------------------------------------------------------------------------- /tools/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.11.3 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 5 | # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software 6 | # Foundation, Inc. 7 | # This Makefile.in is free software; the Free Software Foundation 8 | # gives unlimited permission to copy and/or distribute it, 9 | # with or without modifications, as long as this notice is preserved. 10 | 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 13 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | # PARTICULAR PURPOSE. 15 | 16 | @SET_MAKE@ 17 | VPATH = @srcdir@ 18 | pkgdatadir = $(datadir)/@PACKAGE@ 19 | pkgincludedir = $(includedir)/@PACKAGE@ 20 | pkglibdir = $(libdir)/@PACKAGE@ 21 | pkglibexecdir = $(libexecdir)/@PACKAGE@ 22 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 23 | install_sh_DATA = $(install_sh) -c -m 644 24 | install_sh_PROGRAM = $(install_sh) -c 25 | install_sh_SCRIPT = $(install_sh) -c 26 | INSTALL_HEADER = $(INSTALL_DATA) 27 | transform = $(program_transform_name) 28 | NORMAL_INSTALL = : 29 | PRE_INSTALL = : 30 | POST_INSTALL = : 31 | NORMAL_UNINSTALL = : 32 | PRE_UNINSTALL = : 33 | POST_UNINSTALL = : 34 | subdir = tools 35 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in 36 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 37 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 38 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 39 | $(ACLOCAL_M4) 40 | mkinstalldirs = $(install_sh) -d 41 | CONFIG_HEADER = $(top_builddir)/config.h 42 | CONFIG_CLEAN_FILES = 43 | CONFIG_CLEAN_VPATH_FILES = 44 | SOURCES = 45 | DIST_SOURCES = 46 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 47 | ACLOCAL = @ACLOCAL@ 48 | AMTAR = @AMTAR@ 49 | AUTOCONF = @AUTOCONF@ 50 | AUTOHEADER = @AUTOHEADER@ 51 | AUTOMAKE = @AUTOMAKE@ 52 | AWK = @AWK@ 53 | CC = @CC@ 54 | CCDEPMODE = @CCDEPMODE@ 55 | CFLAGS = @CFLAGS@ 56 | CPP = @CPP@ 57 | CPPFLAGS = @CPPFLAGS@ 58 | CYGPATH_W = @CYGPATH_W@ 59 | DEFS = @DEFS@ 60 | DEPDIR = @DEPDIR@ 61 | ECHO_C = @ECHO_C@ 62 | ECHO_N = @ECHO_N@ 63 | ECHO_T = @ECHO_T@ 64 | EGREP = @EGREP@ 65 | EXEEXT = @EXEEXT@ 66 | GREP = @GREP@ 67 | INSTALL = @INSTALL@ 68 | INSTALL_DATA = @INSTALL_DATA@ 69 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 70 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 71 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 72 | LDFLAGS = @LDFLAGS@ 73 | LIBOBJS = @LIBOBJS@ 74 | LIBS = @LIBS@ 75 | LTLIBOBJS = @LTLIBOBJS@ 76 | MAKEINFO = @MAKEINFO@ 77 | MKDIR_P = @MKDIR_P@ 78 | OBJEXT = @OBJEXT@ 79 | PACKAGE = @PACKAGE@ 80 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 81 | PACKAGE_NAME = @PACKAGE_NAME@ 82 | PACKAGE_STRING = @PACKAGE_STRING@ 83 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 84 | PACKAGE_URL = @PACKAGE_URL@ 85 | PACKAGE_VERSION = @PACKAGE_VERSION@ 86 | PATH_SEPARATOR = @PATH_SEPARATOR@ 87 | SET_MAKE = @SET_MAKE@ 88 | SHELL = @SHELL@ 89 | STRIP = @STRIP@ 90 | VERSION = @VERSION@ 91 | abs_builddir = @abs_builddir@ 92 | abs_srcdir = @abs_srcdir@ 93 | abs_top_builddir = @abs_top_builddir@ 94 | abs_top_srcdir = @abs_top_srcdir@ 95 | ac_ct_CC = @ac_ct_CC@ 96 | am__include = @am__include@ 97 | am__leading_dot = @am__leading_dot@ 98 | am__quote = @am__quote@ 99 | am__tar = @am__tar@ 100 | am__untar = @am__untar@ 101 | bindir = @bindir@ 102 | build_alias = @build_alias@ 103 | builddir = @builddir@ 104 | datadir = @datadir@ 105 | datarootdir = @datarootdir@ 106 | docdir = @docdir@ 107 | dvidir = @dvidir@ 108 | exec_prefix = @exec_prefix@ 109 | host_alias = @host_alias@ 110 | htmldir = @htmldir@ 111 | includedir = @includedir@ 112 | infodir = @infodir@ 113 | install_sh = @install_sh@ 114 | libdir = @libdir@ 115 | libexecdir = @libexecdir@ 116 | localedir = @localedir@ 117 | localstatedir = @localstatedir@ 118 | mandir = @mandir@ 119 | mkdir_p = @mkdir_p@ 120 | oldincludedir = @oldincludedir@ 121 | pdfdir = @pdfdir@ 122 | prefix = @prefix@ 123 | program_transform_name = @program_transform_name@ 124 | psdir = @psdir@ 125 | sbindir = @sbindir@ 126 | sharedstatedir = @sharedstatedir@ 127 | srcdir = @srcdir@ 128 | sysconfdir = @sysconfdir@ 129 | target_alias = @target_alias@ 130 | top_build_prefix = @top_build_prefix@ 131 | top_builddir = @top_builddir@ 132 | top_srcdir = @top_srcdir@ 133 | EXTRA_DIST = *.py 134 | all: all-am 135 | 136 | .SUFFIXES: 137 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) 138 | @for dep in $?; do \ 139 | case '$(am__configure_deps)' in \ 140 | *$$dep*) \ 141 | ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ 142 | && { if test -f $@; then exit 0; else break; fi; }; \ 143 | exit 1;; \ 144 | esac; \ 145 | done; \ 146 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/Makefile'; \ 147 | $(am__cd) $(top_srcdir) && \ 148 | $(AUTOMAKE) --foreign tools/Makefile 149 | .PRECIOUS: Makefile 150 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 151 | @case '$?' in \ 152 | *config.status*) \ 153 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ 154 | *) \ 155 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ 156 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ 157 | esac; 158 | 159 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 160 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 161 | 162 | $(top_srcdir)/configure: $(am__configure_deps) 163 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 164 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) 165 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 166 | $(am__aclocal_m4_deps): 167 | tags: TAGS 168 | TAGS: 169 | 170 | ctags: CTAGS 171 | CTAGS: 172 | 173 | 174 | distdir: $(DISTFILES) 175 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 176 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 177 | list='$(DISTFILES)'; \ 178 | dist_files=`for file in $$list; do echo $$file; done | \ 179 | sed -e "s|^$$srcdirstrip/||;t" \ 180 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 181 | case $$dist_files in \ 182 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 183 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 184 | sort -u` ;; \ 185 | esac; \ 186 | for file in $$dist_files; do \ 187 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 188 | if test -d $$d/$$file; then \ 189 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 190 | if test -d "$(distdir)/$$file"; then \ 191 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 192 | fi; \ 193 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 194 | cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ 195 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 196 | fi; \ 197 | cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ 198 | else \ 199 | test -f "$(distdir)/$$file" \ 200 | || cp -p $$d/$$file "$(distdir)/$$file" \ 201 | || exit 1; \ 202 | fi; \ 203 | done 204 | check-am: all-am 205 | check: check-am 206 | all-am: Makefile 207 | installdirs: 208 | install: install-am 209 | install-exec: install-exec-am 210 | install-data: install-data-am 211 | uninstall: uninstall-am 212 | 213 | install-am: all-am 214 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 215 | 216 | installcheck: installcheck-am 217 | install-strip: 218 | if test -z '$(STRIP)'; then \ 219 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 220 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 221 | install; \ 222 | else \ 223 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 224 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 225 | "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ 226 | fi 227 | mostlyclean-generic: 228 | 229 | clean-generic: 230 | 231 | distclean-generic: 232 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 233 | -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) 234 | 235 | maintainer-clean-generic: 236 | @echo "This command is intended for maintainers to use" 237 | @echo "it deletes files that may require special tools to rebuild." 238 | clean: clean-am 239 | 240 | clean-am: clean-generic mostlyclean-am 241 | 242 | distclean: distclean-am 243 | -rm -f Makefile 244 | distclean-am: clean-am distclean-generic 245 | 246 | dvi: dvi-am 247 | 248 | dvi-am: 249 | 250 | html: html-am 251 | 252 | html-am: 253 | 254 | info: info-am 255 | 256 | info-am: 257 | 258 | install-data-am: 259 | 260 | install-dvi: install-dvi-am 261 | 262 | install-dvi-am: 263 | 264 | install-exec-am: 265 | 266 | install-html: install-html-am 267 | 268 | install-html-am: 269 | 270 | install-info: install-info-am 271 | 272 | install-info-am: 273 | 274 | install-man: 275 | 276 | install-pdf: install-pdf-am 277 | 278 | install-pdf-am: 279 | 280 | install-ps: install-ps-am 281 | 282 | install-ps-am: 283 | 284 | installcheck-am: 285 | 286 | maintainer-clean: maintainer-clean-am 287 | -rm -f Makefile 288 | maintainer-clean-am: distclean-am maintainer-clean-generic 289 | 290 | mostlyclean: mostlyclean-am 291 | 292 | mostlyclean-am: mostlyclean-generic 293 | 294 | pdf: pdf-am 295 | 296 | pdf-am: 297 | 298 | ps: ps-am 299 | 300 | ps-am: 301 | 302 | uninstall-am: 303 | 304 | .MAKE: install-am install-strip 305 | 306 | .PHONY: all all-am check check-am clean clean-generic distclean \ 307 | distclean-generic distdir dvi dvi-am html html-am info info-am \ 308 | install install-am install-data install-data-am install-dvi \ 309 | install-dvi-am install-exec install-exec-am install-html \ 310 | install-html-am install-info install-info-am install-man \ 311 | install-pdf install-pdf-am install-ps install-ps-am \ 312 | install-strip installcheck installcheck-am installdirs \ 313 | maintainer-clean maintainer-clean-generic mostlyclean \ 314 | mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am 315 | 316 | 317 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 318 | # Otherwise a system limit (for SysV at least) may be exceeded. 319 | .NOEXPORT: 320 | -------------------------------------------------------------------------------- /conf/Makefile.in: -------------------------------------------------------------------------------- 1 | # Makefile.in generated by automake 1.11.3 from Makefile.am. 2 | # @configure_input@ 3 | 4 | # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 5 | # 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software 6 | # Foundation, Inc. 7 | # This Makefile.in is free software; the Free Software Foundation 8 | # gives unlimited permission to copy and/or distribute it, 9 | # with or without modifications, as long as this notice is preserved. 10 | 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY, to the extent permitted by law; without 13 | # even the implied warranty of MERCHANTABILITY or FITNESS FOR A 14 | # PARTICULAR PURPOSE. 15 | 16 | @SET_MAKE@ 17 | VPATH = @srcdir@ 18 | pkgdatadir = $(datadir)/@PACKAGE@ 19 | pkgincludedir = $(includedir)/@PACKAGE@ 20 | pkglibdir = $(libdir)/@PACKAGE@ 21 | pkglibexecdir = $(libexecdir)/@PACKAGE@ 22 | am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd 23 | install_sh_DATA = $(install_sh) -c -m 644 24 | install_sh_PROGRAM = $(install_sh) -c 25 | install_sh_SCRIPT = $(install_sh) -c 26 | INSTALL_HEADER = $(INSTALL_DATA) 27 | transform = $(program_transform_name) 28 | NORMAL_INSTALL = : 29 | PRE_INSTALL = : 30 | POST_INSTALL = : 31 | NORMAL_UNINSTALL = : 32 | PRE_UNINSTALL = : 33 | POST_UNINSTALL = : 34 | subdir = conf 35 | DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in 36 | ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 37 | am__aclocal_m4_deps = $(top_srcdir)/configure.ac 38 | am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ 39 | $(ACLOCAL_M4) 40 | mkinstalldirs = $(install_sh) -d 41 | CONFIG_HEADER = $(top_builddir)/config.h 42 | CONFIG_CLEAN_FILES = 43 | CONFIG_CLEAN_VPATH_FILES = 44 | SOURCES = 45 | DIST_SOURCES = 46 | DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) 47 | ACLOCAL = @ACLOCAL@ 48 | AMTAR = @AMTAR@ 49 | AUTOCONF = @AUTOCONF@ 50 | AUTOHEADER = @AUTOHEADER@ 51 | AUTOMAKE = @AUTOMAKE@ 52 | AWK = @AWK@ 53 | CC = @CC@ 54 | CCDEPMODE = @CCDEPMODE@ 55 | CFLAGS = @CFLAGS@ 56 | CPP = @CPP@ 57 | CPPFLAGS = @CPPFLAGS@ 58 | CYGPATH_W = @CYGPATH_W@ 59 | DEFS = @DEFS@ 60 | DEPDIR = @DEPDIR@ 61 | ECHO_C = @ECHO_C@ 62 | ECHO_N = @ECHO_N@ 63 | ECHO_T = @ECHO_T@ 64 | EGREP = @EGREP@ 65 | EXEEXT = @EXEEXT@ 66 | GREP = @GREP@ 67 | INSTALL = @INSTALL@ 68 | INSTALL_DATA = @INSTALL_DATA@ 69 | INSTALL_PROGRAM = @INSTALL_PROGRAM@ 70 | INSTALL_SCRIPT = @INSTALL_SCRIPT@ 71 | INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ 72 | LDFLAGS = @LDFLAGS@ 73 | LIBOBJS = @LIBOBJS@ 74 | LIBS = @LIBS@ 75 | LTLIBOBJS = @LTLIBOBJS@ 76 | MAKEINFO = @MAKEINFO@ 77 | MKDIR_P = @MKDIR_P@ 78 | OBJEXT = @OBJEXT@ 79 | PACKAGE = @PACKAGE@ 80 | PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ 81 | PACKAGE_NAME = @PACKAGE_NAME@ 82 | PACKAGE_STRING = @PACKAGE_STRING@ 83 | PACKAGE_TARNAME = @PACKAGE_TARNAME@ 84 | PACKAGE_URL = @PACKAGE_URL@ 85 | PACKAGE_VERSION = @PACKAGE_VERSION@ 86 | PATH_SEPARATOR = @PATH_SEPARATOR@ 87 | SET_MAKE = @SET_MAKE@ 88 | SHELL = @SHELL@ 89 | STRIP = @STRIP@ 90 | VERSION = @VERSION@ 91 | abs_builddir = @abs_builddir@ 92 | abs_srcdir = @abs_srcdir@ 93 | abs_top_builddir = @abs_top_builddir@ 94 | abs_top_srcdir = @abs_top_srcdir@ 95 | ac_ct_CC = @ac_ct_CC@ 96 | am__include = @am__include@ 97 | am__leading_dot = @am__leading_dot@ 98 | am__quote = @am__quote@ 99 | am__tar = @am__tar@ 100 | am__untar = @am__untar@ 101 | bindir = @bindir@ 102 | build_alias = @build_alias@ 103 | builddir = @builddir@ 104 | datadir = @datadir@ 105 | datarootdir = @datarootdir@ 106 | docdir = @docdir@ 107 | dvidir = @dvidir@ 108 | exec_prefix = @exec_prefix@ 109 | host_alias = @host_alias@ 110 | htmldir = @htmldir@ 111 | includedir = @includedir@ 112 | infodir = @infodir@ 113 | install_sh = @install_sh@ 114 | libdir = @libdir@ 115 | libexecdir = @libexecdir@ 116 | localedir = @localedir@ 117 | localstatedir = @localstatedir@ 118 | mandir = @mandir@ 119 | mkdir_p = @mkdir_p@ 120 | oldincludedir = @oldincludedir@ 121 | pdfdir = @pdfdir@ 122 | prefix = @prefix@ 123 | program_transform_name = @program_transform_name@ 124 | psdir = @psdir@ 125 | sbindir = @sbindir@ 126 | sharedstatedir = @sharedstatedir@ 127 | srcdir = @srcdir@ 128 | sysconfdir = @sysconfdir@ 129 | target_alias = @target_alias@ 130 | top_build_prefix = @top_build_prefix@ 131 | top_builddir = @top_builddir@ 132 | top_srcdir = @top_srcdir@ 133 | EXTRA_DIST = DB_CONFIG.example 134 | all: all-am 135 | 136 | .SUFFIXES: 137 | $(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) 138 | @for dep in $?; do \ 139 | case '$(am__configure_deps)' in \ 140 | *$$dep*) \ 141 | ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ 142 | && { if test -f $@; then exit 0; else break; fi; }; \ 143 | exit 1;; \ 144 | esac; \ 145 | done; \ 146 | echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign conf/Makefile'; \ 147 | $(am__cd) $(top_srcdir) && \ 148 | $(AUTOMAKE) --foreign conf/Makefile 149 | .PRECIOUS: Makefile 150 | Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status 151 | @case '$?' in \ 152 | *config.status*) \ 153 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ 154 | *) \ 155 | echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ 156 | cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ 157 | esac; 158 | 159 | $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) 160 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 161 | 162 | $(top_srcdir)/configure: $(am__configure_deps) 163 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 164 | $(ACLOCAL_M4): $(am__aclocal_m4_deps) 165 | cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh 166 | $(am__aclocal_m4_deps): 167 | tags: TAGS 168 | TAGS: 169 | 170 | ctags: CTAGS 171 | CTAGS: 172 | 173 | 174 | distdir: $(DISTFILES) 175 | @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 176 | topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ 177 | list='$(DISTFILES)'; \ 178 | dist_files=`for file in $$list; do echo $$file; done | \ 179 | sed -e "s|^$$srcdirstrip/||;t" \ 180 | -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ 181 | case $$dist_files in \ 182 | */*) $(MKDIR_P) `echo "$$dist_files" | \ 183 | sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ 184 | sort -u` ;; \ 185 | esac; \ 186 | for file in $$dist_files; do \ 187 | if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ 188 | if test -d $$d/$$file; then \ 189 | dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ 190 | if test -d "$(distdir)/$$file"; then \ 191 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 192 | fi; \ 193 | if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ 194 | cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ 195 | find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ 196 | fi; \ 197 | cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ 198 | else \ 199 | test -f "$(distdir)/$$file" \ 200 | || cp -p $$d/$$file "$(distdir)/$$file" \ 201 | || exit 1; \ 202 | fi; \ 203 | done 204 | check-am: all-am 205 | check: check-am 206 | all-am: Makefile 207 | installdirs: 208 | install: install-am 209 | install-exec: install-exec-am 210 | install-data: install-data-am 211 | uninstall: uninstall-am 212 | 213 | install-am: all-am 214 | @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am 215 | 216 | installcheck: installcheck-am 217 | install-strip: 218 | if test -z '$(STRIP)'; then \ 219 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 220 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 221 | install; \ 222 | else \ 223 | $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ 224 | install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ 225 | "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ 226 | fi 227 | mostlyclean-generic: 228 | 229 | clean-generic: 230 | 231 | distclean-generic: 232 | -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) 233 | -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) 234 | 235 | maintainer-clean-generic: 236 | @echo "This command is intended for maintainers to use" 237 | @echo "it deletes files that may require special tools to rebuild." 238 | clean: clean-am 239 | 240 | clean-am: clean-generic mostlyclean-am 241 | 242 | distclean: distclean-am 243 | -rm -f Makefile 244 | distclean-am: clean-am distclean-generic 245 | 246 | dvi: dvi-am 247 | 248 | dvi-am: 249 | 250 | html: html-am 251 | 252 | html-am: 253 | 254 | info: info-am 255 | 256 | info-am: 257 | 258 | install-data-am: 259 | 260 | install-dvi: install-dvi-am 261 | 262 | install-dvi-am: 263 | 264 | install-exec-am: 265 | 266 | install-html: install-html-am 267 | 268 | install-html-am: 269 | 270 | install-info: install-info-am 271 | 272 | install-info-am: 273 | 274 | install-man: 275 | 276 | install-pdf: install-pdf-am 277 | 278 | install-pdf-am: 279 | 280 | install-ps: install-ps-am 281 | 282 | install-ps-am: 283 | 284 | installcheck-am: 285 | 286 | maintainer-clean: maintainer-clean-am 287 | -rm -f Makefile 288 | maintainer-clean-am: distclean-am maintainer-clean-generic 289 | 290 | mostlyclean: mostlyclean-am 291 | 292 | mostlyclean-am: mostlyclean-generic 293 | 294 | pdf: pdf-am 295 | 296 | pdf-am: 297 | 298 | ps: ps-am 299 | 300 | ps-am: 301 | 302 | uninstall-am: 303 | 304 | .MAKE: install-am install-strip 305 | 306 | .PHONY: all all-am check check-am clean clean-generic distclean \ 307 | distclean-generic distdir dvi dvi-am html html-am info info-am \ 308 | install install-am install-data install-data-am install-dvi \ 309 | install-dvi-am install-exec install-exec-am install-html \ 310 | install-html-am install-info install-info-am install-man \ 311 | install-pdf install-pdf-am install-ps install-ps-am \ 312 | install-strip installcheck installcheck-am installdirs \ 313 | maintainer-clean maintainer-clean-generic mostlyclean \ 314 | mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am 315 | 316 | 317 | # Tell versions [3.59,3.63) of GNU make to not export all variables. 318 | # Otherwise a system limit (for SysV at least) may be exceeded. 319 | .NOEXPORT: 320 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | 2009-04-15 Steve Chu 2 | * Remove stats malloc and stats maps due to a security issue. Thanks for reporting this. 3 | 4 | 2009-03-10 Steve Chu 5 | * new option '-G' for setting log file dir(sometime we want to put log files in a different place, such as SSD disk partition) 6 | 7 | 2009-03-05 Steve Chu 8 | * Fix some warnings on 64-bit compiler, thanks to Nicolas 9 | 10 | 2009-02-26 Steve Chu 11 | * Bugfix: 64bit box can not specify memory pool size larger than 2G with '-m' option 12 | * new option '-E' to automatically remove log files that are no longer needed, but PLEASE NOTICE: 13 | - "Automatic log file removal is likely to make catastrophic recovery impossible." 14 | - "Replication applications will rarely want to configure automatic log file removal as it increases the likelihood a master will be unable to satisfy a client's request for a recent log record." So this option will be disabled when replication is on regardless of whether you specify it. 15 | * Bugfix: slight security issue when client specify a negative value length 16 | 17 | 2009-01-13 Steve Chu 18 | * some default settings policy changed(because most of us is using powerful box): 19 | max simultaneous connections ('-c'): 1024 -> 4096 20 | item buffer size('-b'): 512 bytes -> 2048 bytes 21 | in-memmory cache size of BerkeleyDB('-m'): 64MB -> 256MB 22 | log buffer size('-L'): 32KB -> 4MB 23 | 24 | 2009-01-06 Steve Chu 25 | * new 'rget' command patch for 'memcache.py' 26 | 27 | 2008-12-25 Version 1.2.1-beta released 28 | 29 | 2008-12-10 Steve Chu 30 | * new option '-X' to make the BerkeleyDB allocate region memory from the heap instead of from memory backed by the filesystem or system shared memory. If this option enabled, you can not use db_* standalone utilities(use private commands instead), but get performance improved. 31 | 32 | 2008-11-27 Steve Chu 33 | * new flexible query command 'rget' implemented, can do range query based 34 | on keys. See 'doc/rget.txt' for details. 35 | 36 | 2008-11-26 Steve Chu 37 | * more graceful exit 38 | 39 | 2008-11-24 Version 1.2.0 released 40 | 2008-10-16 Version 1.2.0-beta released 41 | 42 | 2008-10-14 Steve Chu 43 | * a new unittest suit 'mdbtest.py' is added 44 | * a new benchmark suit 'mcben.py' is added, now you can get the benchmark in your environment 45 | and find out how fast MemcacheDB can run. 46 | 47 | 2008-10-08 Steve Chu 48 | * lots of statistics code clean up; stats command adjusted for better rendering; now more replication statistics info is provided. 49 | * more compact and verbose message for logging 50 | * lots of replication code clean up for more reliable electing, a new option "-n" is added that allows user to customize the votes of electing. 51 | * "memcache.py" is nearly patched for recent changes on private commands. 52 | 53 | 2008-09-04 Steve Chu 54 | * New option '-e' to set percent of the pages in the cache that should be clean, used for memp_trickle call(only available when '-T' is presented). 55 | 56 | 2008-09-03 Steve Chu 57 | * Replace the database type setting option '-T' with '-B' 58 | * Now '-T' has new meaning that it fires a separate thread to do memp_trickle every xx seconds. 59 | This feature makes the memory pool more effective by reducing too much frequent pages swapping. 60 | 61 | 2008-09-01 Steve Chu 62 | * Now 'append' and 'prepend' commands are supported. 63 | * Merge bugfix code from Memecached community. 64 | * lots of refactors for better implementation and a bit code tuning. 65 | 66 | 2008-08-28 Version 1.1.0 released 67 | 2008-08-28 Version 1.0.4 released(maitaining release) 68 | 69 | 2008-07-25 Steve Chu 70 | * Warning: 'pkget' and 'pvget' private command now has been discarded. 71 | MemcacheDB will be a more memcache protocol compatible daemon(append and 72 | prepend command will be implemented later), and will not add relational 73 | data model any more, the structural data storage will be issued by another 74 | project (now internal only). 75 | 76 | 2008-07-25 Steve Chu 77 | * Bugfix: "multiple get" did not return the right value 78 | 79 | 2008-07-23 Steve Chu 80 | * add more other replication configure parameters 81 | 82 | 2008-07-14 Steve Chu 83 | * rename "default.db" to "data.db" for less ambiguity 84 | 85 | 2008-07-04 Steve Chu 86 | * work well with Mac OS X(tested on Lepard 10.5.4) 87 | * new 'db_compact' private command to compact a btree database 88 | 89 | 2008-07-03 Version 1.1.0-beta released 90 | 91 | 2008-06-26 Steve Chu 92 | * unix socket connectivity now has be well tested. 93 | 94 | 2008-06-13 Steve Chu 95 | * some code refactoring to improve a bit performance 96 | 97 | 2008-06-11 Steve Chu 98 | * now '-b' option is a tuning way, not a limit. item size that smaller than 99 | '-b' value use fast freelist alloc, otherwise, use system 'malloc' instead. 100 | Many thanks to Davies Liu for patches and ideas. 101 | 102 | 2008-06-03 Steve Chu 103 | * new support to BerkeleyDB 4.7 104 | - new version is BerkeleyDB 4.7 only, due to the changed bdb api 105 | - 'rep_set_request' now use time, not the number of messages 106 | 107 | * Bugfix: 'pkget' and "multiple get" that return lots of items may 108 | cause memory overflow so the daemon crashes. Thanks to Davies Liu 109 | 110 | * flooded verbose messages of bdb and replication now move to '-vv' option 111 | 112 | 2008-04-13 Steve Chu 113 | * Changes: 114 | - allow limitation to 'pkget' and 'pvget' command, 115 | use 'pkget/pvget [limit]' to get limited matched items. 116 | - 'memcache.py' is also patched for this feature. 117 | 118 | 2008-04-03 Steve Chu 119 | * New features: 120 | - add '-T' option to set database type, 'btree' or 'hash' 121 | - add '-E' option to enable second database, so we can use 'pvget' 122 | - new command 'pkget' that you can get items with a key prefix 123 | - new command 'pvget' that you can get items with a value prefix 124 | * Changes: 125 | - add support to memcache.py for 'pkget' and 'pvget' command, see 126 | 'tools/memcache.py' 127 | 128 | 2008-03-21 Version 1.0.3 released 129 | 130 | 2008-03-21 Steve Chu 131 | * Bugfix: --with-bdb can not find libdb.so and db.h 132 | 133 | 2008-03-17 Steve Chu 134 | * add a '-A' option to set page size, and also can get this value from 135 | 'stats bdb' 136 | 137 | 2008-03-07 Steve Chu 138 | * new private command 'rep_set_request' available, to set wehther it allows bulk 139 | transfer and also can get this value from 'stats rep'. See 'doc/replication.txt' 140 | * mdbtop.py update 141 | 142 | 2008-03-06 Steve Chu 143 | * new private command 'rep_set_bulk' available, to set wehther it allows bulk 144 | transfer and also can get this value from 'stats rep'. See 'doc/replication.txt' 145 | 146 | 2008-03-05 Steve Chu 147 | * add 'next_lsn' to 'stats rep' to show master-slave sync status 148 | * Make the default ack policy 'DB_REPMGR_ACKS_ONE_PEER' 149 | * upgrade 'mdbtop.py' for better rendering 150 | 151 | 2008-03-04 Version 1.0.2-beta released 152 | 2008-03-03 Steve Chu 153 | * replication configure changed and improved: 154 | - Make the default ack policy 'DB_REPMGR_ACKS_ALL_PEERS' 155 | - Make the default ack timeout 20 millisecond 156 | - two new private commands 'rep_set_ack_policy' and 157 | 'rep_set_ack_timeout' are available to set ack_policy and ack_timeout, 158 | and 'stats rep' also includes this two value. See 159 | 'docs/replication.txt' 160 | 161 | 2008-02-29 Steve Chu 162 | * give a warning if item buffer size larger than 256KB 163 | * memcache.py is patched for private commands. See 'tools/memcache.py' 164 | 165 | 2008-02-26 Steve Chu 166 | * Bugfix: incr/decr is not atomic in multithread, porting mistake from memcached 167 | 168 | 2008-02-21 Version 1.0.1-beta released 169 | 170 | 2008-02-21 Steve Chu 171 | * Bugfix: some private commands may cause seg fault 172 | 173 | 2008-02-20 Steve Chu 174 | * Bugfix: incr/decr command did not update length string 175 | 176 | 2008-02-18 Steve Chu 177 | * merge all read-only private command of replication into 'stats rep' that memcached client 178 | can read it. Original commands are still available. 'stats bdb' is also provided. 179 | * 'mdbtop.py', a new monitor tool is added for easy maintaining. See 'tools/mdbtop.py' 180 | 181 | 2008-02-14 Big Version 1.0.0-beta released 182 | 183 | 2008-02-01 Steve Chu 184 | * Almost entire code is rewritten based on Memcached 1.2.x. 185 | * More memcache protocol compatibility, now multiple get and flags are supported, 186 | also udp and unix socket is ready(not yet tested). 187 | * big performance improved due to memcached 1.2.x code base. Thread is 188 | used to resolve the blocked I/O. 189 | * use standard build tool, "./configure;make;make install" and done. 190 | * two new pravite command for replication to set/get priority. See 191 | "doc/replication.txt". 192 | 193 | 2008-01-21 Version 0.1.1 released 194 | 195 | 2008-01-21 Steve Chu 196 | * Bug fix: out string 'NOT STORED' breaks clients, it should be 197 | 'NOT_STORED'! 198 | 199 | 2007-11-05 Version 0.1.0 released 200 | 201 | 2007-10-30 Cao Kai , Steve Chu 202 | * big replication code merged, let's ship it! 203 | using option "-R" to enable replication, two private command is added for 204 | replication: db_ismaster, db_whoismaster 205 | * code refactor for performance and readability 206 | 207 | 2007-10-23 Version 0.0.4 released 208 | 209 | 2007-10-22 Steve Chu 210 | * add a new struct db_settings for all db related configures. 211 | * big code cleanup for performance. 212 | * "-L" option now uses a unit of kbytes. 213 | 214 | 2007-10-19 Cao Kai 215 | * add option "-C" and create a separate thread to do periodic checkpoint 216 | * add option "-D" and create a separate thread to do periodic deadlock detecting 217 | 218 | 2007-10-15 Novey Donar 219 | * remove the item key in data.data, about 50% db file size reduced, but not compatible 220 | with previous versions, warning to use. 221 | 222 | 2007-10-08 Steve Chu 223 | * add option "-L" to allow to set transaction log buffer 224 | * add option "-N" to allow to set DB_TXN_NOSYNC flag, if someone wanted 225 | lots of performance improved, but warning to use, because it loses transaction's durability 226 | 227 | 2007-09-29 Version 0.0.3 released 228 | 229 | 2007-09-29 Steve Chu 230 | * add command "flush_all" that will truncate a database, warning to use. 231 | * lots of code formated 232 | * Bugfix: Now using "-u" option can get proper db file mode 233 | 234 | 2007-09-21 Version 0.0.2 released 235 | 236 | 2007-09-20 Steve Chu 237 | * move some macro to memcachedb.h 238 | * rename chkpoint to db_checkpoint, for consistency. 239 | * add new command "db_archive" to remove log files that are no longer needed 240 | * README updated 241 | 242 | 2007-09-19 Steve Chu 243 | * enlarge incr value to unsigned int to conform memcache protocol, now supports max value of 4294967295. 244 | 245 | 2007-09-18 Version 0.0.1 released 246 | 247 | -------------------------------------------------------------------------------- /memcachedb.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MemcacheDB - A distributed key-value storage system designed for persistence: 3 | * 4 | * https://gitorious.org/mdb/memcachedb 5 | * 6 | * Based on the BerkeleyDB version at: 7 | * 8 | * http://memcachedb.googlecode.com 9 | * 10 | * The source code of Memcachedb is most based on Memcached: 11 | * 12 | * http://danga.com/memcached/ 13 | * 14 | * Copyright 2012 Howard Chu. All rights reserved. 15 | * Copyright 2008 Steve Chu. All rights reserved. 16 | * 17 | * Use and distribution licensed under the BSD license. See 18 | * the LICENSE file for full text. 19 | * 20 | * Authors: 21 | * Steve Chu 22 | * Howard Chu 23 | * 24 | */ 25 | 26 | #ifdef HAVE_CONFIG_H 27 | #include "config.h" 28 | #endif 29 | 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | 39 | #define DATA_BUFFER_SIZE 2048 40 | #define UDP_READ_BUFFER_SIZE 65536 41 | #define UDP_MAX_PAYLOAD_SIZE 1400 42 | #define UDP_HEADER_SIZE 8 43 | #define MAX_SENDBUF_SIZE (256 * 1024 * 1024) 44 | /* I'm told the max legnth of a 64-bit num converted to string is 20 bytes. 45 | * Plus a few for spaces, \r\n, \0 */ 46 | #define SUFFIX_SIZE 24 47 | 48 | /** Initial size of list of items being returned by "get". */ 49 | #define ITEM_LIST_INITIAL 200 50 | 51 | /** Initial size of the sendmsg() scatter/gather array. */ 52 | #define IOV_LIST_INITIAL 400 53 | 54 | /** Initial number of sendmsg() argument structures to allocate. */ 55 | #define MSG_LIST_INITIAL 10 56 | 57 | /** High water marks for buffer shrinking */ 58 | #define READ_BUFFER_HIGHWAT 8192 59 | #define ITEM_LIST_HIGHWAT 400 60 | #define IOV_LIST_HIGHWAT 600 61 | #define MSG_LIST_HIGHWAT 100 62 | 63 | #define MAX_REP_PRIORITY 1000000 64 | #define MAX_REP_ACK_POLICY 6 65 | #define MAX_REP_NSITES 1000 66 | 67 | /* Default path for a database, and its env home */ 68 | #define DBHOME "/data1/memcachedb" 69 | 70 | #define RGET_MAX_ITEMS 100 71 | 72 | /* Get a consistent bool type */ 73 | #if HAVE_STDBOOL_H 74 | # include 75 | #else 76 | typedef enum {false = 0, true = 1} bool; 77 | #endif 78 | 79 | #if HAVE_STDINT_H 80 | # include 81 | #else 82 | typedef unsigned char uint8_t; 83 | #endif 84 | 85 | /* unistd.h is here */ 86 | #if HAVE_UNISTD_H 87 | # include 88 | #endif 89 | 90 | /* 64-bit Portable printf */ 91 | /* printf macros for size_t, in the style of inttypes.h */ 92 | #ifdef _LP64 93 | #define __PRIS_PREFIX "z" 94 | #else 95 | #define __PRIS_PREFIX 96 | #endif 97 | 98 | /* Use these macros after a % in a printf format string 99 | to get correct 32/64 bit behavior, like this: 100 | size_t size = records.size(); 101 | printf("%"PRIuS"\n", size); */ 102 | 103 | #define PRIdS __PRIS_PREFIX "d" 104 | #define PRIxS __PRIS_PREFIX "x" 105 | #define PRIuS __PRIS_PREFIX "u" 106 | #define PRIXS __PRIS_PREFIX "X" 107 | #define PRIoS __PRIS_PREFIX "o" 108 | 109 | struct stats { 110 | uint32_t curr_conns; 111 | uint32_t total_conns; 112 | uint32_t conn_structs; 113 | uint64_t get_cmds; 114 | uint64_t set_cmds; 115 | uint64_t get_hits; 116 | uint64_t get_misses; 117 | time_t started; /* when the process was started */ 118 | uint64_t bytes_read; 119 | uint64_t bytes_written; 120 | }; 121 | 122 | #define MAX_VERBOSITY_LEVEL 2 123 | 124 | struct settings { 125 | size_t item_buf_size; 126 | int maxconns; 127 | int port; 128 | int udpport; 129 | char *inter; 130 | int verbose; 131 | char *socketpath; /* path to unix socket if using local socket */ 132 | int access; /* access mask (a la chmod) for unix domain socket */ 133 | int num_threads; /* number of libevent threads to run */ 134 | }; 135 | 136 | extern struct stats stats; 137 | extern struct settings settings; 138 | 139 | struct mdb_settings { 140 | char *env_home; /* db env home dir path */ 141 | int txn_nosync; /* DB_TXN_NOSYNC flag, if 1 will lose transaction's durability for performance */ 142 | int chkpoint_val; /* do checkpoint every *db_chkpoint_val* second, 0 for disable */ 143 | u_int64_t cache_size; /* cache size */ 144 | u_int32_t env_flags; /* env open flags */ 145 | }; 146 | 147 | extern struct mdb_settings mdb_settings; 148 | 149 | typedef struct ditem { 150 | uint8_t nsuffix; /* length of flags-and-length string */ 151 | char buf[2]; 152 | /* " flags length\r\n" 153 | * data with terminating \r\n 154 | */ 155 | } ditem; 156 | 157 | typedef struct item { 158 | MDB_val key; 159 | MDB_val data; 160 | } item; 161 | 162 | 163 | /* warning: don't use these macros with a function, as it evals its arg twice */ 164 | #define ITEM_key(item) ((char*)(item)->key.mv_data) 165 | #define ITEM_suflen(item) (((ditem *)((item)->data.mv_data))->nsuffix) 166 | #define ITEM_suffix(item) (((ditem *)((item)->data.mv_data))->buf) 167 | #define ITEM_data(item) ((char *)(ITEM_suffix(item) + ITEM_suflen(item))) 168 | #define ITEM_dlen(item) ((item)->data.mv_size - ITEM_suflen(item) - 1) 169 | #define ITEM_end(item) ((char *)item->data.mv_data + item->data.mv_size) 170 | #if 0 171 | #define ITEM_key(item) ((char*)&((item)->end[0])) 172 | #define ITEM_suffix(item) ((char*) &((item)->end[0]) + (item)->nkey + 1) 173 | #define ITEM_data(item) ((char*) &((item)->end[0]) + (item)->nkey + 1 + (item)->nsuffix) 174 | #define ITEM_ntotal(item) (sizeof(struct _stritem) + (item)->nkey + 1 + (item)->nsuffix + (item)->nbytes) 175 | #endif 176 | 177 | enum conn_states { 178 | conn_listening, /** the socket which listens for connections */ 179 | conn_read, /** reading in a command line */ 180 | conn_write, /** writing out a simple response */ 181 | conn_nread, /** reading in a fixed number of bytes */ 182 | conn_swallow, /** swallowing unnecessary bytes w/o storing */ 183 | conn_closing, /** closing this connection */ 184 | conn_mwrite, /** writing out many items sequentially */ 185 | }; 186 | 187 | #define NREAD_ADD 1 188 | #define NREAD_SET 2 189 | #define NREAD_REPLACE 3 190 | #define NREAD_APPEND 4 191 | #define NREAD_PREPEND 5 192 | 193 | typedef struct conn conn; 194 | struct conn { 195 | int sfd; 196 | int state; 197 | struct event event; 198 | short ev_flags; 199 | short which; /** which events were just triggered */ 200 | 201 | char *rbuf; /** buffer to read commands into */ 202 | char *rcurr; /** but if we parsed some already, this is where we stopped */ 203 | int rsize; /** total allocated size of rbuf */ 204 | int rbytes; /** how much data, starting from rcur, do we have unparsed */ 205 | 206 | char *wbuf; 207 | char *wcurr; 208 | int wsize; 209 | int wbytes; 210 | int write_and_go; /** which state to go into after finishing current write */ 211 | void *write_and_free; /** free this memory after finishing writing */ 212 | 213 | char *ritem; /** when we read in an item's value, it goes here */ 214 | int rlbytes; 215 | 216 | /* data for the nread state */ 217 | 218 | /** 219 | * item is used to hold an item structure created after reading the command 220 | * line of set/add/replace commands, but before we finished reading the actual 221 | * data. The data is read into ITEM_data(item) to avoid extra copying. 222 | */ 223 | 224 | void *item; /* for commands set/add/replace */ 225 | int item_comm; /* which one is it: set/add/replace */ 226 | 227 | /* data for the swallow state */ 228 | int sbytes; /* how many bytes to swallow */ 229 | 230 | /* data for the mwrite state */ 231 | struct iovec *iov; 232 | int iovsize; /* number of elements allocated in iov[] */ 233 | int iovused; /* number of elements used in iov[] */ 234 | 235 | struct msghdr *msglist; 236 | int msgsize; /* number of elements allocated in msglist[] */ 237 | int msgused; /* number of elements used in msglist[] */ 238 | int msgcurr; /* element in msglist[] being transmitted now */ 239 | int msgbytes; /* number of bytes in current msg */ 240 | 241 | /* data for UDP clients */ 242 | bool udp; /* is this is a UDP "connection" */ 243 | int request_id; /* Incoming UDP request ID, if this is a UDP "connection" */ 244 | struct sockaddr request_addr; /* Who sent the most recent request */ 245 | socklen_t request_addr_size; 246 | unsigned char *hdrbuf; /* udp packet headers */ 247 | int hdrsize; /* number of headers' worth of space is allocated */ 248 | conn *next; /* Used for generating a list of conn structures */ 249 | }; 250 | 251 | /* 252 | * Functions 253 | */ 254 | 255 | /* mdb management */ 256 | void mdb_settings_init(void); 257 | void mdb_setup(void); 258 | void start_chkpoint_thread(void); 259 | void mdb_shutdown(void); 260 | void mdb_chkpoint(void); 261 | 262 | /* item management */ 263 | void item_init(void); 264 | item *do_item_from_freelist(void); 265 | int do_item_add_to_freelist(item *it); 266 | item *item_alloc1(MDB_val *key, const int flags, const int nbytes); 267 | int item_alloc_put(MDB_txn *txn, MDB_val *key, const int flags, const int nbytes, item *it); 268 | item *item_alloc2(size_t ntotal); 269 | int item_free(item *it); 270 | int item_get(MDB_txn *txn, MDB_val *key, item *it); 271 | int item_put(MDB_txn *txn, item *it); 272 | int item_delete(MDB_txn *txn, MDB_val *key); 273 | int item_exists(MDB_txn *txn, MDB_val *key); 274 | int item_cget(MDB_cursor *cursorp, MDB_val *key, item *it, u_int32_t flags); 275 | 276 | /* mdb related stats */ 277 | void stats_mdb(char *temp); 278 | 279 | /* conn management */ 280 | conn *do_conn_from_freelist(); 281 | bool do_conn_add_to_freelist(conn *c); 282 | 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); 283 | 284 | char *add_delta(const bool incr, const int64_t delta, char *buf, MDB_val *key); 285 | int store_item(item *item, int comm); 286 | 287 | /* 288 | * In multithreaded mode, we wrap certain functions with lock management and 289 | * replace the logic of some other functions. All wrapped functions have 290 | * "mt_" and "do_" variants. In multithreaded mode, the plain version of a 291 | * function is #define-d to the "mt_" variant, which often just grabs a 292 | * lock and calls the "do_" function. In singlethreaded mode, the "do_" 293 | * function is called directly. 294 | * 295 | * Functions such as the libevent-related calls that need to do cross-thread 296 | * communication in multithreaded mode (rather than actually doing the work 297 | * in the current thread) are called via "dispatch_" frontends, which are 298 | * also #define-d to directly call the underlying code in singlethreaded mode. 299 | */ 300 | #ifdef USE_THREADS 301 | 302 | void thread_init(int nthreads, struct event_base *main_base); 303 | int dispatch_event_add(int thread, conn *c); 304 | void dispatch_conn_new(int sfd, int init_state, int event_flags, int read_buffer_size, int is_udp); 305 | 306 | /* Lock wrappers for cache functions that are called from main loop. */ 307 | conn *mt_conn_from_freelist(void); 308 | bool mt_conn_add_to_freelist(conn *c); 309 | int mt_is_listen_thread(void); 310 | item *mt_item_from_freelist(void); 311 | int mt_item_add_to_freelist(item *it); 312 | void mt_stats_lock(void); 313 | void mt_stats_unlock(void); 314 | 315 | # define conn_from_freelist() mt_conn_from_freelist() 316 | # define conn_add_to_freelist(x) mt_conn_add_to_freelist(x) 317 | # define is_listen_thread() mt_is_listen_thread() 318 | # define item_from_freelist() mt_item_from_freelist() 319 | # define item_add_to_freelist(x) mt_item_add_to_freelist(x) 320 | 321 | # define STATS_LOCK() mt_stats_lock() 322 | # define STATS_UNLOCK() mt_stats_unlock() 323 | 324 | #else /* !USE_THREADS */ 325 | 326 | # define conn_from_freelist() do_conn_from_freelist() 327 | # define conn_add_to_freelist(x) do_conn_add_to_freelist(x) 328 | # define dispatch_conn_new(x,y,z,a,b) conn_new(x,y,z,a,b,main_base) 329 | # define dispatch_event_add(t,c) event_add(&(c)->event, 0) 330 | # define is_listen_thread() 1 331 | # define item_from_freelist() do_item_from_freelist() 332 | # define item_add_to_freelist(x) do_item_add_to_freelist(x) 333 | # define thread_init(x,y) 0 334 | 335 | # define STATS_LOCK() /**/ 336 | # define STATS_UNLOCK() /**/ 337 | 338 | #endif /* !USE_THREADS */ 339 | 340 | extern MDB_env *env; 341 | extern MDB_dbi dbi; 342 | extern int daemon_quit; 343 | -------------------------------------------------------------------------------- /missing: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # Common stub for a few missing GNU programs while installing. 3 | 4 | scriptversion=2006-05-10.23 5 | 6 | # Copyright (C) 1996, 1997, 1999, 2000, 2002, 2003, 2004, 2005, 2006 7 | # Free Software Foundation, Inc. 8 | # Originally by Fran,cois Pinard , 1996. 9 | 10 | # This program is free software; you can redistribute it and/or modify 11 | # it under the terms of the GNU General Public License as published by 12 | # the Free Software Foundation; either version 2, or (at your option) 13 | # any later version. 14 | 15 | # This program is distributed in the hope that it will be useful, 16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 | # GNU General Public License for more details. 19 | 20 | # You should have received a copy of the GNU General Public License 21 | # along with this program; if not, write to the Free Software 22 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 23 | # 02110-1301, USA. 24 | 25 | # As a special exception to the GNU General Public License, if you 26 | # distribute this file as part of a program that contains a 27 | # configuration script generated by Autoconf, you may include it under 28 | # the same distribution terms that you use for the rest of that program. 29 | 30 | if test $# -eq 0; then 31 | echo 1>&2 "Try \`$0 --help' for more information" 32 | exit 1 33 | fi 34 | 35 | run=: 36 | sed_output='s/.* --output[ =]\([^ ]*\).*/\1/p' 37 | sed_minuso='s/.* -o \([^ ]*\).*/\1/p' 38 | 39 | # In the cases where this matters, `missing' is being run in the 40 | # srcdir already. 41 | if test -f configure.ac; then 42 | configure_ac=configure.ac 43 | else 44 | configure_ac=configure.in 45 | fi 46 | 47 | msg="missing on your system" 48 | 49 | case $1 in 50 | --run) 51 | # Try to run requested program, and just exit if it succeeds. 52 | run= 53 | shift 54 | "$@" && exit 0 55 | # Exit code 63 means version mismatch. This often happens 56 | # when the user try to use an ancient version of a tool on 57 | # a file that requires a minimum version. In this case we 58 | # we should proceed has if the program had been absent, or 59 | # if --run hadn't been passed. 60 | if test $? = 63; then 61 | run=: 62 | msg="probably too old" 63 | fi 64 | ;; 65 | 66 | -h|--h|--he|--hel|--help) 67 | echo "\ 68 | $0 [OPTION]... PROGRAM [ARGUMENT]... 69 | 70 | Handle \`PROGRAM [ARGUMENT]...' for when PROGRAM is missing, or return an 71 | error status if there is no known handling for PROGRAM. 72 | 73 | Options: 74 | -h, --help display this help and exit 75 | -v, --version output version information and exit 76 | --run try to run the given command, and emulate it if it fails 77 | 78 | Supported PROGRAM values: 79 | aclocal touch file \`aclocal.m4' 80 | autoconf touch file \`configure' 81 | autoheader touch file \`config.h.in' 82 | autom4te touch the output file, or create a stub one 83 | automake touch all \`Makefile.in' files 84 | bison create \`y.tab.[ch]', if possible, from existing .[ch] 85 | flex create \`lex.yy.c', if possible, from existing .c 86 | help2man touch the output file 87 | lex create \`lex.yy.c', if possible, from existing .c 88 | makeinfo touch the output file 89 | tar try tar, gnutar, gtar, then tar without non-portable flags 90 | yacc create \`y.tab.[ch]', if possible, from existing .[ch] 91 | 92 | Send bug reports to ." 93 | exit $? 94 | ;; 95 | 96 | -v|--v|--ve|--ver|--vers|--versi|--versio|--version) 97 | echo "missing $scriptversion (GNU Automake)" 98 | exit $? 99 | ;; 100 | 101 | -*) 102 | echo 1>&2 "$0: Unknown \`$1' option" 103 | echo 1>&2 "Try \`$0 --help' for more information" 104 | exit 1 105 | ;; 106 | 107 | esac 108 | 109 | # Now exit if we have it, but it failed. Also exit now if we 110 | # don't have it and --version was passed (most likely to detect 111 | # the program). 112 | case $1 in 113 | lex|yacc) 114 | # Not GNU programs, they don't have --version. 115 | ;; 116 | 117 | tar) 118 | if test -n "$run"; then 119 | echo 1>&2 "ERROR: \`tar' requires --run" 120 | exit 1 121 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 122 | exit 1 123 | fi 124 | ;; 125 | 126 | *) 127 | if test -z "$run" && ($1 --version) > /dev/null 2>&1; then 128 | # We have it, but it failed. 129 | exit 1 130 | elif test "x$2" = "x--version" || test "x$2" = "x--help"; then 131 | # Could not run --version or --help. This is probably someone 132 | # running `$TOOL --version' or `$TOOL --help' to check whether 133 | # $TOOL exists and not knowing $TOOL uses missing. 134 | exit 1 135 | fi 136 | ;; 137 | esac 138 | 139 | # If it does not exist, or fails to run (possibly an outdated version), 140 | # try to emulate it. 141 | case $1 in 142 | aclocal*) 143 | echo 1>&2 "\ 144 | WARNING: \`$1' is $msg. You should only need it if 145 | you modified \`acinclude.m4' or \`${configure_ac}'. You might want 146 | to install the \`Automake' and \`Perl' packages. Grab them from 147 | any GNU archive site." 148 | touch aclocal.m4 149 | ;; 150 | 151 | autoconf) 152 | echo 1>&2 "\ 153 | WARNING: \`$1' is $msg. You should only need it if 154 | you modified \`${configure_ac}'. You might want to install the 155 | \`Autoconf' and \`GNU m4' packages. Grab them from any GNU 156 | archive site." 157 | touch configure 158 | ;; 159 | 160 | autoheader) 161 | echo 1>&2 "\ 162 | WARNING: \`$1' is $msg. You should only need it if 163 | you modified \`acconfig.h' or \`${configure_ac}'. You might want 164 | to install the \`Autoconf' and \`GNU m4' packages. Grab them 165 | from any GNU archive site." 166 | files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}` 167 | test -z "$files" && files="config.h" 168 | touch_files= 169 | for f in $files; do 170 | case $f in 171 | *:*) touch_files="$touch_files "`echo "$f" | 172 | sed -e 's/^[^:]*://' -e 's/:.*//'`;; 173 | *) touch_files="$touch_files $f.in";; 174 | esac 175 | done 176 | touch $touch_files 177 | ;; 178 | 179 | automake*) 180 | echo 1>&2 "\ 181 | WARNING: \`$1' is $msg. You should only need it if 182 | you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'. 183 | You might want to install the \`Automake' and \`Perl' packages. 184 | Grab them from any GNU archive site." 185 | find . -type f -name Makefile.am -print | 186 | sed 's/\.am$/.in/' | 187 | while read f; do touch "$f"; done 188 | ;; 189 | 190 | autom4te) 191 | echo 1>&2 "\ 192 | WARNING: \`$1' is needed, but is $msg. 193 | You might have modified some files without having the 194 | proper tools for further handling them. 195 | You can get \`$1' as part of \`Autoconf' from any GNU 196 | archive site." 197 | 198 | file=`echo "$*" | sed -n "$sed_output"` 199 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 200 | if test -f "$file"; then 201 | touch $file 202 | else 203 | test -z "$file" || exec >$file 204 | echo "#! /bin/sh" 205 | echo "# Created by GNU Automake missing as a replacement of" 206 | echo "# $ $@" 207 | echo "exit 0" 208 | chmod +x $file 209 | exit 1 210 | fi 211 | ;; 212 | 213 | bison|yacc) 214 | echo 1>&2 "\ 215 | WARNING: \`$1' $msg. You should only need it if 216 | you modified a \`.y' file. You may need the \`Bison' package 217 | in order for those modifications to take effect. You can get 218 | \`Bison' from any GNU archive site." 219 | rm -f y.tab.c y.tab.h 220 | if test $# -ne 1; then 221 | eval LASTARG="\${$#}" 222 | case $LASTARG in 223 | *.y) 224 | SRCFILE=`echo "$LASTARG" | sed 's/y$/c/'` 225 | if test -f "$SRCFILE"; then 226 | cp "$SRCFILE" y.tab.c 227 | fi 228 | SRCFILE=`echo "$LASTARG" | sed 's/y$/h/'` 229 | if test -f "$SRCFILE"; then 230 | cp "$SRCFILE" y.tab.h 231 | fi 232 | ;; 233 | esac 234 | fi 235 | if test ! -f y.tab.h; then 236 | echo >y.tab.h 237 | fi 238 | if test ! -f y.tab.c; then 239 | echo 'main() { return 0; }' >y.tab.c 240 | fi 241 | ;; 242 | 243 | lex|flex) 244 | echo 1>&2 "\ 245 | WARNING: \`$1' is $msg. You should only need it if 246 | you modified a \`.l' file. You may need the \`Flex' package 247 | in order for those modifications to take effect. You can get 248 | \`Flex' from any GNU archive site." 249 | rm -f lex.yy.c 250 | if test $# -ne 1; then 251 | eval LASTARG="\${$#}" 252 | case $LASTARG in 253 | *.l) 254 | SRCFILE=`echo "$LASTARG" | sed 's/l$/c/'` 255 | if test -f "$SRCFILE"; then 256 | cp "$SRCFILE" lex.yy.c 257 | fi 258 | ;; 259 | esac 260 | fi 261 | if test ! -f lex.yy.c; then 262 | echo 'main() { return 0; }' >lex.yy.c 263 | fi 264 | ;; 265 | 266 | help2man) 267 | echo 1>&2 "\ 268 | WARNING: \`$1' is $msg. You should only need it if 269 | you modified a dependency of a manual page. You may need the 270 | \`Help2man' package in order for those modifications to take 271 | effect. You can get \`Help2man' from any GNU archive site." 272 | 273 | file=`echo "$*" | sed -n "$sed_output"` 274 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 275 | if test -f "$file"; then 276 | touch $file 277 | else 278 | test -z "$file" || exec >$file 279 | echo ".ab help2man is required to generate this page" 280 | exit 1 281 | fi 282 | ;; 283 | 284 | makeinfo) 285 | echo 1>&2 "\ 286 | WARNING: \`$1' is $msg. You should only need it if 287 | you modified a \`.texi' or \`.texinfo' file, or any other file 288 | indirectly affecting the aspect of the manual. The spurious 289 | call might also be the consequence of using a buggy \`make' (AIX, 290 | DU, IRIX). You might want to install the \`Texinfo' package or 291 | the \`GNU make' package. Grab either from any GNU archive site." 292 | # The file to touch is that specified with -o ... 293 | file=`echo "$*" | sed -n "$sed_output"` 294 | test -z "$file" && file=`echo "$*" | sed -n "$sed_minuso"` 295 | if test -z "$file"; then 296 | # ... or it is the one specified with @setfilename ... 297 | infile=`echo "$*" | sed 's/.* \([^ ]*\) *$/\1/'` 298 | file=`sed -n ' 299 | /^@setfilename/{ 300 | s/.* \([^ ]*\) *$/\1/ 301 | p 302 | q 303 | }' $infile` 304 | # ... or it is derived from the source name (dir/f.texi becomes f.info) 305 | test -z "$file" && file=`echo "$infile" | sed 's,.*/,,;s,.[^.]*$,,'`.info 306 | fi 307 | # If the file does not exist, the user really needs makeinfo; 308 | # let's fail without touching anything. 309 | test -f $file || exit 1 310 | touch $file 311 | ;; 312 | 313 | tar) 314 | shift 315 | 316 | # We have already tried tar in the generic part. 317 | # Look for gnutar/gtar before invocation to avoid ugly error 318 | # messages. 319 | if (gnutar --version > /dev/null 2>&1); then 320 | gnutar "$@" && exit 0 321 | fi 322 | if (gtar --version > /dev/null 2>&1); then 323 | gtar "$@" && exit 0 324 | fi 325 | firstarg="$1" 326 | if shift; then 327 | case $firstarg in 328 | *o*) 329 | firstarg=`echo "$firstarg" | sed s/o//` 330 | tar "$firstarg" "$@" && exit 0 331 | ;; 332 | esac 333 | case $firstarg in 334 | *h*) 335 | firstarg=`echo "$firstarg" | sed s/h//` 336 | tar "$firstarg" "$@" && exit 0 337 | ;; 338 | esac 339 | fi 340 | 341 | echo 1>&2 "\ 342 | WARNING: I can't seem to be able to run \`tar' with the given arguments. 343 | You may want to install GNU tar or Free paxutils, or check the 344 | command line arguments." 345 | exit 1 346 | ;; 347 | 348 | *) 349 | echo 1>&2 "\ 350 | WARNING: \`$1' is needed, and is $msg. 351 | You might have modified some files without having the 352 | proper tools for further handling them. Check the \`README' file, 353 | it often tells you about the needed prerequisites for installing 354 | this package. You may also peek at any GNU archive site, in case 355 | some other package would contain this missing \`$1' program." 356 | exit 1 357 | ;; 358 | esac 359 | 360 | exit 0 361 | 362 | # Local variables: 363 | # eval: (add-hook 'write-file-hooks 'time-stamp) 364 | # time-stamp-start: "scriptversion=" 365 | # time-stamp-format: "%:y-%02m-%02d.%02H" 366 | # time-stamp-end: "$" 367 | # End: 368 | -------------------------------------------------------------------------------- /thread.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MemcacheDB - A distributed key-value storage system designed for persistence: 3 | * 4 | * https://gitorious.org/mdb/memcachedb 5 | * 6 | * Based on the BerkeleyDB version at: 7 | * 8 | * http://memcachedb.googlecode.com 9 | * 10 | * The source code of Memcachedb is most based on Memcached: 11 | * 12 | * http://danga.com/memcached/ 13 | * 14 | * Copyright 2012 Howard Chu. All rights reserved. 15 | * Copyright 2008 Steve Chu. All rights reserved. 16 | * 17 | * Use and distribution licensed under the BSD license. See 18 | * the LICENSE file for full text. 19 | * 20 | * Authors: 21 | * Steve Chu 22 | * Howard Chu 23 | * 24 | */ 25 | 26 | #include "memcachedb.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #ifdef HAVE_MALLOC_H 33 | #include 34 | #endif 35 | 36 | #ifdef HAVE_STRING_H 37 | #include 38 | #endif 39 | 40 | #ifdef USE_THREADS 41 | 42 | #include 43 | 44 | #define ITEMS_PER_ALLOC 64 45 | 46 | /* An item in the connection queue. */ 47 | typedef struct conn_queue_item CQ_ITEM; 48 | struct conn_queue_item { 49 | int sfd; 50 | int init_state; 51 | int event_flags; 52 | int read_buffer_size; 53 | int is_udp; 54 | CQ_ITEM *next; 55 | }; 56 | 57 | /* A connection queue. */ 58 | typedef struct conn_queue CQ; 59 | struct conn_queue { 60 | CQ_ITEM *head; 61 | CQ_ITEM *tail; 62 | pthread_mutex_t lock; 63 | pthread_cond_t cond; 64 | }; 65 | 66 | /* Lock for connection freelist */ 67 | static pthread_mutex_t conn_lock; 68 | 69 | /* Lock for item buffer freelist */ 70 | static pthread_mutex_t ibuffer_lock; 71 | 72 | /* Lock for global stats */ 73 | static pthread_mutex_t stats_lock; 74 | 75 | /* Free list of CQ_ITEM structs */ 76 | static CQ_ITEM *cqi_freelist; 77 | static pthread_mutex_t cqi_freelist_lock; 78 | 79 | /* 80 | * Each libevent instance has a wakeup pipe, which other threads 81 | * can use to signal that they've put a new connection on its queue. 82 | */ 83 | typedef struct { 84 | pthread_t thread_id; /* unique ID of this thread */ 85 | struct event_base *base; /* libevent handle this thread uses */ 86 | struct event notify_event; /* listen event for notify pipe */ 87 | int notify_receive_fd; /* receiving end of notify pipe */ 88 | int notify_send_fd; /* sending end of notify pipe */ 89 | CQ new_conn_queue; /* queue of new connections to handle */ 90 | } LIBEVENT_THREAD; 91 | 92 | static LIBEVENT_THREAD *threads; 93 | 94 | /* 95 | * Number of threads that have finished setting themselves up. 96 | */ 97 | static int init_count = 0; 98 | static pthread_mutex_t init_lock; 99 | static pthread_cond_t init_cond; 100 | 101 | 102 | static void thread_libevent_process(int fd, short which, void *arg); 103 | 104 | /* 105 | * Initializes a connection queue. 106 | */ 107 | static void cq_init(CQ *cq) { 108 | pthread_mutex_init(&cq->lock, NULL); 109 | pthread_cond_init(&cq->cond, NULL); 110 | cq->head = NULL; 111 | cq->tail = NULL; 112 | } 113 | 114 | /* 115 | * Waits for work on a connection queue. 116 | */ 117 | static CQ_ITEM *cq_pop(CQ *cq) { 118 | CQ_ITEM *item; 119 | 120 | pthread_mutex_lock(&cq->lock); 121 | while (NULL == cq->head) 122 | pthread_cond_wait(&cq->cond, &cq->lock); 123 | item = cq->head; 124 | cq->head = item->next; 125 | if (NULL == cq->head) 126 | cq->tail = NULL; 127 | pthread_mutex_unlock(&cq->lock); 128 | 129 | return item; 130 | } 131 | 132 | /* 133 | * Looks for an item on a connection queue, but doesn't block if there isn't 134 | * one. 135 | * Returns the item, or NULL if no item is available 136 | */ 137 | static CQ_ITEM *cq_peek(CQ *cq) { 138 | CQ_ITEM *item; 139 | 140 | pthread_mutex_lock(&cq->lock); 141 | item = cq->head; 142 | if (NULL != item) { 143 | cq->head = item->next; 144 | if (NULL == cq->head) 145 | cq->tail = NULL; 146 | } 147 | pthread_mutex_unlock(&cq->lock); 148 | 149 | return item; 150 | } 151 | 152 | /* 153 | * Adds an item to a connection queue. 154 | */ 155 | static void cq_push(CQ *cq, CQ_ITEM *item) { 156 | item->next = NULL; 157 | 158 | pthread_mutex_lock(&cq->lock); 159 | if (NULL == cq->tail) 160 | cq->head = item; 161 | else 162 | cq->tail->next = item; 163 | cq->tail = item; 164 | pthread_cond_signal(&cq->cond); 165 | pthread_mutex_unlock(&cq->lock); 166 | } 167 | 168 | /* 169 | * Returns a fresh connection queue item. 170 | */ 171 | static CQ_ITEM *cqi_new() { 172 | CQ_ITEM *item = NULL; 173 | pthread_mutex_lock(&cqi_freelist_lock); 174 | if (cqi_freelist) { 175 | item = cqi_freelist; 176 | cqi_freelist = item->next; 177 | } 178 | pthread_mutex_unlock(&cqi_freelist_lock); 179 | 180 | if (NULL == item) { 181 | int i; 182 | 183 | /* Allocate a bunch of items at once to reduce fragmentation */ 184 | item = malloc(sizeof(CQ_ITEM) * ITEMS_PER_ALLOC); 185 | if (NULL == item) 186 | return NULL; 187 | 188 | /* 189 | * Link together all the new items except the first one 190 | * (which we'll return to the caller) for placement on 191 | * the freelist. 192 | */ 193 | for (i = 2; i < ITEMS_PER_ALLOC; i++) 194 | item[i - 1].next = &item[i]; 195 | 196 | pthread_mutex_lock(&cqi_freelist_lock); 197 | item[ITEMS_PER_ALLOC - 1].next = cqi_freelist; 198 | cqi_freelist = &item[1]; 199 | pthread_mutex_unlock(&cqi_freelist_lock); 200 | } 201 | 202 | return item; 203 | } 204 | 205 | 206 | /* 207 | * Frees a connection queue item (adds it to the freelist.) 208 | */ 209 | static void cqi_free(CQ_ITEM *item) { 210 | pthread_mutex_lock(&cqi_freelist_lock); 211 | item->next = cqi_freelist; 212 | cqi_freelist = item; 213 | pthread_mutex_unlock(&cqi_freelist_lock); 214 | } 215 | 216 | 217 | /* 218 | * Creates a worker thread. 219 | */ 220 | static void create_worker(void *(*func)(void *), void *arg) { 221 | pthread_t thread; 222 | pthread_attr_t attr; 223 | int ret; 224 | 225 | pthread_attr_init(&attr); 226 | 227 | if ((ret = pthread_create(&thread, &attr, func, arg)) != 0) { 228 | fprintf(stderr, "Can't create thread: %s\n", 229 | strerror(ret)); 230 | exit(1); 231 | } 232 | } 233 | 234 | 235 | /* 236 | * Pulls a conn structure from the freelist, if one is available. 237 | */ 238 | conn *mt_conn_from_freelist() { 239 | conn *c; 240 | 241 | pthread_mutex_lock(&conn_lock); 242 | c = do_conn_from_freelist(); 243 | pthread_mutex_unlock(&conn_lock); 244 | 245 | return c; 246 | } 247 | 248 | 249 | /* 250 | * Adds a conn structure to the freelist. 251 | * 252 | * Returns 0 on success, 1 if the structure couldn't be added. 253 | */ 254 | bool mt_conn_add_to_freelist(conn *c) { 255 | bool result; 256 | 257 | pthread_mutex_lock(&conn_lock); 258 | result = do_conn_add_to_freelist(c); 259 | pthread_mutex_unlock(&conn_lock); 260 | 261 | return result; 262 | } 263 | 264 | /* 265 | * Pulls a item buffer from the freelist, if one is available. 266 | */ 267 | 268 | item *mt_item_from_freelist(void) { 269 | item *it; 270 | pthread_mutex_lock(&ibuffer_lock); 271 | it = do_item_from_freelist(); 272 | pthread_mutex_unlock(&ibuffer_lock); 273 | return it; 274 | } 275 | 276 | /* 277 | * Adds a item buffer to the freelist. 278 | * 279 | * Returns 0 on success, 1 if the buffer couldn't be added. 280 | */ 281 | int mt_item_add_to_freelist(item *it){ 282 | int result; 283 | 284 | pthread_mutex_lock(&ibuffer_lock); 285 | result = do_item_add_to_freelist(it); 286 | pthread_mutex_unlock(&ibuffer_lock); 287 | 288 | return result; 289 | } 290 | 291 | 292 | /****************************** LIBEVENT THREADS *****************************/ 293 | 294 | /* 295 | * Set up a thread's information. 296 | */ 297 | static void setup_thread(LIBEVENT_THREAD *me) { 298 | if (! me->base) { 299 | me->base = event_init(); 300 | if (! me->base) { 301 | fprintf(stderr, "Can't allocate event base\n"); 302 | exit(1); 303 | } 304 | } 305 | 306 | /* Listen for notifications from other threads */ 307 | event_set(&me->notify_event, me->notify_receive_fd, 308 | EV_READ | EV_PERSIST, thread_libevent_process, me); 309 | event_base_set(me->base, &me->notify_event); 310 | 311 | if (event_add(&me->notify_event, 0) == -1) { 312 | fprintf(stderr, "Can't monitor libevent notify pipe\n"); 313 | exit(1); 314 | } 315 | 316 | cq_init(&me->new_conn_queue); 317 | } 318 | 319 | 320 | /* 321 | * Worker thread: main event loop 322 | */ 323 | static void *worker_libevent(void *arg) { 324 | LIBEVENT_THREAD *me = arg; 325 | 326 | /* Any per-thread setup can happen here; thread_init() will block until 327 | * all threads have finished initializing. 328 | */ 329 | 330 | pthread_mutex_lock(&init_lock); 331 | init_count++; 332 | pthread_cond_signal(&init_cond); 333 | pthread_mutex_unlock(&init_lock); 334 | 335 | event_base_loop(me->base, 0); 336 | return NULL; 337 | } 338 | 339 | 340 | /* 341 | * Processes an incoming "handle a new connection" item. This is called when 342 | * input arrives on the libevent wakeup pipe. 343 | */ 344 | static void thread_libevent_process(int fd, short which, void *arg) { 345 | LIBEVENT_THREAD *me = arg; 346 | CQ_ITEM *item; 347 | char buf[1]; 348 | 349 | if (read(fd, buf, 1) != 1) 350 | if (settings.verbose > 0) 351 | fprintf(stderr, "Can't read from libevent pipe\n"); 352 | 353 | item = cq_peek(&me->new_conn_queue); 354 | 355 | if (NULL != item) { 356 | conn *c = conn_new(item->sfd, item->init_state, item->event_flags, 357 | item->read_buffer_size, item->is_udp, me->base); 358 | if (c == NULL) { 359 | if (item->is_udp) { 360 | fprintf(stderr, "Can't listen for events on UDP socket\n"); 361 | exit(1); 362 | } else { 363 | if (settings.verbose > 0) { 364 | fprintf(stderr, "Can't listen for events on fd %d\n", 365 | item->sfd); 366 | } 367 | close(item->sfd); 368 | } 369 | } 370 | cqi_free(item); 371 | } 372 | } 373 | 374 | /* Which thread we assigned a connection to most recently. */ 375 | static int last_thread = -1; 376 | 377 | /* 378 | * Dispatches a new connection to another thread. This is only ever called 379 | * from the main thread, either during initialization (for UDP) or because 380 | * of an incoming connection. 381 | */ 382 | void dispatch_conn_new(int sfd, int init_state, int event_flags, 383 | int read_buffer_size, int is_udp) { 384 | CQ_ITEM *item = cqi_new(); 385 | int thread = (last_thread + 1) % settings.num_threads; 386 | 387 | last_thread = thread; 388 | 389 | item->sfd = sfd; 390 | item->init_state = init_state; 391 | item->event_flags = event_flags; 392 | item->read_buffer_size = read_buffer_size; 393 | item->is_udp = is_udp; 394 | 395 | cq_push(&threads[thread].new_conn_queue, item); 396 | if (write(threads[thread].notify_send_fd, "", 1) != 1) { 397 | perror("Writing to thread notify pipe"); 398 | } 399 | } 400 | 401 | /* 402 | * Returns true if this is the thread that listens for new TCP connections. 403 | */ 404 | int mt_is_listen_thread() { 405 | return pthread_self() == threads[0].thread_id; 406 | } 407 | 408 | /******************************* GLOBAL STATS ******************************/ 409 | 410 | void mt_stats_lock() { 411 | pthread_mutex_lock(&stats_lock); 412 | } 413 | 414 | void mt_stats_unlock() { 415 | pthread_mutex_unlock(&stats_lock); 416 | } 417 | 418 | /* 419 | * Initializes the thread subsystem, creating various worker threads. 420 | * 421 | * nthreads Number of event handler threads to spawn 422 | * main_base Event base for main thread 423 | */ 424 | void thread_init(int nthreads, struct event_base *main_base) { 425 | int i; 426 | 427 | pthread_mutex_init(&ibuffer_lock, NULL); 428 | pthread_mutex_init(&conn_lock, NULL); 429 | pthread_mutex_init(&stats_lock, NULL); 430 | 431 | pthread_mutex_init(&init_lock, NULL); 432 | pthread_cond_init(&init_cond, NULL); 433 | 434 | pthread_mutex_init(&cqi_freelist_lock, NULL); 435 | cqi_freelist = NULL; 436 | 437 | threads = malloc(sizeof(LIBEVENT_THREAD) * nthreads); 438 | if (! threads) { 439 | perror("Can't allocate thread descriptors"); 440 | exit(1); 441 | } 442 | 443 | threads[0].base = main_base; 444 | threads[0].thread_id = pthread_self(); 445 | 446 | for (i = 0; i < nthreads; i++) { 447 | int fds[2]; 448 | if (pipe(fds)) { 449 | perror("Can't create notify pipe"); 450 | exit(1); 451 | } 452 | 453 | threads[i].notify_receive_fd = fds[0]; 454 | threads[i].notify_send_fd = fds[1]; 455 | 456 | setup_thread(&threads[i]); 457 | } 458 | 459 | /* Create threads after we've done all the libevent setup. */ 460 | for (i = 1; i < nthreads; i++) { 461 | create_worker(worker_libevent, &threads[i]); 462 | } 463 | 464 | /* Wait for all the threads to set themselves up before returning. */ 465 | pthread_mutex_lock(&init_lock); 466 | init_count++; /* main thread */ 467 | while (init_count < nthreads) { 468 | pthread_cond_wait(&init_cond, &init_lock); 469 | } 470 | pthread_mutex_unlock(&init_lock); 471 | } 472 | 473 | #endif 474 | -------------------------------------------------------------------------------- /install-sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # install - install a program, script, or datafile 3 | 4 | scriptversion=2006-10-14.15 5 | 6 | # This originates from X11R5 (mit/util/scripts/install.sh), which was 7 | # later released in X11R6 (xc/config/util/install.sh) with the 8 | # following copyright and license. 9 | # 10 | # Copyright (C) 1994 X Consortium 11 | # 12 | # Permission is hereby granted, free of charge, to any person obtaining a copy 13 | # of this software and associated documentation files (the "Software"), to 14 | # deal in the Software without restriction, including without limitation the 15 | # rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 16 | # sell copies of the Software, and to permit persons to whom the Software is 17 | # furnished to do so, subject to the following conditions: 18 | # 19 | # The above copyright notice and this permission notice shall be included in 20 | # all copies or substantial portions of the Software. 21 | # 22 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | # X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 | # AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- 27 | # TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 | # 29 | # Except as contained in this notice, the name of the X Consortium shall not 30 | # be used in advertising or otherwise to promote the sale, use or other deal- 31 | # ings in this Software without prior written authorization from the X Consor- 32 | # tium. 33 | # 34 | # 35 | # FSF changes to this file are in the public domain. 36 | # 37 | # Calling this script install-sh is preferred over install.sh, to prevent 38 | # `make' implicit rules from creating a file called install from it 39 | # when there is no Makefile. 40 | # 41 | # This script is compatible with the BSD install script, but was written 42 | # from scratch. 43 | 44 | nl=' 45 | ' 46 | IFS=" "" $nl" 47 | 48 | # set DOITPROG to echo to test this script 49 | 50 | # Don't use :- since 4.3BSD and earlier shells don't like it. 51 | doit="${DOITPROG-}" 52 | if test -z "$doit"; then 53 | doit_exec=exec 54 | else 55 | doit_exec=$doit 56 | fi 57 | 58 | # Put in absolute file names if you don't have them in your path; 59 | # or use environment vars. 60 | 61 | mvprog="${MVPROG-mv}" 62 | cpprog="${CPPROG-cp}" 63 | chmodprog="${CHMODPROG-chmod}" 64 | chownprog="${CHOWNPROG-chown}" 65 | chgrpprog="${CHGRPPROG-chgrp}" 66 | stripprog="${STRIPPROG-strip}" 67 | rmprog="${RMPROG-rm}" 68 | mkdirprog="${MKDIRPROG-mkdir}" 69 | 70 | posix_glob= 71 | posix_mkdir= 72 | 73 | # Desired mode of installed file. 74 | mode=0755 75 | 76 | chmodcmd=$chmodprog 77 | chowncmd= 78 | chgrpcmd= 79 | stripcmd= 80 | rmcmd="$rmprog -f" 81 | mvcmd="$mvprog" 82 | src= 83 | dst= 84 | dir_arg= 85 | dstarg= 86 | no_target_directory= 87 | 88 | usage="Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE 89 | or: $0 [OPTION]... SRCFILES... DIRECTORY 90 | or: $0 [OPTION]... -t DIRECTORY SRCFILES... 91 | or: $0 [OPTION]... -d DIRECTORIES... 92 | 93 | In the 1st form, copy SRCFILE to DSTFILE. 94 | In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. 95 | In the 4th, create DIRECTORIES. 96 | 97 | Options: 98 | -c (ignored) 99 | -d create directories instead of installing files. 100 | -g GROUP $chgrpprog installed files to GROUP. 101 | -m MODE $chmodprog installed files to MODE. 102 | -o USER $chownprog installed files to USER. 103 | -s $stripprog installed files. 104 | -t DIRECTORY install into DIRECTORY. 105 | -T report an error if DSTFILE is a directory. 106 | --help display this help and exit. 107 | --version display version info and exit. 108 | 109 | Environment variables override the default commands: 110 | CHGRPPROG CHMODPROG CHOWNPROG CPPROG MKDIRPROG MVPROG RMPROG STRIPPROG 111 | " 112 | 113 | while test $# -ne 0; do 114 | case $1 in 115 | -c) shift 116 | continue;; 117 | 118 | -d) dir_arg=true 119 | shift 120 | continue;; 121 | 122 | -g) chgrpcmd="$chgrpprog $2" 123 | shift 124 | shift 125 | continue;; 126 | 127 | --help) echo "$usage"; exit $?;; 128 | 129 | -m) mode=$2 130 | shift 131 | shift 132 | case $mode in 133 | *' '* | *' '* | *' 134 | '* | *'*'* | *'?'* | *'['*) 135 | echo "$0: invalid mode: $mode" >&2 136 | exit 1;; 137 | esac 138 | continue;; 139 | 140 | -o) chowncmd="$chownprog $2" 141 | shift 142 | shift 143 | continue;; 144 | 145 | -s) stripcmd=$stripprog 146 | shift 147 | continue;; 148 | 149 | -t) dstarg=$2 150 | shift 151 | shift 152 | continue;; 153 | 154 | -T) no_target_directory=true 155 | shift 156 | continue;; 157 | 158 | --version) echo "$0 $scriptversion"; exit $?;; 159 | 160 | --) shift 161 | break;; 162 | 163 | -*) echo "$0: invalid option: $1" >&2 164 | exit 1;; 165 | 166 | *) break;; 167 | esac 168 | done 169 | 170 | if test $# -ne 0 && test -z "$dir_arg$dstarg"; then 171 | # When -d is used, all remaining arguments are directories to create. 172 | # When -t is used, the destination is already specified. 173 | # Otherwise, the last argument is the destination. Remove it from $@. 174 | for arg 175 | do 176 | if test -n "$dstarg"; then 177 | # $@ is not empty: it contains at least $arg. 178 | set fnord "$@" "$dstarg" 179 | shift # fnord 180 | fi 181 | shift # arg 182 | dstarg=$arg 183 | done 184 | fi 185 | 186 | if test $# -eq 0; then 187 | if test -z "$dir_arg"; then 188 | echo "$0: no input file specified." >&2 189 | exit 1 190 | fi 191 | # It's OK to call `install-sh -d' without argument. 192 | # This can happen when creating conditional directories. 193 | exit 0 194 | fi 195 | 196 | if test -z "$dir_arg"; then 197 | trap '(exit $?); exit' 1 2 13 15 198 | 199 | # Set umask so as not to create temps with too-generous modes. 200 | # However, 'strip' requires both read and write access to temps. 201 | case $mode in 202 | # Optimize common cases. 203 | *644) cp_umask=133;; 204 | *755) cp_umask=22;; 205 | 206 | *[0-7]) 207 | if test -z "$stripcmd"; then 208 | u_plus_rw= 209 | else 210 | u_plus_rw='% 200' 211 | fi 212 | cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; 213 | *) 214 | if test -z "$stripcmd"; then 215 | u_plus_rw= 216 | else 217 | u_plus_rw=,u+rw 218 | fi 219 | cp_umask=$mode$u_plus_rw;; 220 | esac 221 | fi 222 | 223 | for src 224 | do 225 | # Protect names starting with `-'. 226 | case $src in 227 | -*) src=./$src ;; 228 | esac 229 | 230 | if test -n "$dir_arg"; then 231 | dst=$src 232 | dstdir=$dst 233 | test -d "$dstdir" 234 | dstdir_status=$? 235 | else 236 | 237 | # Waiting for this to be detected by the "$cpprog $src $dsttmp" command 238 | # might cause directories to be created, which would be especially bad 239 | # if $src (and thus $dsttmp) contains '*'. 240 | if test ! -f "$src" && test ! -d "$src"; then 241 | echo "$0: $src does not exist." >&2 242 | exit 1 243 | fi 244 | 245 | if test -z "$dstarg"; then 246 | echo "$0: no destination specified." >&2 247 | exit 1 248 | fi 249 | 250 | dst=$dstarg 251 | # Protect names starting with `-'. 252 | case $dst in 253 | -*) dst=./$dst ;; 254 | esac 255 | 256 | # If destination is a directory, append the input filename; won't work 257 | # if double slashes aren't ignored. 258 | if test -d "$dst"; then 259 | if test -n "$no_target_directory"; then 260 | echo "$0: $dstarg: Is a directory" >&2 261 | exit 1 262 | fi 263 | dstdir=$dst 264 | dst=$dstdir/`basename "$src"` 265 | dstdir_status=0 266 | else 267 | # Prefer dirname, but fall back on a substitute if dirname fails. 268 | dstdir=` 269 | (dirname "$dst") 2>/dev/null || 270 | expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ 271 | X"$dst" : 'X\(//\)[^/]' \| \ 272 | X"$dst" : 'X\(//\)$' \| \ 273 | X"$dst" : 'X\(/\)' \| . 2>/dev/null || 274 | echo X"$dst" | 275 | sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ 276 | s//\1/ 277 | q 278 | } 279 | /^X\(\/\/\)[^/].*/{ 280 | s//\1/ 281 | q 282 | } 283 | /^X\(\/\/\)$/{ 284 | s//\1/ 285 | q 286 | } 287 | /^X\(\/\).*/{ 288 | s//\1/ 289 | q 290 | } 291 | s/.*/./; q' 292 | ` 293 | 294 | test -d "$dstdir" 295 | dstdir_status=$? 296 | fi 297 | fi 298 | 299 | obsolete_mkdir_used=false 300 | 301 | if test $dstdir_status != 0; then 302 | case $posix_mkdir in 303 | '') 304 | # Create intermediate dirs using mode 755 as modified by the umask. 305 | # This is like FreeBSD 'install' as of 1997-10-28. 306 | umask=`umask` 307 | case $stripcmd.$umask in 308 | # Optimize common cases. 309 | *[2367][2367]) mkdir_umask=$umask;; 310 | .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; 311 | 312 | *[0-7]) 313 | mkdir_umask=`expr $umask + 22 \ 314 | - $umask % 100 % 40 + $umask % 20 \ 315 | - $umask % 10 % 4 + $umask % 2 316 | `;; 317 | *) mkdir_umask=$umask,go-w;; 318 | esac 319 | 320 | # With -d, create the new directory with the user-specified mode. 321 | # Otherwise, rely on $mkdir_umask. 322 | if test -n "$dir_arg"; then 323 | mkdir_mode=-m$mode 324 | else 325 | mkdir_mode= 326 | fi 327 | 328 | posix_mkdir=false 329 | case $umask in 330 | *[123567][0-7][0-7]) 331 | # POSIX mkdir -p sets u+wx bits regardless of umask, which 332 | # is incompatible with FreeBSD 'install' when (umask & 300) != 0. 333 | ;; 334 | *) 335 | tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ 336 | trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 337 | 338 | if (umask $mkdir_umask && 339 | exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 340 | then 341 | if test -z "$dir_arg" || { 342 | # Check for POSIX incompatibilities with -m. 343 | # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or 344 | # other-writeable bit of parent directory when it shouldn't. 345 | # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. 346 | ls_ld_tmpdir=`ls -ld "$tmpdir"` 347 | case $ls_ld_tmpdir in 348 | d????-?r-*) different_mode=700;; 349 | d????-?--*) different_mode=755;; 350 | *) false;; 351 | esac && 352 | $mkdirprog -m$different_mode -p -- "$tmpdir" && { 353 | ls_ld_tmpdir_1=`ls -ld "$tmpdir"` 354 | test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" 355 | } 356 | } 357 | then posix_mkdir=: 358 | fi 359 | rmdir "$tmpdir/d" "$tmpdir" 360 | else 361 | # Remove any dirs left behind by ancient mkdir implementations. 362 | rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null 363 | fi 364 | trap '' 0;; 365 | esac;; 366 | esac 367 | 368 | if 369 | $posix_mkdir && ( 370 | umask $mkdir_umask && 371 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" 372 | ) 373 | then : 374 | else 375 | 376 | # The umask is ridiculous, or mkdir does not conform to POSIX, 377 | # or it failed possibly due to a race condition. Create the 378 | # directory the slow way, step by step, checking for races as we go. 379 | 380 | case $dstdir in 381 | /*) prefix=/ ;; 382 | -*) prefix=./ ;; 383 | *) prefix= ;; 384 | esac 385 | 386 | case $posix_glob in 387 | '') 388 | if (set -f) 2>/dev/null; then 389 | posix_glob=true 390 | else 391 | posix_glob=false 392 | fi ;; 393 | esac 394 | 395 | oIFS=$IFS 396 | IFS=/ 397 | $posix_glob && set -f 398 | set fnord $dstdir 399 | shift 400 | $posix_glob && set +f 401 | IFS=$oIFS 402 | 403 | prefixes= 404 | 405 | for d 406 | do 407 | test -z "$d" && continue 408 | 409 | prefix=$prefix$d 410 | if test -d "$prefix"; then 411 | prefixes= 412 | else 413 | if $posix_mkdir; then 414 | (umask=$mkdir_umask && 415 | $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break 416 | # Don't fail if two instances are running concurrently. 417 | test -d "$prefix" || exit 1 418 | else 419 | case $prefix in 420 | *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; 421 | *) qprefix=$prefix;; 422 | esac 423 | prefixes="$prefixes '$qprefix'" 424 | fi 425 | fi 426 | prefix=$prefix/ 427 | done 428 | 429 | if test -n "$prefixes"; then 430 | # Don't fail if two instances are running concurrently. 431 | (umask $mkdir_umask && 432 | eval "\$doit_exec \$mkdirprog $prefixes") || 433 | test -d "$dstdir" || exit 1 434 | obsolete_mkdir_used=true 435 | fi 436 | fi 437 | fi 438 | 439 | if test -n "$dir_arg"; then 440 | { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && 441 | { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && 442 | { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || 443 | test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 444 | else 445 | 446 | # Make a couple of temp file names in the proper directory. 447 | dsttmp=$dstdir/_inst.$$_ 448 | rmtmp=$dstdir/_rm.$$_ 449 | 450 | # Trap to clean up those temp files at exit. 451 | trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 452 | 453 | # Copy the file name to the temp name. 454 | (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && 455 | 456 | # and set any options; do chmod last to preserve setuid bits. 457 | # 458 | # If any of these fail, we abort the whole thing. If we want to 459 | # ignore errors from any of these, just make sure not to ignore 460 | # errors from the above "$doit $cpprog $src $dsttmp" command. 461 | # 462 | { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } \ 463 | && { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } \ 464 | && { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } \ 465 | && { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && 466 | 467 | # Now rename the file to the real destination. 468 | { $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null \ 469 | || { 470 | # The rename failed, perhaps because mv can't rename something else 471 | # to itself, or perhaps because mv is so ancient that it does not 472 | # support -f. 473 | 474 | # Now remove or move aside any old file at destination location. 475 | # We try this two ways since rm can't unlink itself on some 476 | # systems and the destination file might be busy for other 477 | # reasons. In this case, the final cleanup might fail but the new 478 | # file should still install successfully. 479 | { 480 | if test -f "$dst"; then 481 | $doit $rmcmd -f "$dst" 2>/dev/null \ 482 | || { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null \ 483 | && { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }; }\ 484 | || { 485 | echo "$0: cannot unlink or rename $dst" >&2 486 | (exit 1); exit 1 487 | } 488 | else 489 | : 490 | fi 491 | } && 492 | 493 | # Now rename the file to the real destination. 494 | $doit $mvcmd "$dsttmp" "$dst" 495 | } 496 | } || exit 1 497 | 498 | trap '' 0 499 | fi 500 | done 501 | 502 | # Local variables: 503 | # eval: (add-hook 'write-file-hooks 'time-stamp) 504 | # time-stamp-start: "scriptversion=" 505 | # time-stamp-format: "%:y-%02m-%02d.%02H" 506 | # time-stamp-end: "$" 507 | # End: 508 | -------------------------------------------------------------------------------- /depcomp: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # depcomp - compile a program generating dependencies as side-effects 3 | 4 | scriptversion=2006-10-15.18 5 | 6 | # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006 Free Software 7 | # Foundation, Inc. 8 | 9 | # This program is free software; you can redistribute it and/or modify 10 | # it under the terms of the GNU General Public License as published by 11 | # the Free Software Foundation; either version 2, or (at your option) 12 | # any later version. 13 | 14 | # This program is distributed in the hope that it will be useful, 15 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | # GNU General Public License for more details. 18 | 19 | # You should have received a copy of the GNU General Public License 20 | # along with this program; if not, write to the Free Software 21 | # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 22 | # 02110-1301, USA. 23 | 24 | # As a special exception to the GNU General Public License, if you 25 | # distribute this file as part of a program that contains a 26 | # configuration script generated by Autoconf, you may include it under 27 | # the same distribution terms that you use for the rest of that program. 28 | 29 | # Originally written by Alexandre Oliva . 30 | 31 | case $1 in 32 | '') 33 | echo "$0: No command. Try \`$0 --help' for more information." 1>&2 34 | exit 1; 35 | ;; 36 | -h | --h*) 37 | cat <<\EOF 38 | Usage: depcomp [--help] [--version] PROGRAM [ARGS] 39 | 40 | Run PROGRAMS ARGS to compile a file, generating dependencies 41 | as side-effects. 42 | 43 | Environment variables: 44 | depmode Dependency tracking mode. 45 | source Source file read by `PROGRAMS ARGS'. 46 | object Object file output by `PROGRAMS ARGS'. 47 | DEPDIR directory where to store dependencies. 48 | depfile Dependency file to output. 49 | tmpdepfile Temporary file to use when outputing dependencies. 50 | libtool Whether libtool is used (yes/no). 51 | 52 | Report bugs to . 53 | EOF 54 | exit $? 55 | ;; 56 | -v | --v*) 57 | echo "depcomp $scriptversion" 58 | exit $? 59 | ;; 60 | esac 61 | 62 | if test -z "$depmode" || test -z "$source" || test -z "$object"; then 63 | echo "depcomp: Variables source, object and depmode must be set" 1>&2 64 | exit 1 65 | fi 66 | 67 | # Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po. 68 | depfile=${depfile-`echo "$object" | 69 | sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`} 70 | tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`} 71 | 72 | rm -f "$tmpdepfile" 73 | 74 | # Some modes work just like other modes, but use different flags. We 75 | # parameterize here, but still list the modes in the big case below, 76 | # to make depend.m4 easier to write. Note that we *cannot* use a case 77 | # here, because this file can only contain one case statement. 78 | if test "$depmode" = hp; then 79 | # HP compiler uses -M and no extra arg. 80 | gccflag=-M 81 | depmode=gcc 82 | fi 83 | 84 | if test "$depmode" = dashXmstdout; then 85 | # This is just like dashmstdout with a different argument. 86 | dashmflag=-xM 87 | depmode=dashmstdout 88 | fi 89 | 90 | case "$depmode" in 91 | gcc3) 92 | ## gcc 3 implements dependency tracking that does exactly what 93 | ## we want. Yay! Note: for some reason libtool 1.4 doesn't like 94 | ## it if -MD -MP comes after the -MF stuff. Hmm. 95 | ## Unfortunately, FreeBSD c89 acceptance of flags depends upon 96 | ## the command line argument order; so add the flags where they 97 | ## appear in depend2.am. Note that the slowdown incurred here 98 | ## affects only configure: in makefiles, %FASTDEP% shortcuts this. 99 | for arg 100 | do 101 | case $arg in 102 | -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;; 103 | *) set fnord "$@" "$arg" ;; 104 | esac 105 | shift # fnord 106 | shift # $arg 107 | done 108 | "$@" 109 | stat=$? 110 | if test $stat -eq 0; then : 111 | else 112 | rm -f "$tmpdepfile" 113 | exit $stat 114 | fi 115 | mv "$tmpdepfile" "$depfile" 116 | ;; 117 | 118 | gcc) 119 | ## There are various ways to get dependency output from gcc. Here's 120 | ## why we pick this rather obscure method: 121 | ## - Don't want to use -MD because we'd like the dependencies to end 122 | ## up in a subdir. Having to rename by hand is ugly. 123 | ## (We might end up doing this anyway to support other compilers.) 124 | ## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like 125 | ## -MM, not -M (despite what the docs say). 126 | ## - Using -M directly means running the compiler twice (even worse 127 | ## than renaming). 128 | if test -z "$gccflag"; then 129 | gccflag=-MD, 130 | fi 131 | "$@" -Wp,"$gccflag$tmpdepfile" 132 | stat=$? 133 | if test $stat -eq 0; then : 134 | else 135 | rm -f "$tmpdepfile" 136 | exit $stat 137 | fi 138 | rm -f "$depfile" 139 | echo "$object : \\" > "$depfile" 140 | alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz 141 | ## The second -e expression handles DOS-style file names with drive letters. 142 | sed -e 's/^[^:]*: / /' \ 143 | -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile" 144 | ## This next piece of magic avoids the `deleted header file' problem. 145 | ## The problem is that when a header file which appears in a .P file 146 | ## is deleted, the dependency causes make to die (because there is 147 | ## typically no way to rebuild the header). We avoid this by adding 148 | ## dummy dependencies for each header file. Too bad gcc doesn't do 149 | ## this for us directly. 150 | tr ' ' ' 151 | ' < "$tmpdepfile" | 152 | ## Some versions of gcc put a space before the `:'. On the theory 153 | ## that the space means something, we add a space to the output as 154 | ## well. 155 | ## Some versions of the HPUX 10.20 sed can't process this invocation 156 | ## correctly. Breaking it into two sed invocations is a workaround. 157 | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" 158 | rm -f "$tmpdepfile" 159 | ;; 160 | 161 | hp) 162 | # This case exists only to let depend.m4 do its work. It works by 163 | # looking at the text of this script. This case will never be run, 164 | # since it is checked for above. 165 | exit 1 166 | ;; 167 | 168 | sgi) 169 | if test "$libtool" = yes; then 170 | "$@" "-Wp,-MDupdate,$tmpdepfile" 171 | else 172 | "$@" -MDupdate "$tmpdepfile" 173 | fi 174 | stat=$? 175 | if test $stat -eq 0; then : 176 | else 177 | rm -f "$tmpdepfile" 178 | exit $stat 179 | fi 180 | rm -f "$depfile" 181 | 182 | if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files 183 | echo "$object : \\" > "$depfile" 184 | 185 | # Clip off the initial element (the dependent). Don't try to be 186 | # clever and replace this with sed code, as IRIX sed won't handle 187 | # lines with more than a fixed number of characters (4096 in 188 | # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines; 189 | # the IRIX cc adds comments like `#:fec' to the end of the 190 | # dependency line. 191 | tr ' ' ' 192 | ' < "$tmpdepfile" \ 193 | | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \ 194 | tr ' 195 | ' ' ' >> $depfile 196 | echo >> $depfile 197 | 198 | # The second pass generates a dummy entry for each header file. 199 | tr ' ' ' 200 | ' < "$tmpdepfile" \ 201 | | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \ 202 | >> $depfile 203 | else 204 | # The sourcefile does not contain any dependencies, so just 205 | # store a dummy comment line, to avoid errors with the Makefile 206 | # "include basename.Plo" scheme. 207 | echo "#dummy" > "$depfile" 208 | fi 209 | rm -f "$tmpdepfile" 210 | ;; 211 | 212 | aix) 213 | # The C for AIX Compiler uses -M and outputs the dependencies 214 | # in a .u file. In older versions, this file always lives in the 215 | # current directory. Also, the AIX compiler puts `$object:' at the 216 | # start of each line; $object doesn't have directory information. 217 | # Version 6 uses the directory in both cases. 218 | stripped=`echo "$object" | sed 's/\(.*\)\..*$/\1/'` 219 | tmpdepfile="$stripped.u" 220 | if test "$libtool" = yes; then 221 | "$@" -Wc,-M 222 | else 223 | "$@" -M 224 | fi 225 | stat=$? 226 | 227 | if test -f "$tmpdepfile"; then : 228 | else 229 | stripped=`echo "$stripped" | sed 's,^.*/,,'` 230 | tmpdepfile="$stripped.u" 231 | fi 232 | 233 | if test $stat -eq 0; then : 234 | else 235 | rm -f "$tmpdepfile" 236 | exit $stat 237 | fi 238 | 239 | if test -f "$tmpdepfile"; then 240 | outname="$stripped.o" 241 | # Each line is of the form `foo.o: dependent.h'. 242 | # Do two passes, one to just change these to 243 | # `$object: dependent.h' and one to simply `dependent.h:'. 244 | sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile" 245 | sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile" 246 | else 247 | # The sourcefile does not contain any dependencies, so just 248 | # store a dummy comment line, to avoid errors with the Makefile 249 | # "include basename.Plo" scheme. 250 | echo "#dummy" > "$depfile" 251 | fi 252 | rm -f "$tmpdepfile" 253 | ;; 254 | 255 | icc) 256 | # Intel's C compiler understands `-MD -MF file'. However on 257 | # icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c 258 | # ICC 7.0 will fill foo.d with something like 259 | # foo.o: sub/foo.c 260 | # foo.o: sub/foo.h 261 | # which is wrong. We want: 262 | # sub/foo.o: sub/foo.c 263 | # sub/foo.o: sub/foo.h 264 | # sub/foo.c: 265 | # sub/foo.h: 266 | # ICC 7.1 will output 267 | # foo.o: sub/foo.c sub/foo.h 268 | # and will wrap long lines using \ : 269 | # foo.o: sub/foo.c ... \ 270 | # sub/foo.h ... \ 271 | # ... 272 | 273 | "$@" -MD -MF "$tmpdepfile" 274 | stat=$? 275 | if test $stat -eq 0; then : 276 | else 277 | rm -f "$tmpdepfile" 278 | exit $stat 279 | fi 280 | rm -f "$depfile" 281 | # Each line is of the form `foo.o: dependent.h', 282 | # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'. 283 | # Do two passes, one to just change these to 284 | # `$object: dependent.h' and one to simply `dependent.h:'. 285 | sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile" 286 | # Some versions of the HPUX 10.20 sed can't process this invocation 287 | # correctly. Breaking it into two sed invocations is a workaround. 288 | sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" | 289 | sed -e 's/$/ :/' >> "$depfile" 290 | rm -f "$tmpdepfile" 291 | ;; 292 | 293 | hp2) 294 | # The "hp" stanza above does not work with aCC (C++) and HP's ia64 295 | # compilers, which have integrated preprocessors. The correct option 296 | # to use with these is +Maked; it writes dependencies to a file named 297 | # 'foo.d', which lands next to the object file, wherever that 298 | # happens to be. 299 | # Much of this is similar to the tru64 case; see comments there. 300 | dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` 301 | test "x$dir" = "x$object" && dir= 302 | base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` 303 | if test "$libtool" = yes; then 304 | tmpdepfile1=$dir$base.d 305 | tmpdepfile2=$dir.libs/$base.d 306 | "$@" -Wc,+Maked 307 | else 308 | tmpdepfile1=$dir$base.d 309 | tmpdepfile2=$dir$base.d 310 | "$@" +Maked 311 | fi 312 | stat=$? 313 | if test $stat -eq 0; then : 314 | else 315 | rm -f "$tmpdepfile1" "$tmpdepfile2" 316 | exit $stat 317 | fi 318 | 319 | for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" 320 | do 321 | test -f "$tmpdepfile" && break 322 | done 323 | if test -f "$tmpdepfile"; then 324 | sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile" 325 | # Add `dependent.h:' lines. 326 | sed -ne '2,${; s/^ *//; s/ \\*$//; s/$/:/; p;}' "$tmpdepfile" >> "$depfile" 327 | else 328 | echo "#dummy" > "$depfile" 329 | fi 330 | rm -f "$tmpdepfile" "$tmpdepfile2" 331 | ;; 332 | 333 | tru64) 334 | # The Tru64 compiler uses -MD to generate dependencies as a side 335 | # effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'. 336 | # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put 337 | # dependencies in `foo.d' instead, so we check for that too. 338 | # Subdirectories are respected. 339 | dir=`echo "$object" | sed -e 's|/[^/]*$|/|'` 340 | test "x$dir" = "x$object" && dir= 341 | base=`echo "$object" | sed -e 's|^.*/||' -e 's/\.o$//' -e 's/\.lo$//'` 342 | 343 | if test "$libtool" = yes; then 344 | # With Tru64 cc, shared objects can also be used to make a 345 | # static library. This mechanism is used in libtool 1.4 series to 346 | # handle both shared and static libraries in a single compilation. 347 | # With libtool 1.4, dependencies were output in $dir.libs/$base.lo.d. 348 | # 349 | # With libtool 1.5 this exception was removed, and libtool now 350 | # generates 2 separate objects for the 2 libraries. These two 351 | # compilations output dependencies in $dir.libs/$base.o.d and 352 | # in $dir$base.o.d. We have to check for both files, because 353 | # one of the two compilations can be disabled. We should prefer 354 | # $dir$base.o.d over $dir.libs/$base.o.d because the latter is 355 | # automatically cleaned when .libs/ is deleted, while ignoring 356 | # the former would cause a distcleancheck panic. 357 | tmpdepfile1=$dir.libs/$base.lo.d # libtool 1.4 358 | tmpdepfile2=$dir$base.o.d # libtool 1.5 359 | tmpdepfile3=$dir.libs/$base.o.d # libtool 1.5 360 | tmpdepfile4=$dir.libs/$base.d # Compaq CCC V6.2-504 361 | "$@" -Wc,-MD 362 | else 363 | tmpdepfile1=$dir$base.o.d 364 | tmpdepfile2=$dir$base.d 365 | tmpdepfile3=$dir$base.d 366 | tmpdepfile4=$dir$base.d 367 | "$@" -MD 368 | fi 369 | 370 | stat=$? 371 | if test $stat -eq 0; then : 372 | else 373 | rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" 374 | exit $stat 375 | fi 376 | 377 | for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3" "$tmpdepfile4" 378 | do 379 | test -f "$tmpdepfile" && break 380 | done 381 | if test -f "$tmpdepfile"; then 382 | sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile" 383 | # That's a tab and a space in the []. 384 | sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile" 385 | else 386 | echo "#dummy" > "$depfile" 387 | fi 388 | rm -f "$tmpdepfile" 389 | ;; 390 | 391 | #nosideeffect) 392 | # This comment above is used by automake to tell side-effect 393 | # dependency tracking mechanisms from slower ones. 394 | 395 | dashmstdout) 396 | # Important note: in order to support this mode, a compiler *must* 397 | # always write the preprocessed file to stdout, regardless of -o. 398 | "$@" || exit $? 399 | 400 | # Remove the call to Libtool. 401 | if test "$libtool" = yes; then 402 | while test $1 != '--mode=compile'; do 403 | shift 404 | done 405 | shift 406 | fi 407 | 408 | # Remove `-o $object'. 409 | IFS=" " 410 | for arg 411 | do 412 | case $arg in 413 | -o) 414 | shift 415 | ;; 416 | $object) 417 | shift 418 | ;; 419 | *) 420 | set fnord "$@" "$arg" 421 | shift # fnord 422 | shift # $arg 423 | ;; 424 | esac 425 | done 426 | 427 | test -z "$dashmflag" && dashmflag=-M 428 | # Require at least two characters before searching for `:' 429 | # in the target name. This is to cope with DOS-style filenames: 430 | # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise. 431 | "$@" $dashmflag | 432 | sed 's:^[ ]*[^: ][^:][^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile" 433 | rm -f "$depfile" 434 | cat < "$tmpdepfile" > "$depfile" 435 | tr ' ' ' 436 | ' < "$tmpdepfile" | \ 437 | ## Some versions of the HPUX 10.20 sed can't process this invocation 438 | ## correctly. Breaking it into two sed invocations is a workaround. 439 | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" 440 | rm -f "$tmpdepfile" 441 | ;; 442 | 443 | dashXmstdout) 444 | # This case only exists to satisfy depend.m4. It is never actually 445 | # run, as this mode is specially recognized in the preamble. 446 | exit 1 447 | ;; 448 | 449 | makedepend) 450 | "$@" || exit $? 451 | # Remove any Libtool call 452 | if test "$libtool" = yes; then 453 | while test $1 != '--mode=compile'; do 454 | shift 455 | done 456 | shift 457 | fi 458 | # X makedepend 459 | shift 460 | cleared=no 461 | for arg in "$@"; do 462 | case $cleared in 463 | no) 464 | set ""; shift 465 | cleared=yes ;; 466 | esac 467 | case "$arg" in 468 | -D*|-I*) 469 | set fnord "$@" "$arg"; shift ;; 470 | # Strip any option that makedepend may not understand. Remove 471 | # the object too, otherwise makedepend will parse it as a source file. 472 | -*|$object) 473 | ;; 474 | *) 475 | set fnord "$@" "$arg"; shift ;; 476 | esac 477 | done 478 | obj_suffix="`echo $object | sed 's/^.*\././'`" 479 | touch "$tmpdepfile" 480 | ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@" 481 | rm -f "$depfile" 482 | cat < "$tmpdepfile" > "$depfile" 483 | sed '1,2d' "$tmpdepfile" | tr ' ' ' 484 | ' | \ 485 | ## Some versions of the HPUX 10.20 sed can't process this invocation 486 | ## correctly. Breaking it into two sed invocations is a workaround. 487 | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile" 488 | rm -f "$tmpdepfile" "$tmpdepfile".bak 489 | ;; 490 | 491 | cpp) 492 | # Important note: in order to support this mode, a compiler *must* 493 | # always write the preprocessed file to stdout. 494 | "$@" || exit $? 495 | 496 | # Remove the call to Libtool. 497 | if test "$libtool" = yes; then 498 | while test $1 != '--mode=compile'; do 499 | shift 500 | done 501 | shift 502 | fi 503 | 504 | # Remove `-o $object'. 505 | IFS=" " 506 | for arg 507 | do 508 | case $arg in 509 | -o) 510 | shift 511 | ;; 512 | $object) 513 | shift 514 | ;; 515 | *) 516 | set fnord "$@" "$arg" 517 | shift # fnord 518 | shift # $arg 519 | ;; 520 | esac 521 | done 522 | 523 | "$@" -E | 524 | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \ 525 | -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' | 526 | sed '$ s: \\$::' > "$tmpdepfile" 527 | rm -f "$depfile" 528 | echo "$object : \\" > "$depfile" 529 | cat < "$tmpdepfile" >> "$depfile" 530 | sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile" 531 | rm -f "$tmpdepfile" 532 | ;; 533 | 534 | msvisualcpp) 535 | # Important note: in order to support this mode, a compiler *must* 536 | # always write the preprocessed file to stdout, regardless of -o, 537 | # because we must use -o when running libtool. 538 | "$@" || exit $? 539 | IFS=" " 540 | for arg 541 | do 542 | case "$arg" in 543 | "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI") 544 | set fnord "$@" 545 | shift 546 | shift 547 | ;; 548 | *) 549 | set fnord "$@" "$arg" 550 | shift 551 | shift 552 | ;; 553 | esac 554 | done 555 | "$@" -E | 556 | sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile" 557 | rm -f "$depfile" 558 | echo "$object : \\" > "$depfile" 559 | . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile" 560 | echo " " >> "$depfile" 561 | . "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile" 562 | rm -f "$tmpdepfile" 563 | ;; 564 | 565 | none) 566 | exec "$@" 567 | ;; 568 | 569 | *) 570 | echo "Unknown depmode $depmode" 1>&2 571 | exit 1 572 | ;; 573 | esac 574 | 575 | exit 0 576 | 577 | # Local Variables: 578 | # mode: shell-script 579 | # sh-indentation: 2 580 | # eval: (add-hook 'write-file-hooks 'time-stamp) 581 | # time-stamp-start: "scriptversion=" 582 | # time-stamp-format: "%:y-%02m-%02d.%02H" 583 | # time-stamp-end: "$" 584 | # End: 585 | -------------------------------------------------------------------------------- /doc/protocol.txt: -------------------------------------------------------------------------------- 1 | Protocol 2 | -------- 3 | 4 | Clients of memcached communicate with server through TCP connections. 5 | (A UDP interface is also available; details are below under "UDP 6 | protocol.") A given running memcached server listens on some 7 | (configurable) port; clients connect to that port, send commands to 8 | the server, read responses, and eventually close the connection. 9 | 10 | There is no need to send any command to end the session. A client may 11 | just close the connection at any moment it no longer needs it. Note, 12 | however, that clients are encouraged to cache their connections rather 13 | than reopen them every time they need to store or retrieve data. This 14 | is because memcached is especially designed to work very efficiently 15 | with a very large number (many hundreds, more than a thousand if 16 | necessary) of open connections. Caching connections will eliminate the 17 | overhead associated with establishing a TCP connection (the overhead 18 | of preparing for a new connection on the server side is insignificant 19 | compared to this). 20 | 21 | There are two kinds of data sent in the memcache protocol: text lines 22 | and unstructured data. Text lines are used for commands from clients 23 | and responses from servers. Unstructured data is sent when a client 24 | wants to store or retrieve data. The server will transmit back 25 | unstructured data in exactly the same way it received it, as a byte 26 | stream. The server doesn't care about byte order issues in 27 | unstructured data and isn't aware of them. There are no limitations on 28 | characters that may appear in unstructured data; however, the reader 29 | of such data (either a client or a server) will always know, from a 30 | preceding text line, the exact length of the data block being 31 | transmitted. 32 | 33 | Text lines are always terminated by \r\n. Unstructured data is _also_ 34 | terminated by \r\n, even though \r, \n or any other 8-bit characters 35 | may also appear inside the data. Therefore, when a client retrieves 36 | data from a server, it must use the length of the data block (which it 37 | will be provided with) to determine where the data block ends, and not 38 | the fact that \r\n follows the end of the data block, even though it 39 | does. 40 | 41 | Keys 42 | ---- 43 | 44 | Data stored by memcached is identified with the help of a key. A key 45 | is a text string which should uniquely identify the data for clients 46 | that are interested in storing and retrieving it. Currently the 47 | length limit of a key is set at 250 characters (of course, normally 48 | clients wouldn't need to use such long keys); the key must not include 49 | control characters or whitespace. 50 | 51 | Commands 52 | -------- 53 | 54 | There are three types of commands. 55 | 56 | Storage commands (there are six: "set", "add", "replace", "append" 57 | "prepend" and "cas") ask the server to store some data identified by a key. The 58 | client sends a command line, and then a data block; after that the 59 | client expects one line of response, which will indicate success or 60 | faulure. 61 | 62 | Retrieval commands (there are two: "get" and "gets") ask the server to 63 | retrieve data corresponding to a set of keys (one or more keys in one 64 | request). The client sends a command line, which includes all the 65 | requested keys; after that for each item the server finds it sends to 66 | the client one response line with information about the item, and one 67 | data block with the item's data; this continues until the server 68 | finished with the "END" response line. 69 | 70 | All other commands don't involve unstructured data. In all of them, 71 | the client sends one command line, and expects (depending on the 72 | command) either one line of response, or several lines of response 73 | ending with "END" on the last line. 74 | 75 | A command line always starts with the name of the command, followed by 76 | parameters (if any) delimited by whitespace. Command names are 77 | lower-case and are case-sensitive. 78 | 79 | Expiration times 80 | ---------------- 81 | 82 | Some commands involve a client sending some kind of expiration time 83 | (relative to an item or to an operation requested by the client) to 84 | the server. In all such cases, the actual value sent may either be 85 | Unix time (number of seconds since January 1, 1970, as a 32-bit 86 | value), or a number of seconds starting from current time. In the 87 | latter case, this number of seconds may not exceed 60*60*24*30 (number 88 | of seconds in 30 days); if the number sent by a client is larger than 89 | that, the server will consider it to be real Unix time value rather 90 | than an offset from current time. 91 | 92 | 93 | Error strings 94 | ------------- 95 | 96 | Each command sent by a client may be answered with an error string 97 | from the server. These error strings come in three types: 98 | 99 | - "ERROR\r\n" 100 | 101 | means the client sent a nonexistent command name. 102 | 103 | - "CLIENT_ERROR \r\n" 104 | 105 | means some sort of client error in the input line, i.e. the input 106 | doesn't conform to the protocol in some way. is a 107 | human-readable error string. 108 | 109 | - "SERVER_ERROR \r\n" 110 | 111 | means some sort of server error prevents the server from carrying 112 | out the command. is a human-readable error string. In cases 113 | of severe server errors, which make it impossible to continue 114 | serving the client (this shouldn't normally happen), the server will 115 | close the connection after sending the error line. This is the only 116 | case in which the server closes a connection to a client. 117 | 118 | 119 | In the descriptions of individual commands below, these error lines 120 | are not again specifically mentioned, but clients must allow for their 121 | possibility. 122 | 123 | 124 | Storage commands 125 | ---------------- 126 | 127 | First, the client sends a command line which looks like this: 128 | 129 | []\r\n 130 | 131 | - is "set", "add", "replace", "append", "prepend", or "cas" 132 | 133 | "set" means "store this data". 134 | 135 | "add" means "store this data, but only if the server *doesn't* already 136 | hold data for this key". 137 | 138 | "replace" means "store this data, but only if the server *does* 139 | already hold data for this key". 140 | 141 | "append" means "add this data to an existing key after existing data". 142 | 143 | "prepend" means "add this data to an existing key before existing data". 144 | 145 | The append and prepend commands do not accept flags or exptime. 146 | They update existing data portions, and ignore new flag and exptime 147 | settings. 148 | 149 | "cas" is a check and set operation which means "store this data but 150 | only if no one else has updated since I last fetched it." 151 | 152 | - is the key under which the client asks to store the data 153 | 154 | - is an arbitrary 16-bit unsigned integer (written out in 155 | decimal) that the server stores along with the data and sends back 156 | when the item is retrieved. Clients may use this as a bit field to 157 | store data-specific information; this field is opaque to the server. 158 | Note that in memcached 1.2.1 and higher, flags may be 32-bits, instead 159 | of 16, but you might want to restrict yourself to 16 bits for 160 | compatibility with older versions. 161 | 162 | - is expiration time. If it's 0, the item never expires 163 | (although it may be deleted from the cache to make place for other 164 | items). If it's non-zero (either Unix time or offset in seconds from 165 | current time), it is guaranteed that clients will not be able to 166 | retrieve this item after the expiration time arrives (measured by 167 | server time). 168 | 169 | - is the number of bytes in the data block to follow, *not* 170 | including the delimiting \r\n. may be zero (in which case 171 | it's followed by an empty data block). 172 | 173 | - is a unique 64-bit value of an existing entry. 174 | Clients should use the value returned from the "gets" command 175 | when issuing "cas" updates. 176 | 177 | After this line, the client sends the data block: 178 | 179 | \r\n 180 | 181 | - is a chunk of arbitrary 8-bit data of length 182 | from the previous line. 183 | 184 | After sending the command line and the data blockm the client awaits 185 | the reply, which may be: 186 | 187 | - "STORED\r\n", to indicate success. 188 | 189 | - "NOT_STORED\r\n" to indicate the data was not stored, but not 190 | because of an error. This normally means that either that the 191 | condition for an "add" or a "replace" command wasn't met, or that the 192 | item is in a delete queue (see the "delete" command below). 193 | 194 | - "EXISTS\r\n" to indicate that the item you are trying to store with 195 | a "cas" command has been modified since you last fetched it. 196 | 197 | - "NOT_FOUND\r\n" to indicate that the item you are trying to store 198 | with a "cas" command did not exist or has been deleted. 199 | 200 | 201 | Retrieval command: 202 | ------------------ 203 | 204 | The retrieval commands "get" and "gets" operates like this: 205 | 206 | get *\r\n 207 | gets *\r\n 208 | 209 | - * means one or more key strings separated by whitespace. 210 | 211 | After this command, the client expects zero or more items, each of 212 | which is received as a text line followed by a data block. After all 213 | the items have been transmitted, the server sends the string 214 | 215 | "END\r\n" 216 | 217 | to indicate the end of response. 218 | 219 | Each item sent by the server looks like this: 220 | 221 | VALUE []\r\n 222 | \r\n 223 | 224 | - is the key for the item being sent 225 | 226 | - is the flags value set by the storage command 227 | 228 | - is the length of the data block to follow, *not* including 229 | its delimiting \r\n 230 | 231 | - is a unique 64-bit integer that uniquely identifies 232 | this specific item. 233 | 234 | - is the data for this item. 235 | 236 | If some of the keys appearing in a retrieval request are not sent back 237 | by the server in the item list this means that the server does not 238 | hold items with such keys (because they were never stored, or stored 239 | but deleted to make space for more items, or expired, or explicitly 240 | deleted by a client). 241 | 242 | 243 | Deletion 244 | -------- 245 | 246 | The command "delete" allows for explicit deletion of items: 247 | 248 | delete