├── .dockerignore ├── NEWS ├── doc ├── readme.txt ├── Makefile.am ├── xml2rfc │ └── reference.RFC.0768.xml └── CONTRIBUTORS ├── AUTHORS-memcached ├── t ├── sasl │ └── memcached.conf ├── bogus-commands.t ├── issue_50.t ├── issue_arcus_655.t ├── line-lengths.t ├── issue_152.t ├── maxconns.t ├── binary-get.t ├── flags.t ├── binary_crash.t ├── issue_61.t ├── unixsocket.t ├── issue_70.t ├── issue_104.t ├── dash-M.t ├── daemonize.t ├── issue_68.t ├── issue_108.t ├── issue_14.t ├── issue_42.t ├── cmd_extensions.t ├── scrub.t ├── evictions.t ├── issue_41.t ├── set_with_largest_slab.t ├── verbosity.t ├── issue_163.t ├── issue_ee_599.t ├── issue_29.t ├── 64bit.t ├── etc │ ├── too_many_eviction_big_work.pl │ ├── too_many_eviction_w_load.pl │ ├── too_many_eviction_s_fast.pl │ ├── too_many_eviction_s_slow.pl │ ├── too_many_eviction_w_work.pl │ ├── stress-workload-change.pl │ ├── eager_item_invalidation.pl │ ├── too_many_eviction_issue.pl │ ├── too_many_eviction_m_work.pl │ ├── stress-memcached.pl │ ├── too_many_eviction_l_work.pl │ └── too_many_eviction_s_work.pl ├── readable_expiretime.t ├── whitespace.t ├── issue_3.t ├── flush-all.t ├── coll_sop_segfault_p012611.t ├── gat.t ├── issue_22.t ├── coll_mop_update.t ├── multiversioning.t ├── coll_mop_insert.t ├── 00-startup.t ├── mget2.t ├── lru.t ├── coll_mop_upsert.t ├── tlist │ ├── engine_default_s.txt │ └── engine_default_b.txt ├── touch.t ├── mgets.t ├── expirations.t ├── noreply.t ├── coll_bkeymismatch_test.t ├── coll_max_elembytes_test.t ├── item_size_max.t └── keyscan.t ├── deps ├── cyrus-sasl-2.1.28.tar.gz ├── libevent-2.1.12-stable.tar.gz ├── arcus-zookeeper-3.5.9-p3.tar.gz └── install.sh ├── devtools ├── maketags.sh ├── clean-whitespace.pl ├── svn-tarballs.pl └── bench_noreply.pl ├── .shipit ├── _run_memcached_solo.sh ├── hash.h ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── feature-refactoring-request.md │ └── bug_report.md └── workflows │ └── CI.yml ├── Makefile.docker ├── win32 ├── dlfcn.h ├── config.sh ├── defs.c ├── dlfcn.c └── config.h ├── AUTHORS ├── stdin_check.h ├── scripts ├── damemtop.yaml ├── README.damemtop ├── memcached.sysv └── memcached-init ├── protocol_extension.h ├── PATENTS ├── include └── memcached │ ├── visibility.h │ ├── engine_common.h │ ├── extension_loggers.h │ ├── vbucket.h │ ├── engine_testapp.h │ ├── mock_server.h │ ├── callback.h │ └── config_parser.h ├── genhash_int.h ├── sasl_auxprop.h ├── globals.c ├── rfc1321 ├── global.h └── md5.h ├── README ├── Dockerfile ├── run_test.pl ├── engine_loader.h ├── sasl_defs.h ├── .gitignore ├── sizes.c ├── cmdlog.h ├── engines ├── default │ ├── checkpoint.h │ ├── cmdlogfile.h │ ├── default_engine.conf │ ├── mem_pool.h │ ├── cmdlogbuf.h │ └── chkpt_snapshot.h └── demo │ └── dm_assoc.h ├── solaris_priv.c ├── HACKING ├── COPYING ├── LICENSE-memcached ├── docs ├── install.md ├── administration │ └── userlog.md └── ascii-protocol │ ├── ch10-command-item-attribute.md │ ├── ch99-appendix.md │ └── README.md ├── BUILD ├── cluster_config.h ├── arcus_hb.h ├── stdin_check.c ├── config └── version.pl ├── lqdetect.h ├── extension_loggers.c ├── isasl.h ├── arcus_zk.h └── CONTRIBUTING.md /.dockerignore: -------------------------------------------------------------------------------- 1 | .gitignore -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- 1 | http://www.danga.com/memcached/news.bml 2 | -------------------------------------------------------------------------------- /doc/readme.txt: -------------------------------------------------------------------------------- 1 | To build the documentation you need xml2rfc ( http://xml.resource.org/ ). 2 | -------------------------------------------------------------------------------- /AUTHORS-memcached: -------------------------------------------------------------------------------- 1 | Anatoly Vorobey 2 | Brad Fitzpatrick 3 | -------------------------------------------------------------------------------- /t/sasl/memcached.conf: -------------------------------------------------------------------------------- 1 | mech_list: plain cram-md5 2 | log_level: 5 3 | sasldb_path: /tmp/test-memcached.sasldb 4 | -------------------------------------------------------------------------------- /deps/cyrus-sasl-2.1.28.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naver/arcus-memcached/master/deps/cyrus-sasl-2.1.28.tar.gz -------------------------------------------------------------------------------- /deps/libevent-2.1.12-stable.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naver/arcus-memcached/master/deps/libevent-2.1.12-stable.tar.gz -------------------------------------------------------------------------------- /deps/arcus-zookeeper-3.5.9-p3.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naver/arcus-memcached/master/deps/arcus-zookeeper-3.5.9-p3.tar.gz -------------------------------------------------------------------------------- /devtools/maketags.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | find ../ -name "*[cht]" > ./cscope.files 3 | ctags --extra=+q -L ./cscope.files -f ./tags 4 | rm ./cscope.files 5 | -------------------------------------------------------------------------------- /.shipit: -------------------------------------------------------------------------------- 1 | steps = FindVersion, ChangeVersion, CheckChangeLog, DistTest, Commit, Tag, MakeDist, AddToSVNDir 2 | 3 | AddToSVNDir.dir = ../website/dist 4 | svn.tagpattern = %v 5 | -------------------------------------------------------------------------------- /_run_memcached_solo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | CURRENT_DIR_PATH=`pwd` 4 | 5 | ./memcached -E $CURRENT_DIR_PATH/.libs/default_engine.so -X $CURRENT_DIR_PATH/.libs/syslog_logger.so -X $CURRENT_DIR_PATH/.libs/ascii_scrub.so $@ 6 | -------------------------------------------------------------------------------- /hash.h: -------------------------------------------------------------------------------- 1 | #ifndef HASH_H 2 | #define HASH_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | uint32_t mc_hash(const void *key, size_t length, const uint32_t initval); 9 | 10 | #ifdef __cplusplus 11 | } 12 | #endif 13 | 14 | #endif /* HASH_H */ 15 | 16 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### 🔗 Related Issue 2 | 3 | 4 | - 5 | 6 | ### ⌨️ What I did 7 | 8 | 9 | - 10 | -------------------------------------------------------------------------------- /Makefile.docker: -------------------------------------------------------------------------------- 1 | VERSION ?= develop 2 | 3 | build: 4 | - docker buildx create --name project-v3-builder 5 | docker buildx use project-v3-builder 6 | - docker buildx build --push --platform=linux/arm64,linux/amd64 --tag jam2in/arcus-memcached:${VERSION} --progress tty . 7 | - docker buildx rm project-v3-builder 8 | -------------------------------------------------------------------------------- /win32/dlfcn.h: -------------------------------------------------------------------------------- 1 | #ifndef DLFCN_H 2 | #define DLFCN_H 3 | void* dlopen(const char* path, int mode); 4 | void* dlsym(void* handle, const char* symbol); 5 | int dlclose(void* handle); 6 | const char *dlerror(void); 7 | 8 | #define RTLD_LAZY 1 9 | #define RTLD_LOCAL 2 10 | 11 | #define RTLD_NOW 0x00002 12 | #endif 13 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | JunHyun Park ; 2 | HyongYoub Kim 3 | YeaSol Kim (ngleader) ; 4 | HoonMin Kim (harebox) ; 5 | SeongHwan Jeong (scryner) 6 | Chang Song 7 | -------------------------------------------------------------------------------- /stdin_check.h: -------------------------------------------------------------------------------- 1 | #ifndef STDIN_CHECK_H 2 | #define STDIN_CHECK_H 3 | 4 | #include "memcached/engine.h" 5 | 6 | /* prototype required to avoid warnings treated as failures on some *NIX */ 7 | EXTENSION_ERROR_CODE memcached_extensions_initialize(const char *config, 8 | GET_SERVER_API get_server_api); 9 | #endif 10 | -------------------------------------------------------------------------------- /scripts/damemtop.yaml: -------------------------------------------------------------------------------- 1 | delay: 3 2 | mode: t 3 | top_mode: 4 | sort_column: "hostname" 5 | sort_order: "asc" 6 | columns: 7 | - hostname 8 | - all_version 9 | - all_fill_rate 10 | - hit_rate 11 | - evictions 12 | - bytes_written 13 | - "2:get_hits" 14 | servers: 15 | - 127.0.0.1:11211 16 | - 127.0.0.2:11211 17 | -------------------------------------------------------------------------------- /protocol_extension.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #ifndef EXAMPLE_PROTOCOL_H 3 | #define EXAMPLE_PROTOCOL_H 4 | 5 | #include 6 | 7 | EXTENSION_ERROR_CODE memcached_extensions_initialize(const char *config, 8 | GET_SERVER_API get_server_api); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature-refactoring-request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature/Refactoring request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### 🔍 Description 11 | 12 | 13 | - 14 | 15 | ### ⏰ Implementation Idea 16 | 17 | 18 | - 19 | -------------------------------------------------------------------------------- /PATENTS: -------------------------------------------------------------------------------- 1 | Arcus has patents on the implementation of b+tree smget operation like below. 2 | 3 | | Nation | Number | Title | Status | 4 | | ------------- | --------------- | ------------------- | ---------- | 5 | | United States | 13/474,382 | Multiple Range Scan | registered | 6 | | Korea | 10-2011-0054384 | Multiple Range Scan | applied | 7 | | Japan | 2012-092668 | Multiple Range Scan | applied | 8 | -------------------------------------------------------------------------------- /t/bogus-commands.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 1; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $rst; 14 | 15 | $cmd = "boguscommand slkdsldkfjsd"; 16 | $rst = "ERROR unknown command"; 17 | mem_cmd_is($sock, $cmd, "", $rst); 18 | 19 | # after test 20 | release_memcached($engine, $server); 21 | -------------------------------------------------------------------------------- /include/memcached/visibility.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #ifndef MEMCACHED_VISIBILITY_H 3 | #define MEMCACHED_VISIBILITY_H 1 4 | 5 | #if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550) 6 | #define MEMCACHED_PUBLIC_API __global 7 | #elif defined __GNUC__ 8 | #define MEMCACHED_PUBLIC_API __attribute__ ((visibility("default"))) 9 | #else 10 | #define MEMCACHED_PUBLIC_API 11 | #endif 12 | 13 | #endif /* MEMCACHED_VISIBILITY_H */ 14 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | ### ⛔ What happened? 11 | 12 | - 13 | 14 | ### 🎯 Reproduction Steps 15 | 16 | 17 | - 18 | 19 | ### 💡 Expected Behavior / Solution 20 | 21 | 22 | - 23 | -------------------------------------------------------------------------------- /win32/config.sh: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | MEMC_VERSION=`git describe | tr '-' '_'`; 3 | cat > .libs/config_version.h << EOF 4 | #ifndef CONFIG_VERSION_H 5 | #define CONFIG_VERSION_H 6 | 7 | /* Define to the full name and version of this package. */ 8 | #define PACKAGE_STRING "memcached $MEMC_VERSION" 9 | 10 | /* Define to the version of this package. */ 11 | #define PACKAGE_VERSION "$MEMC_VERSION" 12 | 13 | /* Version number of package */ 14 | #define VERSION "$MEMC_VERSION" 15 | 16 | #endif // CONFIG_VERSION_H 17 | EOF 18 | -------------------------------------------------------------------------------- /genhash_int.h: -------------------------------------------------------------------------------- 1 | /** 2 | * \private 3 | */ 4 | struct genhash_entry_t { 5 | /** The key for this entry */ 6 | void *key; 7 | /** Size of the key */ 8 | size_t nkey; 9 | /** The value for this entry */ 10 | void *value; 11 | /** Size of the value */ 12 | size_t nvalue; 13 | /** Pointer to the next entry */ 14 | struct genhash_entry_t *next; 15 | }; 16 | 17 | struct _genhash { 18 | size_t size; 19 | struct hash_ops ops; 20 | struct genhash_entry_t *buckets[]; 21 | }; 22 | -------------------------------------------------------------------------------- /include/memcached/engine_common.h: -------------------------------------------------------------------------------- 1 | #ifndef ENGINE_COMMON_H 2 | #define ENGINE_COMMON_H 3 | 4 | /* Slab sizing definitions. */ 5 | #define POWER_SMALLEST 1 6 | #define POWER_LARGEST 200 7 | #define MAX_SLAB_CLASSES (POWER_LARGEST+1) 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | typedef struct engine_interface { 14 | uint64_t interface; /**< The version number on the engine structure */ 15 | } ENGINE_HANDLE; 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | #endif /* ENGINE_COMMON_H */ 22 | -------------------------------------------------------------------------------- /t/issue_50.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 1; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine, '-B binary'); 11 | my $sock = $server->sock; 12 | 13 | $SIG{ALRM} = sub { die "alarm\n" }; 14 | alarm(2); 15 | print $sock "Here's a bunch of garbage that doesn't look like the bin prot."; 16 | my $rv = <$sock>; 17 | ok(1, "Either the above worked and quit, or hung forever."); 18 | 19 | # after test 20 | release_memcached($engine, $server); 21 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | man_MANS = memcached.1 2 | 3 | EXTRA_DIST = *.txt 4 | 5 | BUILT_SOURCES= 6 | 7 | if BUILD_SPECIFICATIONS 8 | BUILT_SOURCES += protocol-binary.txt protocol-binary-range.txt \ 9 | engine-interface.txt 10 | MOSTLYCLEANFILES = protocol-binary.txt protocol-binary-range.txt \ 11 | engine-interface.txt 12 | endif 13 | 14 | %.txt: %.full 15 | @XML2RFC@ $< $@ 16 | 17 | %.chk: %.xml xml2rfc/rfc2629-refchk.xsl 18 | @XSLTPROC@ xml2rfc/rfc2629-refchk.xsl $< >$@ 19 | 20 | %.full: %.xml xml2rfc/rfc2629-noinc.xsl 21 | @XSLTPROC@ xml2rfc/rfc2629-noinc.xsl $< >$@ 22 | -------------------------------------------------------------------------------- /t/issue_arcus_655.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 2; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $expire = time() - 1; # immediate expiration 14 | my $cmd = "bop insert bkey 0 6 create 0 $expire 10"; 15 | my $val = "datum0"; 16 | my $rst = "CREATED_STORED"; 17 | mem_cmd_is($sock, $cmd, $val, $rst); 18 | 19 | $cmd = "bop get bkey 0"; 20 | $rst = "NOT_FOUND"; 21 | mem_cmd_is($sock, $cmd, "", $rst); 22 | 23 | release_memcached($engine, $server) 24 | -------------------------------------------------------------------------------- /t/line-lengths.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use FindBin qw($Bin); 4 | our @files; 5 | 6 | BEGIN { 7 | chdir "$Bin/.." or die; 8 | @files = ( "doc/protocol.txt" ); 9 | } 10 | 11 | use Test::More tests => scalar(@files); 12 | 13 | foreach my $f (@files) { 14 | open(my $fh, $f) or die("Can't open $f"); 15 | my @long_lines = (); 16 | my $line_number = 0; 17 | while(<$fh>) { 18 | $line_number++; 19 | if(length($_) > 80) { 20 | push(@long_lines, $line_number); 21 | } 22 | } 23 | close($fh); 24 | ok(@long_lines == 0, "$f has a long lines: @long_lines"); 25 | } 26 | -------------------------------------------------------------------------------- /t/issue_152.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 2; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val; 14 | my $rst; 15 | 16 | # key string longer than KEY_MAX_LENGTH 17 | my $key = "a"x32001; 18 | 19 | $cmd = "set a 1 0 1"; $val = "a"; $rst = "STORED"; 20 | mem_cmd_is($sock, $cmd, $val, $rst); 21 | 22 | $cmd = "get a $key"; $rst = "CLIENT_ERROR bad command line format"; 23 | mem_cmd_is($sock, $cmd, "", $rst); 24 | 25 | # after test 26 | release_memcached($engine, $server); 27 | -------------------------------------------------------------------------------- /sasl_auxprop.h: -------------------------------------------------------------------------------- 1 | #ifndef SASL_AUXPROP_H 2 | #define SASL_AUXPROP_H 3 | 4 | #ifdef ENABLE_SASL 5 | #ifdef ENABLE_ZK_INTEGRATION 6 | 7 | #include 8 | #include 9 | 10 | int arcus_auxprop_plug_init(const sasl_utils_t *utils, 11 | int max_version, 12 | int *out_version, 13 | sasl_auxprop_plug_t **plug, 14 | const char *plugname); 15 | 16 | int arcus_getdata(const char *user, char *out, const size_t max_out); 17 | 18 | #endif /* ENABLE_ZK_INTEGRATION */ 19 | #endif /* ENABLE_SASL */ 20 | 21 | #endif /* SASL_AUXPROP_H */ 22 | -------------------------------------------------------------------------------- /t/maxconns.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use Test::More tests => 11; 7 | 8 | use FindBin qw($Bin); 9 | use lib "$Bin/lib"; 10 | use MemcachedTest; 11 | 12 | 13 | # start up a server with 10 maximum connections 14 | my $engine = shift; 15 | my $server = get_memcached($engine, '-c 20'); 16 | my $sock = $server->sock; 17 | my @sockets; 18 | 19 | ok(defined($sock), 'Connection 0'); 20 | push (@sockets, $sock); 21 | 22 | 23 | foreach my $conn (1..10) { 24 | $sock = $server->new_sock; 25 | ok(defined($sock), "Made connection $conn"); 26 | push(@sockets, $sock); 27 | } 28 | 29 | # after test 30 | release_memcached($engine, $server); 31 | -------------------------------------------------------------------------------- /devtools/clean-whitespace.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use FindBin qw($Bin); 4 | chdir "$Bin/.." or die; 5 | my @files = (glob("*.h"), glob("./include/memcached/*.h"), glob("*.c"), glob("*.ac"), glob("./win32/*.c"), glob("./win32/*.h"), glob("./m4/*.m4"), glob("./t/*.t")); 6 | 7 | foreach my $f (@files) { 8 | open(my $fh, $f) or die; 9 | my $before = do { local $/; <$fh>; }; 10 | close ($fh); 11 | my $after = $before; 12 | $after =~ s/\t/ /g; 13 | $after =~ s/ +$//mg; 14 | $after .= "\n" unless $after =~ /\n$/; 15 | next if $after eq $before; 16 | open(my $fh, ">$f") or die; 17 | print $fh $after; 18 | close($fh); 19 | } 20 | -------------------------------------------------------------------------------- /include/memcached/extension_loggers.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #ifndef MEMCACHED_EXTENSION_LOGGERS_H 3 | #define MEMCACHED_EXTENSION_LOGGERS_H 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | MEMCACHED_PUBLIC_API EXTENSION_LOGGER_DESCRIPTOR* get_null_logger(void); 11 | 12 | MEMCACHED_PUBLIC_API EXTENSION_LOGGER_DESCRIPTOR* get_stderr_logger(void); 13 | 14 | MEMCACHED_PUBLIC_API 15 | EXTENSION_ERROR_CODE memcached_initialize_stderr_logger(GET_SERVER_API get_server_api); 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | #endif /* MEMCACHED_EXTENSION_LOGGER_H */ 22 | -------------------------------------------------------------------------------- /t/binary-get.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 8; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $count = 1; 14 | my $cmd; 15 | my $val; 16 | my $rst; 17 | 18 | foreach my $blob ("mooo\0", "mumble\0\0\0\0\r\rblarg", "\0", "\r") { 19 | my $key = "foo$count"; 20 | my $len = length($blob); 21 | $cmd = "set $key 0 0 $len"; $val = $blob; $rst = "STORED"; 22 | mem_cmd_is($sock, $cmd, $val, $rst); 23 | mem_get_is($sock, $key, $blob); 24 | $count++; 25 | } 26 | 27 | # after test 28 | release_memcached($engine, $server); 29 | -------------------------------------------------------------------------------- /t/flags.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 6; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val; 14 | my $rst; 15 | 16 | # set foo (and should get it) 17 | for my $flags (0, 123, 2**16-1) { 18 | $cmd = "set foo $flags 0 6"; $val = "fooval"; $rst = "STORED"; 19 | mem_cmd_is($sock, $cmd, $val, $rst); 20 | $cmd = "get foo"; 21 | $rst = "VALUE foo $flags 6\n" 22 | . "fooval\n" 23 | . "END"; 24 | mem_cmd_is($sock, $cmd, "", $rst); 25 | } 26 | 27 | # after test 28 | release_memcached($engine, $server); 29 | -------------------------------------------------------------------------------- /t/binary_crash.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 2; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | ok($server->new_sock, "opened new socket"); 14 | 15 | print $sock "\x80\x12\x00\x01\x08\x00\x00\x00\xff\xff\xff\xe8\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\xff\xff\x01\x00\x00\x00\x00\x00\x00\x00\x00\x000\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"; 16 | 17 | sleep 0.5; 18 | ok($server->new_sock, "failed to open new socket"); 19 | 20 | # after test 21 | release_memcached($engine, $server); 22 | -------------------------------------------------------------------------------- /scripts/README.damemtop: -------------------------------------------------------------------------------- 1 | dormando's awesome memcached top 2 | 3 | A flexible 'top' like utility for viewing memcached clusters. 4 | 5 | Under development. Latest code is available at: 6 | http://github.com/dormando/damemtop 7 | 8 | See --help for full information. 9 | 10 | Requires 'AnyEvent', and 'YAML' libraries from CPAN: 11 | http://search.cpan.org/ 12 | 13 | 'AnyEvent' depends on 'common::sense' (also at CPAN). 14 | 15 | If you have a large cluster and want higher performance, find 16 | and install 'EV' from CPAN. AnyEvent will automagically use it 17 | and use epoll, kqeueue, etc, for socket handling. 18 | 19 | Pester me for questions/bugs/ideas. As of writing the util is 20 | in early release and missing many future features. 21 | -------------------------------------------------------------------------------- /t/issue_61.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 2; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine, "-R 1"); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $rst; 14 | 15 | $cmd = "set foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba\r\nset foobar 0 0 5\r\nBubba"; 16 | $rst = "STORED\n" 17 | . "STORED\n" 18 | . "STORED\n" 19 | . "STORED\n" 20 | . "STORED\n" 21 | . "STORED"; 22 | mem_cmd_is($sock, $cmd, "", $rst); 23 | my $stats = mem_stats($sock); 24 | is ($stats->{"conn_yields"}, "5", "Got a decent number of yields"); 25 | 26 | # after test 27 | release_memcached($engine, $server); 28 | -------------------------------------------------------------------------------- /doc/xml2rfc/reference.RFC.0768.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | User Datagram Protocol 7 | 8 | University of Southern California (USC)/Information Sciences Institute 9 |
10 | 11 | 4676 Admiralty Way 12 | Marina del Rey 13 | CA 14 | 90291 15 | US 16 | +1 213 822 1511
17 |
18 | 19 | 20 | 21 | 22 |
23 | -------------------------------------------------------------------------------- /t/unixsocket.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 3; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $filename = "/tmp/memcachetest$$"; 10 | 11 | my $engine = shift; 12 | my $server = get_memcached($engine, "-s $filename"); 13 | my $sock = $server->sock; 14 | my $cmd; 15 | my $val; 16 | my $rst; 17 | 18 | ok(-S $filename, "creating unix domain socket $filename"); 19 | 20 | # set foo (and should get it) 21 | $cmd = "set foo 0 0 6"; $val = "fooval"; $rst = "STORED"; 22 | mem_cmd_is($sock, $cmd, $val, $rst); 23 | $cmd = "get foo"; 24 | $rst = "VALUE foo 0 6 25 | fooval 26 | END"; 27 | mem_cmd_is($sock, $cmd, "", $rst); 28 | 29 | unlink($filename); 30 | 31 | ## Just some basic stuff for now... 32 | 33 | # after test 34 | release_memcached($engine, $server); 35 | -------------------------------------------------------------------------------- /t/issue_70.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 4; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val; 14 | my $rst; 15 | my $msg; 16 | 17 | $cmd = "set issue70 0 0 0\r\n"; $rst = "STORED"; $msg = "stored issue70"; 18 | mem_cmd_is($sock, $cmd, "", $rst); 19 | 20 | $cmd = "set issue70 0 0 -1"; $rst = "CLIENT_ERROR bad command line format"; 21 | mem_cmd_is($sock, $cmd, "", $rst); 22 | 23 | $cmd = "set issue70 0 0 4294967295"; $rst = "CLIENT_ERROR bad command line format"; 24 | mem_cmd_is($sock, $cmd, "", $rst); 25 | 26 | $cmd = "set issue70 0 0 2147483647"; $val = "scoobyscoobydoo"; 27 | $rst = "CLIENT_ERROR bad command line format"; 28 | mem_cmd_is($sock, $cmd, $val, $rst); 29 | 30 | # after test 31 | release_memcached($engine, $server); 32 | -------------------------------------------------------------------------------- /globals.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include "memcached.h" 3 | 4 | /* 5 | * This file contains global variables shared across the rest of the 6 | * memcached codebase. These were originally in memcached.c but had 7 | * to be removed to make the rest of the object files linkable into 8 | * the test infrastructure. 9 | * 10 | */ 11 | 12 | /* 13 | * We keep the current time of day in a global variable that's updated by a 14 | * timer event. This saves us a bunch of time() system calls (we really only 15 | * need to get the time once a second, whereas there can be tens of thousands 16 | * of requests a second) and allows us to use server-start-relative timestamps 17 | * rather than absolute UNIX timestamps, a space savings on systems where 18 | * sizeof(time_t) > sizeof(unsigned int). 19 | */ 20 | volatile rel_time_t current_time; 21 | 22 | /** exported globals **/ 23 | struct stats stats; 24 | struct settings settings; 25 | -------------------------------------------------------------------------------- /t/issue_104.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 6; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val; 14 | my $rst; 15 | 16 | # first get should miss 17 | $cmd = "get foo"; $rst = "END"; 18 | mem_cmd_is($sock, $cmd, "", $rst); 19 | 20 | # Now set and get (should hit) 21 | $cmd = "set foo 0 0 6"; $val = "fooval"; $rst = "STORED"; 22 | mem_cmd_is($sock, $cmd, $val, $rst); 23 | $cmd = "get foo"; 24 | $rst = "VALUE foo 0 6 25 | fooval 26 | END"; 27 | mem_cmd_is($sock, $cmd, "", $rst); 28 | 29 | my $stats = mem_stats($sock); 30 | is($stats->{cmd_get}, 2, "Should have 2 get requests"); 31 | is($stats->{get_hits}, 1, "Should have 1 hit"); 32 | is($stats->{get_misses}, 1, "Should have 1 miss"); 33 | 34 | # after test 35 | release_memcached($engine, $server); 36 | -------------------------------------------------------------------------------- /rfc1321/global.h: -------------------------------------------------------------------------------- 1 | /* GLOBAL.H - RSAREF types and constants 2 | */ 3 | 4 | /* PROTOTYPES should be set to one if and only if the compiler supports 5 | function argument prototyping. 6 | The following makes PROTOTYPES default to 0 if it has not already 7 | been defined with C compiler flags. 8 | */ 9 | #ifndef PROTOTYPES 10 | #define PROTOTYPES 0 11 | #endif 12 | 13 | #include 14 | 15 | /* POINTER defines a generic pointer type */ 16 | typedef unsigned char *POINTER; 17 | 18 | /* UINT2 defines a two byte word */ 19 | typedef uint16_t UINT2; 20 | 21 | /* UINT4 defines a four byte word */ 22 | typedef uint32_t UINT4; 23 | 24 | /* PROTO_LIST is defined depending on how PROTOTYPES is defined above. 25 | If using PROTOTYPES, then PROTO_LIST returns the list, otherwise it 26 | returns an empty list. 27 | */ 28 | #if PROTOTYPES 29 | #define PROTO_LIST(list) list 30 | #else 31 | #define PROTO_LIST(list) () 32 | #endif 33 | 34 | -------------------------------------------------------------------------------- /t/dash-M.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine, '-M -m 1'); 11 | my $sock = $server->sock; 12 | 13 | my $value = "B" x 8192; 14 | my $vallen = length($value); 15 | 16 | my $resp = "STORED\r\n"; 17 | my $key = 0; 18 | 19 | while($resp eq "STORED\r\n") { 20 | print $sock "set dash$key 0 0 $vallen\r\n$value\r\n"; 21 | $key++; 22 | $resp = scalar <$sock>; 23 | } 24 | 25 | my $max_stored = $key - 1; 26 | 27 | plan tests => $max_stored + 1; 28 | 29 | print $sock "set dash$key 0 0 $vallen\r\n$value\r\n"; 30 | is(scalar <$sock>, "SERVER_ERROR out of memory storing object\r\n", 31 | "failed to add another one."); 32 | 33 | for($key = 0; $key < $max_stored; $key++) { 34 | mem_get_is $sock, "dash$key", $value, "Failed at dash$key"; 35 | } 36 | 37 | # after test 38 | release_memcached($engine, $server); 39 | -------------------------------------------------------------------------------- /t/daemonize.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 7; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | use File::Temp qw(tempfile); 10 | 11 | my (undef, $tmpfn) = tempfile(); 12 | 13 | my $engine = shift; 14 | my $server = get_memcached($engine, "-d -P $tmpfn"); 15 | my $sock = $server->sock; 16 | sleep 0.5; 17 | 18 | ok(-e $tmpfn, "pid file exists"); 19 | ok(-s $tmpfn, "pid file has length"); 20 | 21 | open (my $fh, $tmpfn) or die; 22 | my $readpid = do { local $/; <$fh>; }; 23 | chomp $readpid; 24 | close ($fh); 25 | 26 | ok(kill(0, $readpid), "process is still running"); 27 | 28 | my $stats = mem_stats($sock); 29 | is($stats->{pid}, $readpid, "memcached reports same pid as file"); 30 | 31 | ok($server->new_sock, "opened new socket"); 32 | ok(kill(9, $readpid), "sent KILL signal"); 33 | sleep 0.5; 34 | ok(! $server->new_sock, "failed to open new socket"); 35 | 36 | # after test 37 | release_memcached($engine, $server); 38 | -------------------------------------------------------------------------------- /t/issue_68.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 996; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val; 14 | my $rst; 15 | my $msg; 16 | 17 | for (my $keyi = 1; $keyi < 250; $keyi++) { 18 | my $key = "x" x $keyi; 19 | $cmd = "set $key 0 0 1"; $val = "9"; $rst = "STORED"; 20 | mem_cmd_is($sock, $cmd, $val, $rst); 21 | $cmd = "get $key"; 22 | $rst = "VALUE $key 0 1\n" 23 | . "9\n" 24 | . "END"; 25 | mem_cmd_is($sock, $cmd, "", $rst); 26 | $cmd = "incr $key 1"; $rst = "10"; $msg = "incr $key to 10"; 27 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 28 | $cmd = "get $key"; 29 | $rst = "VALUE $key 0 2\n" 30 | . "10\n" 31 | . "END"; 32 | mem_cmd_is($sock, $cmd, "", $rst); 33 | } 34 | 35 | # after test 36 | release_memcached($engine, $server); 37 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Dependencies: 2 | 3 | -- libevent, http://www.monkey.org/~provos/libevent/ (libevent-dev) 4 | 5 | If using Linux, you need a kernel with epoll. Sure, libevent will 6 | work with normal select, but it sucks. 7 | 8 | epoll isn't in Linux 2.4, but there's a backport at: 9 | 10 | http://www.xmailserver.org/linux-patches/nio-improve.html 11 | 12 | You want the epoll-lt patch (level-triggered). 13 | 14 | If you're using MacOS, you'll want libevent 1.1 or higher to deal with 15 | a kqueue bug. 16 | 17 | Also, be warned that the -k (mlockall) option to memcached might be 18 | dangerous when using a large cache. Just make sure the memcached machines 19 | don't swap. memcached does non-blocking network I/O, but not disk. (it 20 | should never go to disk, or you've lost the whole point of it) 21 | 22 | The memcached website is at: 23 | 24 | http://www.memcached.org 25 | 26 | Want to contribute? Up-to-date pointers should be at: 27 | 28 | http://contributing.appspot.com/memcached 29 | -------------------------------------------------------------------------------- /t/issue_108.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 4; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $key = "del_key"; 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | my $msg; 17 | 18 | $cmd = "add $key 0 0 1"; $val = "x"; $rst = "STORED"; 19 | mem_cmd_is($sock, $cmd, $val, $rst); 20 | 21 | $cmd = "delete $key 0"; $rst = "DELETED"; $msg = "Properly deleted with 0"; 22 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 23 | 24 | $cmd = "add $key 0 0 1"; $val = "x"; $rst = "STORED"; 25 | mem_cmd_is($sock, $cmd, $val, $rst); 26 | 27 | print $sock "delete $key 0 noreply\r\n"; 28 | # will not reply, but a subsequent add will succeed 29 | 30 | $cmd = "add $key 0 0 1"; $val = "x"; $rst = "STORED"; 31 | $msg = "Add succeeded after quiet deletion."; 32 | mem_cmd_is($sock, $cmd, $val, $rst, $msg); 33 | 34 | # after test 35 | release_memcached($engine, $server); 36 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rockylinux:8 AS builder 2 | RUN yum update -y 3 | RUN yum install -y make libtool which git 4 | # Copy all files from the repository not included in .dockerignore to /src in the image. 5 | COPY . /src 6 | WORKDIR /src 7 | RUN ./deps/install.sh /arcus || (tail ./deps/install.log; exit 1) 8 | RUN ./config/autorun.sh 9 | RUN ./configure --prefix=/arcus --enable-zk-integration 10 | RUN make && make install 11 | 12 | FROM rockylinux:8 AS base 13 | COPY --from=builder /arcus /arcus 14 | ENV PATH=${PATH}:/arcus/bin 15 | 16 | EXPOSE 11211/tcp 17 | 18 | ENTRYPOINT ["memcached",\ 19 | "-E", "/arcus/lib/default_engine.so",\ 20 | "-X", "/arcus/lib/ascii_scrub.so",\ 21 | "-u", "root",\ 22 | "-D", ":",\ 23 | "-r"] 24 | 25 | # for arcus-operator 26 | FROM base 27 | RUN yum update -y 28 | RUN yum install -y bind-utils nc 29 | RUN yum clean all -y 30 | ENV MEMCACHED_DIR=/arcus-memcached 31 | ENV PATH=${PATH}:${MEMCACHED_DIR} 32 | ENV ARCUS_USER=root 33 | WORKDIR ${MEMCACHED_DIR} 34 | RUN ln -s /arcus/lib ${MEMCACHED_DIR}/.libs 35 | -------------------------------------------------------------------------------- /run_test.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use Cwd; 4 | 5 | my $engine_name = shift; 6 | my $script_type = shift; 7 | my @engine_list = ("default"); 8 | my $opt = '--job 2'; # --job N : run N test jobs in parallel 9 | my $srcdir = getcwd; 10 | my $ext = "s"; 11 | 12 | if ($script_type eq "big") { 13 | $ext = "b"; 14 | } 15 | 16 | # default engine specific test script : ./t/default 17 | # common engine test script : ./t 18 | 19 | if (grep $_ eq $engine_name, @engine_list) { 20 | my $returnCode = system("prove $opt - < $srcdir/t/tlist/engine_$engine_name\_$ext\.txt :: $engine_name"); 21 | if ($returnCode != 0) { 22 | exit(1); 23 | } 24 | } elsif ("$engine_name" eq "") { 25 | # default engine test 26 | my $returnCode = system("prove $opt - < $srcdir/t/tlist/engine_default_$ext\.txt :: default"); 27 | if ($returnCode != 0) { 28 | exit(1); 29 | } 30 | } else { 31 | system("echo -e \'\033[31mmake test [TYPE=] [ENGINE=<@engine_list>]\033[0m\n\'"); 32 | exit(1); 33 | } 34 | -------------------------------------------------------------------------------- /t/issue_14.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 21; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val = "B"x66560; 14 | my $rst; 15 | my $key = 0; 16 | 17 | for ($key = 0; $key < 10; $key++) { 18 | $cmd = "set key$key 0 2 66560"; $rst = "STORED"; 19 | mem_cmd_is($sock, $cmd, $val, $rst); 20 | } 21 | 22 | #print $sock "stats slabs" 23 | my $first_stats = mem_stats($sock, "slabs"); 24 | my $first_malloc = $first_stats->{total_malloced}; 25 | 26 | sleep(4); 27 | 28 | for ($key = 10; $key < 20; $key++) { 29 | $cmd = "set key$key 0 2 66560"; $rst = "STORED"; 30 | mem_cmd_is($sock, $cmd, $val, $rst); 31 | } 32 | 33 | my $second_stats = mem_stats($sock, "slabs"); 34 | my $second_malloc = $second_stats->{total_malloced}; 35 | 36 | is ($second_malloc, $first_malloc, "Memory grows.."); 37 | 38 | # after test 39 | release_memcached($engine, $server); 40 | -------------------------------------------------------------------------------- /t/issue_42.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 11; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val = "B"x10; 14 | my $rst; 15 | my $key = 0; 16 | 17 | for ($key = 0; $key < 10; $key++) { 18 | $cmd = "set key$key 0 0 10"; $rst = "STORED"; 19 | mem_cmd_is($sock, $cmd, $val, $rst); 20 | } 21 | 22 | my $first_stats = mem_stats($sock, "slabs"); 23 | ### [ARCUS] CHANGED FOLLOWING TEST ### 24 | # Arcus uses small memory allocator. 25 | # So, the used chunk is the chunk of the small memory allocator. 26 | # And, the chunk size of small memory allocator is 64KB. 27 | #my $req = $first_stats->{"1:mem_requested"}; 28 | #ok ($req == "600" || $req == "720", "Check allocated size"); 29 | my $req = $first_stats->{"0:mem_requested"}; 30 | ok ($req == "262144", "Check allocated size"); 31 | ###################################### 32 | 33 | # after test 34 | release_memcached($engine, $server); 35 | -------------------------------------------------------------------------------- /t/cmd_extensions.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | 6 | use Test::More tests => 5; 7 | 8 | use FindBin qw($Bin); 9 | use lib "$Bin/lib"; 10 | use MemcachedTest; 11 | 12 | my $engine = shift; 13 | my $server = get_memcached($engine, '-X .libs/example_protocol.so'); 14 | my $sock = $server->sock; 15 | my $cmd; 16 | my $val; 17 | my $rst; 18 | 19 | 20 | ok(defined($sock), 'Connection 0'); 21 | 22 | $cmd = "noop"; $rst = "OK"; 23 | mem_cmd_is($sock, $cmd, "", $rst); 24 | 25 | $cmd = "echo foo bar"; $rst = "echo [foo] [bar]"; 26 | mem_cmd_is($sock, $cmd, "", $rst); 27 | 28 | $cmd = "echo 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7"; 29 | $rst = "echo [1] [2] [3] [4] [5] [6] [7] [8] [9] [0] " 30 | . "[1] [2] [3] [4] [5] [6] [7] [8] [9] [0] [1] [2] [3] [4] [5] [6] [7]"; 31 | mem_cmd_is($sock, $cmd, "", $rst); 32 | 33 | $cmd = "echo 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8"; 34 | $rst = "ERROR too many arguments"; 35 | mem_cmd_is($sock, $cmd, "", $rst); 36 | 37 | # after test 38 | release_memcached($engine, $server); 39 | -------------------------------------------------------------------------------- /t/scrub.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 83; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine, "-X .libs/ascii_scrub.so"); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val; 14 | my $rst; 15 | my $key = 0; 16 | 17 | for ($key = 0; $key < 40; $key++) { 18 | $cmd = "set key$key 0 0 5"; $val = "value"; $rst = "STORED"; 19 | mem_cmd_is($sock, $cmd, $val, $rst); 20 | } 21 | 22 | for ($key = 40; $key < 80; $key++) { 23 | $cmd = "set key$key 0 1 5"; $val = "value"; $rst = "STORED"; 24 | mem_cmd_is($sock, $cmd, $val, $rst); 25 | } 26 | 27 | sleep(1.5); 28 | $cmd = "scrub"; $rst = "OK"; 29 | mem_cmd_is($sock, $cmd, "", $rst, "scrub started"); 30 | sleep(1.0); 31 | my $stats = mem_stats($sock, "scrub"); 32 | my $visited = $stats->{"scrubber:visited"}; 33 | my $cleaned = $stats->{"scrubber:cleaned"}; 34 | 35 | is ($visited, "80", "visited"); 36 | is ($cleaned, "40", "cleaned"); 37 | 38 | # after test 39 | release_memcached($engine, $server); 40 | -------------------------------------------------------------------------------- /engine_loader.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #ifndef ENGINE_LOADER_H 3 | #define ENGINE_LOADER_H 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | MEMCACHED_PUBLIC_API bool load_engine(const char *soname, 13 | SERVER_HANDLE_V1 *(*get_server_api)(void), 14 | EXTENSION_LOGGER_DESCRIPTOR *logger, 15 | ENGINE_HANDLE **engine_handle); 16 | 17 | MEMCACHED_PUBLIC_API bool init_engine(ENGINE_HANDLE * engine, 18 | const char *config_str, 19 | EXTENSION_LOGGER_DESCRIPTOR *logger); 20 | 21 | MEMCACHED_PUBLIC_API void log_engine_details(ENGINE_HANDLE * engine, 22 | EXTENSION_LOGGER_DESCRIPTOR *logger); 23 | 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif /* ENGINE_LOADER_H */ 29 | -------------------------------------------------------------------------------- /t/evictions.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # Test the 'stats items' evictions counters. 3 | 4 | use strict; 5 | use Test::More tests => 92; 6 | use FindBin qw($Bin); 7 | use lib "$Bin/lib"; 8 | use MemcachedTest; 9 | 10 | my $engine = shift; 11 | my $server = get_memcached($engine, "-m 3"); 12 | my $sock = $server->sock; 13 | my $cmd; 14 | my $val = "B"x66560; 15 | my $rst; 16 | my $key = 0; 17 | 18 | # These aren't set to expire. 19 | for ($key = 0; $key < 40; $key++) { 20 | $cmd = "set key$key 0 0 66560"; $rst = "STORED"; 21 | mem_cmd_is($sock, $cmd, $val, $rst); 22 | } 23 | 24 | # These ones would expire in 600 seconds. 25 | for ($key = 0; $key < 50; $key++) { 26 | $cmd = "set key$key 0 600 66560"; $rst = "STORED"; 27 | mem_cmd_is($sock, $cmd, $val, $rst); 28 | } 29 | 30 | my $stats = mem_stats($sock, "items"); 31 | my $evicted = $stats->{"items:31:evicted"}; 32 | isnt($evicted, "0", "check evicted"); 33 | my $evicted_nonzero = $stats->{"items:31:evicted_nonzero"}; 34 | isnt($evicted_nonzero, "0", "check evicted_nonzero"); 35 | 36 | # after test 37 | release_memcached($engine, $server); 38 | -------------------------------------------------------------------------------- /.github/workflows/CI.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "develop" ] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | - name: Install Arcus Server Dependency Packages 17 | run: sudo apt-get install -qq build-essential autoconf automake libtool 18 | - name: Cache ARCUS Directory 19 | id: arcus-cache 20 | uses: actions/cache@v4 21 | with: 22 | path: ~/arcus 23 | key: ${{runner.os}}-arcus 24 | - name: Install Arcus Server Dependency Libraries 25 | if: steps.arcus-cache.outputs.cache-hit != 'true' 26 | run: ./deps/install.sh $HOME/arcus 27 | - name: Build Arcus Server 28 | run: | 29 | ./config/autorun.sh 30 | ./configure --enable-zk-integration --with-zk-reconfig --enable-sasl --with-libevent=${HOME}/arcus --with-zookeeper=${HOME}/arcus --with-sasl=${HOME}/arcus 31 | make 32 | - name: Test ARCUS Server 33 | run: make test 34 | -------------------------------------------------------------------------------- /sasl_defs.h: -------------------------------------------------------------------------------- 1 | #ifndef SASL_DEFS_H 2 | #define SASL_DEFS_H 1 3 | 4 | // Longest one I could find was ``9798-U-RSA-SHA1-ENC'' 5 | #define MAX_SASL_MECH_LEN 32 6 | 7 | 8 | #if defined(ENABLE_SASL) 9 | 10 | #include 11 | int init_sasl(void); 12 | void shutdown_sasl(void); 13 | uint16_t arcus_sasl_authz(const char *username); 14 | 15 | #elif defined(ENABLE_ISASL) 16 | 17 | #include "isasl.h" 18 | int init_sasl(void); 19 | void shutdown_sasl(void); 20 | uint16_t arcus_sasl_authz(const char *username); 21 | 22 | #else /* End of SASL support */ 23 | 24 | typedef void* sasl_conn_t; 25 | 26 | #define shutdown_sasl() 27 | #define init_sasl() 0 28 | #define arcus_sasl_authz(a) 0 29 | #define sasl_dispose(x) {} 30 | #define sasl_server_new(a, b, c, d, e, f, g, h) 1 31 | #define sasl_listmech(a, b, c, d, e, f, g, h) 1 32 | #define sasl_server_start(a, b, c, d, e, f) 1 33 | #define sasl_server_step(a, b, c, d, e) 1 34 | #define sasl_getprop(a, b, c) {} 35 | 36 | #define SASL_CONTINUE 1 37 | #define SASL_OK 0 38 | #define SASL_FAIL -1 39 | 40 | #endif /* sasl compat */ 41 | 42 | #endif /* SASL_DEFS_H */ 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Keep the entries sorted to reduce the risk for a merge conflict 2 | *.[ao] 3 | *.exe 4 | *.gcda 5 | *.gcno 6 | *.gcov 7 | *.l[ao] 8 | *.tcov 9 | *~ 10 | .deps 11 | .dirstamp 12 | /.libs/ 13 | /aclocal.m4 14 | /arcus-memcached-*.tar.gz 15 | /autom4te.cache 16 | /compile 17 | /config.guess 18 | /config.h 19 | /config.h.in 20 | /config.log 21 | /config.status 22 | /config.sub 23 | /config/Doxyfile 24 | /config/Doxyfile-api 25 | /configure 26 | /depcomp 27 | /deps/* 28 | !/deps/*.tar.gz 29 | !/deps/install.sh 30 | /doc/doxy 31 | /doc/doxy-api 32 | /doc/engine-interface.txt 33 | /doc/protocol-binary-range.txt 34 | /doc/protocol-binary.txt 35 | /engine_testapp 36 | /install-sh 37 | /libtool 38 | /ltmain.sh 39 | /m4/version.m4 40 | /memcached 41 | /memcached-*.tar.gz 42 | /memcached-debug 43 | /memcached-debug.profile 44 | /memcached.spec 45 | /memcached_dtrace.h 46 | /missing 47 | /mkinstalldirs 48 | /sizes 49 | /stamp-h1 50 | /t/binary-sasl.t 51 | /testapp 52 | /timedrun 53 | /version.num 54 | Makefile 55 | Makefile.in 56 | TAGS 57 | cscope.out 58 | tags 59 | 60 | # MacOS 61 | .DS_Store 62 | 63 | # Visual Stuido Code 64 | .vscode 65 | -------------------------------------------------------------------------------- /sizes.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | 4 | #include "memcached.h" 5 | 6 | static void display(const char *name, size_t size) 7 | { 8 | printf("%s\t%d\n", name, (int)size); 9 | } 10 | 11 | int main(int argc, char **argv) 12 | { 13 | display("Thread stats", sizeof(struct thread_stats)); 14 | display("Global stats", sizeof(struct mc_stats)); 15 | display("Settings", sizeof(struct settings)); 16 | display("Libevent thread", sizeof(LIBEVENT_THREAD)); 17 | display("Connection", sizeof(conn)); 18 | 19 | printf("----------------------------------------\n"); 20 | 21 | display("libevent thread cumulative", sizeof(LIBEVENT_THREAD)); 22 | display("Thread stats cumulative\t", sizeof(struct thread_stats)); 23 | 24 | printf("----------------------------------------\n"); 25 | 26 | display("hash item info\t", sizeof(item_info)); 27 | display("elem item info\t", sizeof(eitem_info)); 28 | display("item attributes\t", sizeof(item_attr)); 29 | display("eflag filter\t", sizeof(eflag_filter)); 30 | display("eflag update\t", sizeof(eflag_update)); 31 | display("Pipe reponse buffer", PIPE_RES_MAX_SIZE); 32 | 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /cmdlog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * arcus-memcached - Arcus memory cache server 3 | * Copyright 2015 JaM2in Co., Ltd. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #ifndef CMDLOG_H 18 | #define CMDLOG_H 19 | 20 | #include 21 | 22 | #include "memcached/extension.h" 23 | 24 | #define COMMAND_LOGGING 25 | 26 | extern bool cmdlog_in_use; 27 | 28 | void cmdlog_init(int port, EXTENSION_LOGGER_DESCRIPTOR *logger); 29 | void cmdlog_final(void); 30 | int cmdlog_start(char *file_path, bool *already_started); 31 | void cmdlog_stop(bool *already_stopped); 32 | char *cmdlog_stats(void); 33 | void cmdlog_write(char *client_ip, char *command); 34 | #endif 35 | -------------------------------------------------------------------------------- /t/issue_41.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use warnings; 5 | use POSIX qw(ceil); 6 | use Test::More tests => 691; 7 | use FindBin qw($Bin); 8 | use lib "$Bin/lib"; 9 | use MemcachedTest; 10 | 11 | my $engine = shift; 12 | my $server = get_memcached($engine); 13 | my $sock = $server->sock; 14 | 15 | my $factor = 2; 16 | my $cmd; 17 | my $val = "x" x $factor; 18 | my $rst; 19 | my $key = ''; 20 | 21 | # SET items of diverse size to the daemon so it can attempt 22 | # to return a large stats output for slabs 23 | for (my $i=0; $i<69; $i++) { 24 | for (my $j=0; $j<10; $j++) { 25 | $key = "$i:$j"; 26 | $cmd = "set key$key 0 0 $factor"; $rst = "STORED"; 27 | mem_cmd_is($sock, $cmd, $val, $rst); 28 | } 29 | $factor *= 1.2; 30 | $factor = ceil($factor); 31 | $val = "x" x $factor; 32 | } 33 | 34 | # This request will kill the daemon if it has not allocated 35 | # enough memory internally. 36 | my $stats = mem_stats($sock, "slabs"); 37 | 38 | # Verify whether the daemon is still running or not by asking 39 | # it for statistics. 40 | print $sock "version\r\n"; 41 | my $v = scalar <$sock>; 42 | ok(defined $v && length($v), "memcached didn't respond"); 43 | 44 | # after test 45 | release_memcached($engine, $server); 46 | -------------------------------------------------------------------------------- /t/set_with_largest_slab.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 258; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | 10 | my $engine = shift; 11 | my $server = get_memcached($engine, "-f 1.04"); 12 | my $sock = $server->sock; 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | 17 | # Test sets up to a large size around 1MB. 18 | # Everything up to 1MB - 1k should succeed, everything 1MB +1k should fail. 19 | 20 | my $len = 4096; 21 | while ($len < 1024*1028) { 22 | $val = "B"x$len; 23 | if ($len >= (1024*1024)) { 24 | # Ensure causing a memory overflow doesn't leave stale data. 25 | $cmd = "set foo_$len 0 0 3"; $rst = "STORED"; 26 | mem_cmd_is($sock, $cmd, "MOO", $rst); 27 | $cmd = "set foo_$len 0 0 $len"; $rst = "CLIENT_ERROR object too large for cache"; 28 | mem_cmd_is($sock, $cmd, $val, $rst, "failed to store size $len"); 29 | $cmd = "get foo_$len"; $rst = "END"; 30 | mem_cmd_is($sock, $cmd, "", $rst); 31 | } else { 32 | $cmd = "set foo_$len 0 0 $len"; $rst = "STORED"; 33 | mem_cmd_is($sock, $cmd, $val, $rst, "stored size $len"); 34 | } 35 | $len += 4096; 36 | } 37 | 38 | # after test 39 | release_memcached($engine, $server); 40 | -------------------------------------------------------------------------------- /include/memcached/vbucket.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #ifndef MEMCACHED_VBUCKET_H 3 | #define MEMCACHED_VBUCKET_H 1 4 | 5 | #ifdef __cplusplus 6 | extern "C" 7 | { 8 | #endif 9 | 10 | /* number of vbuckets */ 11 | #define NUM_VBUCKETS 65536 12 | 13 | /* vbucket command */ 14 | #define CMD_SET_VBUCKET 0x83 15 | #define CMD_GET_VBUCKET 0x84 16 | #define CMD_DEL_VBUCKET 0x85 17 | 18 | /* vbucket state */ 19 | enum vbucket_state { 20 | VBUCKET_STATE_DEAD = 0, 21 | VBUCKET_STATE_ACTIVE = 1, 22 | VBUCKET_STATE_REPLICA = 2, 23 | VBUCKET_STATE_PENDING = 3 24 | }; 25 | 26 | struct vbucket_info { 27 | int state : 2; 28 | }; 29 | 30 | union vbucket_info_adapter { 31 | char c; 32 | struct vbucket_info v; 33 | }; 34 | 35 | #if 0 // OLD_CODE 36 | typedef enum { 37 | active = 1, /**< Actively servicing a vbucket. */ 38 | replica, /**< Servicing a vbucket as a replica only. */ 39 | pending, /**< Pending active. */ 40 | dead /**< Not in use, pending deletion. */ 41 | } vbucket_state_t; 42 | 43 | #define is_valid_vbucket_state_t(state) \ 44 | (state == active || state == replica || state == pending || state == dead) 45 | #endif 46 | 47 | #ifdef __cplusplus 48 | } 49 | #endif 50 | #endif 51 | -------------------------------------------------------------------------------- /engines/default/checkpoint.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | /* 3 | * arcus-memcached - Arcus memory cache server 4 | * Copyright 2019 JaM2in Co., Ltd. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef CHECKPOINT_H 19 | #define CHECKPOINT_H 20 | 21 | #include "chkpt_snapshot.h" 22 | 23 | #ifdef ENABLE_PERSISTENCE 24 | /* Recovery Functions */ 25 | int chkpt_recovery_analysis(void); 26 | int chkpt_recovery_redo(void); 27 | 28 | ENGINE_ERROR_CODE chkpt_init(struct default_engine* engine); 29 | ENGINE_ERROR_CODE chkpt_thread_start(void); 30 | 31 | void chkpt_thread_stop(void); 32 | void chkpt_final(void); 33 | 34 | int64_t chkpt_get_lasttime(void); 35 | 36 | void chkpt_persistence_stats(struct default_engine *engine, ADD_STAT add_stat, const void *cookie); 37 | 38 | #endif 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /t/verbosity.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use Test::More tests => 8; 4 | use FindBin qw($Bin); 5 | use lib "$Bin/lib"; 6 | use MemcachedTest; 7 | 8 | my $engine = shift; 9 | my $server = get_memcached($engine); 10 | my $sock = $server->sock; 11 | my $cmd; 12 | my $val; 13 | my $rst; 14 | 15 | $cmd = "config verbosity foo bar my"; $rst = "CLIENT_ERROR bad command line format"; 16 | mem_cmd_is($sock, $cmd, "", $rst, "Illegal number of arguments"); 17 | 18 | $cmd = "config verbosity noreply"; $rst = "CLIENT_ERROR bad command line format"; 19 | mem_cmd_is($sock, $cmd, "", $rst, "Illegal noreply"); 20 | 21 | $cmd = "config verbosity 0"; $rst = "END"; 22 | mem_cmd_is($sock, $cmd, "", $rst, "Correct syntax"); 23 | 24 | my $settings = mem_stats($sock, 'settings'); 25 | is('0', $settings->{'verbosity'}, "Verify settings"); 26 | 27 | $cmd = "config verbosity foo"; $rst = "CLIENT_ERROR bad command line format"; 28 | mem_cmd_is($sock, $cmd, "", $rst, "Not a numeric argument"); 29 | 30 | $cmd = "config verbosity 1"; $rst = "END"; 31 | mem_cmd_is($sock, $cmd, "", $rst,"Correct syntax"); 32 | 33 | $settings = mem_stats($sock, 'settings'); 34 | is('1', $settings->{'verbosity'}, "Verify settings"); 35 | 36 | $cmd = "config verbosity 100"; $rst = "SERVER_ERROR cannot change the verbosity over the limit"; 37 | mem_cmd_is($sock, $cmd, "", $rst, "Over the max value"); 38 | 39 | # after test 40 | release_memcached($engine, $server); 41 | -------------------------------------------------------------------------------- /solaris_priv.c: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | #include 3 | #include 4 | #include 5 | #include "memcached.h" 6 | 7 | /* 8 | * this section of code will drop all (Solaris) privileges including 9 | * those normally granted to all userland process (basic privileges). The 10 | * effect of this is that after running this code, the process will not able 11 | * to fork(), exec(), etc. See privileges(5) for more information. 12 | */ 13 | void drop_privileges(void) { 14 | priv_set_t *privs = priv_str_to_set("basic", ",", NULL); 15 | 16 | if (privs == NULL) { 17 | perror("priv_str_to_set"); 18 | exit(EXIT_FAILURE); 19 | } 20 | 21 | (void)priv_delset(privs, PRIV_FILE_LINK_ANY); 22 | (void)priv_delset(privs, PRIV_PROC_EXEC); 23 | (void)priv_delset(privs, PRIV_PROC_FORK); 24 | (void)priv_delset(privs, PRIV_PROC_INFO); 25 | (void)priv_delset(privs, PRIV_PROC_SESSION); 26 | 27 | if (setppriv(PRIV_SET, PRIV_PERMITTED, privs) != 0) { 28 | perror("setppriv(PRIV_SET, PRIV_PERMITTED)"); 29 | exit(EXIT_FAILURE); 30 | } 31 | 32 | priv_emptyset(privs); 33 | 34 | if (setppriv(PRIV_SET, PRIV_INHERITABLE, privs) != 0) { 35 | perror("setppriv(PRIV_SET, PRIV_INHERITABLE)"); 36 | exit(EXIT_FAILURE); 37 | } 38 | 39 | if (setppriv(PRIV_SET, PRIV_LIMIT, privs) != 0) { 40 | perror("setppriv(PRIV_SET, PRIV_LIMIT)"); 41 | exit(EXIT_FAILURE); 42 | } 43 | 44 | priv_freeset(privs); 45 | } 46 | -------------------------------------------------------------------------------- /engines/default/cmdlogfile.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | /* 3 | * arcus-memcached - Arcus memory cache server 4 | * Copyright 2019 JaM2in Co., Ltd. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef CMDLOGFILE_H 19 | #define CMDLOGFILE_H 20 | 21 | #include "cmdlogrec.h" 22 | 23 | #ifdef ENABLE_PERSISTENCE 24 | /* external log file functions */ 25 | void cmdlog_file_write(char *log_ptr, uint32_t log_size, bool dual_write); 26 | void cmdlog_file_complete_dual_write(void); 27 | bool cmdlog_file_dual_write_finished(void); 28 | int cmdlog_file_sync(void); 29 | 30 | int cmdlog_file_open(char *path); 31 | void cmdlog_file_close(void); 32 | void cmdlog_file_init(struct default_engine* engine); 33 | void cmdlog_file_final(void); 34 | int cmdlog_file_apply(void); 35 | size_t cmdlog_file_getsize(void); 36 | 37 | void cmdlog_get_fsync_lsn(LogSN *lsn); 38 | #endif 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /t/issue_163.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 7; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | ### [ARCUS] CHANGED FOLLOWING TEST ### 10 | ## ENABLE_MIGRATION: hash_item structure has more fields in migration. 11 | #my $server = get_memcached($engine); 12 | my $engine = shift; 13 | my $server = get_memcached($engine, "-n 32"); 14 | ###################################### 15 | my $sock = $server->sock; 16 | my $cmd; 17 | my $val1 = "A"x77320; 18 | my $val2 = "B"x77330; 19 | my $rst; 20 | 21 | $cmd = "set key 0 1 77320"; $rst = "STORED"; 22 | mem_cmd_is($sock, $cmd, $val1, $rst); 23 | 24 | my $stats = mem_stats($sock, "slabs"); 25 | my $requested = $stats->{"31:mem_requested"}; 26 | isnt ($requested, "0", "We should have requested some memory"); 27 | 28 | sleep(3); 29 | $cmd = "set key 0 0 77330"; $rst = "STORED"; 30 | mem_cmd_is($sock, $cmd, $val2, $rst); 31 | 32 | my $stats = mem_stats($sock, "items"); 33 | my $reclaimed = $stats->{"items:31:reclaimed"}; 34 | is ($reclaimed, "1", "Objects should be reclaimed"); 35 | 36 | $cmd = "delete key"; $rst = "DELETED"; 37 | mem_cmd_is($sock, $cmd, "", $rst); 38 | 39 | $cmd = "set key 0 0 77320"; $rst = "STORED"; 40 | mem_cmd_is($sock, $cmd, $val1, $rst); 41 | 42 | my $stats = mem_stats($sock, "slabs"); 43 | my $requested2 = $stats->{"31:mem_requested"}; 44 | is ($requested2, $requested, "we've not allocated and freed the same amont"); 45 | 46 | # after test 47 | release_memcached($engine, $server); 48 | -------------------------------------------------------------------------------- /engines/default/default_engine.conf: -------------------------------------------------------------------------------- 1 | # This is a default engine config file. 2 | # 3 | # 4 | # Max collection size (default: 50000, min: 10000, max: 1000000). 5 | # The maximum number of elements that can be stored in each collection item. 6 | # 7 | # We recommend setting this value below the default to avoid latency problems. 8 | # The request for an item that has many elements could cause to delay 9 | # not only in response to itself but also to other requests. 10 | max_list_size=50000 11 | max_set_size=50000 12 | max_map_size=50000 13 | max_btree_size=50000 14 | # 15 | # Max element bytes (default: 16KB, min: 1KB, max: 32KB) 16 | max_element_bytes=16KB 17 | # 18 | # Scrub count (default: 96, min: 16, max: 320) 19 | # Count of scrubbing items at each try. 20 | scrub_count=96 21 | 22 | # 23 | # Persistence configuration 24 | # 25 | # use persistence (true or false, default: false) 26 | use_persistence=false 27 | # 28 | # The path of the snapshot file (default: ARCUS-DB) 29 | data_path=ARCUS-DB 30 | # 31 | # The path of the command log file (default: ARCUS-DB) 32 | logs_path=ARCUS-DB 33 | # 34 | # asynchronous logging 35 | #async_logging=true 36 | # 37 | # checkpoint interval (unit: percentage, default: 100) 38 | # The ratio of the command log file size to the snapshot file size. 39 | # 100 means checkpoint if snapshot file size is 10GB, command log file size is 20GB or more 40 | #chkpt_interval_pct_snapshot=100 41 | # 42 | # checkpoint interval minimum file size (unit: MB, default: 256) 43 | #chkpt_interval_min_logsize=256 44 | -------------------------------------------------------------------------------- /t/issue_ee_599.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 8; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val; 14 | my $rst; 15 | my $size; 16 | my $stats; 17 | 18 | $size = 10; 19 | $cmd = "set key1 1 0 $size"; $val = "x"x$size; $rst = "STORED"; 20 | mem_cmd_is($sock, $cmd, $val, $rst); 21 | 22 | $size = 3; 23 | $cmd = "set key2 1 0 $size"; $val = "x"x$size; $rst = "STORED"; 24 | mem_cmd_is($sock, $cmd, $val, $rst); 25 | 26 | $size = 20; 27 | $cmd = "set key3 1 0 $size"; $val = "x"x$size; $rst = "STORED"; 28 | mem_cmd_is($sock, $cmd, $val, $rst); 29 | 30 | $size = 3; 31 | $cmd = "set key4 1 0 $size"; $val = "x"x$size; $rst = "STORED"; 32 | mem_cmd_is($sock, $cmd, $val, $rst); 33 | 34 | # make free space 35 | $cmd = "delete key1"; $rst = "DELETED"; 36 | mem_cmd_is($sock, $cmd, "", $rst); 37 | 38 | sleep(0.01); 39 | $stats = mem_stats($sock, "slabs"); 40 | is ($stats->{"SM:free_small_space"} != 0, 1,"$cmd confirm that free_small_space is not 0"); 41 | 42 | $cmd = "delete key3"; $rst = "DELETED"; 43 | mem_cmd_is($sock, $cmd, "", $rst); 44 | 45 | sleep(0.01); 46 | $stats = mem_stats($sock, "slabs"); 47 | # Previously, there was a phenomenon in 48 | # which free_small_space was calculated to be larger than 0 49 | is ($stats->{"SM:free_small_space"}, 0, "$cmd confirm free_small_space"); 50 | 51 | # after test 52 | release_memcached($engine, $server); 53 | -------------------------------------------------------------------------------- /HACKING: -------------------------------------------------------------------------------- 1 | * Hacking Memcached 2 | 3 | * Prerequisites 4 | 5 | - autoconf 6 | - automake 7 | - autotools 8 | - libevent 9 | 10 | * Getting Started 11 | 12 | After checking out a git repository, you must first run autogen.sh 13 | once in order to create the configure script. 14 | 15 | Next, run the configure script and start doing builds. 16 | 17 | * Setting up Git 18 | 19 | Though not required, there are a couple of things you can add to git 20 | to help development. 21 | 22 | ** Pre Commit Hook 23 | 24 | The pre-commit hook can be used to ensure that your tree passes tests 25 | before allowing a commit. To do so, add the following to 26 | .git/hooks/pre-commit (which must be executable): 27 | 28 | #!/bin/sh 29 | make test 30 | 31 | ** Post Commit Hook 32 | 33 | Because the version number changes on each commit, it's good to use a 34 | post commit hook to update the version number after each commit so as 35 | to keep the reporting accurate. To do so, add the following to 36 | .git/hooks/post-commit (which must be executable) 37 | 38 | #!/bin/sh 39 | ./version.sh 40 | 41 | ** Running memcached in gdb for tests. 42 | 43 | By default `make test` will spawn a memcached daemon for each test. 44 | This doesn't let you easily drop into gdb or run verbosely. 45 | 46 | If you export the environment variable 47 | T_MEMD_USE_DAEMON="127.0.0.1:11211" the tests will use an existing 48 | daemon at that address. 49 | 50 | * Sending patches 51 | 52 | See current instructions at http://contributing.appspot.com/memcached 53 | -------------------------------------------------------------------------------- /win32/defs.c: -------------------------------------------------------------------------------- 1 | /* dummy_defs.c 2 | * 3 | * Create blank UNIX function definitions to allow win32 builds. */ 4 | 5 | #include 6 | 7 | int lstat(const char *path, struct stat *tstat) { 8 | return -1; 9 | } 10 | 11 | int getrlimit(int __resource, struct rlimit *rlimits) { 12 | /* HACK ALERT: This function MUST BE called from main() before any * 13 | * network operation for Windows networking to work. Since the * 14 | * main() is calling getrlimit() that is NOT meaningful for * 15 | * Windows, this function is being used to invoke WSAStartup() * 16 | * below only once during the the first call to getrlimit() * 17 | */ 18 | static int onceonly = 0; 19 | WSADATA wsaData; 20 | if (!onceonly) { 21 | onceonly = 1; 22 | if (WSAStartup(MAKEWORD(2,0), &wsaData) != 0) { 23 | fprintf(stderr, "Socket Initialization Error. Program aborted\n"); 24 | exit(EXIT_FAILURE); 25 | } 26 | } 27 | rlimits->rlim_cur = 1; // Hack: just enough to allow main() to move forward. 28 | rlimits->rlim_max = 1; 29 | return 0; 30 | } 31 | 32 | int setrlimit(int __resource, struct rlimit *__rlimits) { 33 | return 0; 34 | } 35 | 36 | _uid_t getuid(void) { 37 | return -1; 38 | } 39 | _uid_t geteuid(void) { 40 | return -1; 41 | } 42 | 43 | struct passwd *getpwnam(const char *name) { 44 | return 0; 45 | } 46 | 47 | int setuid(_uid_t uid) { 48 | return -1; 49 | } 50 | 51 | int setgid(_uid_t gid) { 52 | return -1; 53 | } 54 | -------------------------------------------------------------------------------- /rfc1321/md5.h: -------------------------------------------------------------------------------- 1 | /* MD5.H - header file for MD5C.C 2 | */ 3 | 4 | /* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All 5 | rights reserved. 6 | 7 | License to copy and use this software is granted provided that it 8 | is identified as the "RSA Data Security, Inc. MD5 Message-Digest 9 | Algorithm" in all material mentioning or referencing this software 10 | or this function. 11 | 12 | License is also granted to make and use derivative works provided 13 | that such works are identified as "derived from the RSA Data 14 | Security, Inc. MD5 Message-Digest Algorithm" in all material 15 | mentioning or referencing the derived work. 16 | 17 | RSA Data Security, Inc. makes no representations concerning either 18 | the merchantability of this software or the suitability of this 19 | software for any particular purpose. It is provided "as is" 20 | without express or implied warranty of any kind. 21 | 22 | These notices must be retained in any copies of any part of this 23 | documentation and/or software. 24 | */ 25 | 26 | /* MD5 context. */ 27 | typedef struct { 28 | UINT4 state[4]; /* state (ABCD) */ 29 | UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */ 30 | unsigned char buffer[64]; /* input buffer */ 31 | } MD5_CTX; 32 | 33 | void MD5Init PROTO_LIST ((MD5_CTX *)); 34 | void MD5Update PROTO_LIST ((MD5_CTX *, unsigned char *, unsigned int)); 35 | void MD5Final PROTO_LIST ((unsigned char [16], MD5_CTX *)); 36 | -------------------------------------------------------------------------------- /t/issue_29.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 4; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $rst; 14 | my $msg; 15 | 16 | $cmd = "set issue29 0 0 0\r\n"; $rst = "STORED"; $msg = "stored issue29"; 17 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 18 | 19 | my $first_stats = mem_stats($sock, "slabs"); 20 | ### [ARCUS] CHANGED FOLLOWING TEST ### 21 | # Arcus uses small memory allocator. 22 | # So, the used chunk is the chunk of the small memory allocator. 23 | #my $first_used = $first_stats->{"1:used_chunks"}; 24 | 25 | #is(1, $first_used, "Used one"); 26 | ###################################### 27 | my $first_used = $first_stats->{"0:used_chunks"}; 28 | 29 | is(1, $first_used, "Used one chunk"); 30 | ###################################### 31 | 32 | $cmd = "set issue29_b 0 0 0\r\n"; $rst = "STORED"; $msg = "stored issue29_b"; 33 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 34 | 35 | my $second_stats = mem_stats($sock, "slabs"); 36 | ### [ARCUS] CHANGED FOLLOWING TEST ### 37 | # Arcus uses small memory allocator. 38 | #my $second_used = $second_stats->{"1:used_chunks"}; 39 | 40 | #is(2, $second_used, "Used two") 41 | ###################################### 42 | my $second_used = $second_stats->{"0:used_chunks"}; 43 | 44 | is(1, $second_used, "Used still one chunk"); 45 | ###################################### 46 | 47 | # after test 48 | release_memcached($engine, $server); 49 | -------------------------------------------------------------------------------- /engines/default/mem_pool.h: -------------------------------------------------------------------------------- 1 | /* 2 | * arcus-memcached - Arcus memory cache server 3 | * Copyright 2010-2014 NAVER Corp. 4 | * Copyright 2015-current JaM2in Co., Ltd. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef MEM_POOL_H 19 | #define MEM_POOL_H 20 | 21 | #include 22 | 23 | #ifdef ENABLE_LARGE_ITEM 24 | 25 | #define LARGE_POINTER_ARRAY_LENGTH 1024 // 16MB 26 | #define MAX_LARGE_POINTER_ARRAY_POOL 1000 27 | 28 | typedef struct { 29 | uint32_t pool_id; 30 | value_item **addnl; 31 | } large_pa; 32 | 33 | typedef struct { 34 | uint32_t used_cnt; 35 | uint32_t pool_size; 36 | large_pa *large_pa_pool; 37 | pthread_mutex_t large_pa_pool_lock; 38 | } large_pa_pool_t; 39 | 40 | /* mem pool functions */ 41 | void pointer_array_pool_init(void); 42 | void pointer_array_pool_final(void); 43 | void pointer_array_pool_alloc(large_pa *pa, uint32_t elem_count); 44 | void pointer_array_free(large_pa *pa); 45 | 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /t/64bit.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | $ENV{T_MEMD_INITIAL_MALLOC} = "4294967328"; # 2**32 + 32 , just over 4GB 10 | $ENV{T_MEMD_SLABS_ALLOC} = 0; # don't preallocate slabs 11 | 12 | my $engine = shift; 13 | my $server = get_memcached($engine, "-m 4098 -M"); 14 | my $sock = $server->sock; 15 | 16 | my ($stats, $slabs) = @_; 17 | 18 | $stats = mem_stats($sock); 19 | 20 | if ($stats->{'pointer_size'} eq "32") { 21 | plan skip_all => 'Skipping 64-bit tests on 32-bit build'; 22 | exit 0; 23 | } else { 24 | plan tests => 6; 25 | } 26 | 27 | is($stats->{'pointer_size'}, 64, "is 64 bit"); 28 | is($stats->{'limit_maxbytes'}, "4297064448", "max bytes is 4098 MB"); 29 | 30 | $slabs = mem_stats($sock, 'slabs'); 31 | is($slabs->{'total_malloced'}, "4294967328", "expected (faked) value of total_malloced"); 32 | is($slabs->{'active_slabs'}, 0, "no active slabs"); 33 | 34 | my $hit_limit = 0; 35 | ### [ARCUS] CHANGED FOLLOWING TEST ### 36 | # Arcus-memcached allowed more memory to be allocated. 37 | #for (1..5) { 38 | for (1..10) { 39 | ###################################### 40 | my $size = 400 * 1024; 41 | my $data = "a" x $size; 42 | print $sock "set big$_ 0 0 $size\r\n$data\r\n"; 43 | my $res = <$sock>; 44 | $hit_limit = 1 if $res ne "STORED\r\n"; 45 | } 46 | ok($hit_limit, "hit size limit"); 47 | 48 | $slabs = mem_stats($sock, 'slabs'); 49 | is($slabs->{'active_slabs'}, 1, "1 active slab"); 50 | 51 | # after test 52 | release_memcached($engine, $server); 53 | -------------------------------------------------------------------------------- /engines/default/cmdlogbuf.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | /* 3 | * arcus-memcached - Arcus memory cache server 4 | * Copyright 2019 JaM2in Co., Ltd. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef CMDLOGBUF_H 19 | #define CMDLOGBUF_H 20 | 21 | #include "cmdlogmgr.h" 22 | #include "cmdlogrec.h" 23 | 24 | #ifdef ENABLE_PERSISTENCE 25 | /* external log buffer functions */ 26 | void cmdlog_buff_write(LogRec *logrec, log_waiter_t *waiter, bool dual_write); 27 | void cmdlog_buff_flush_direct(LogSN *upto_lsn); 28 | void cmdlog_buff_flush_request(LogSN *upto_lsn); 29 | void cmdlog_buff_complete_dual_write(bool success); 30 | 31 | void cmdlog_get_write_lsn(LogSN *lsn); 32 | void cmdlog_get_flush_lsn(LogSN *lsn); 33 | 34 | ENGINE_ERROR_CODE cmdlog_buf_init(struct default_engine *engine); 35 | void cmdlog_buf_final(void); 36 | ENGINE_ERROR_CODE cmdlog_buf_flush_thread_start(void); 37 | void cmdlog_buf_flush_thread_stop(void); 38 | #endif 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /include/memcached/engine_testapp.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #ifndef MEMCACHED_ENGINE_TESTAPP_H 3 | #define MEMCACHED_ENGINE_TESTAPP_H 4 | 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | enum test_result { 12 | SUCCESS = 11, 13 | FAIL = 13, 14 | DIED = 14, 15 | CORE = 15, 16 | PENDING = 19 17 | }; 18 | 19 | struct test_harness { 20 | const char *engine_path; 21 | const char *default_engine_cfg; 22 | ENGINE_HANDLE_V1 *(*start_engine)(const char *, const char *, bool); 23 | void(*reload_engine)(ENGINE_HANDLE **, ENGINE_HANDLE_V1 **, const char *, const char *, bool); 24 | const void *(*create_cookie)(void); 25 | void (*destroy_cookie)(const void *cookie); 26 | void (*set_ewouldblock_handling)(const void *cookie, bool enable); 27 | void (*lock_cookie)(const void *cookie); 28 | void (*unlock_cookie)(const void *cookie); 29 | void (*waitfor_cookie)(const void *cookie); 30 | }; 31 | 32 | typedef struct test { 33 | const char *name; 34 | enum test_result(*tfun)(ENGINE_HANDLE *, ENGINE_HANDLE_V1 *); 35 | bool(*test_setup)(ENGINE_HANDLE *, ENGINE_HANDLE_V1 *); 36 | bool(*test_teardown)(ENGINE_HANDLE *, ENGINE_HANDLE_V1 *); 37 | const char *cfg; 38 | } engine_test_t; 39 | 40 | typedef engine_test_t* (*GET_TESTS)(void); 41 | 42 | typedef bool (*SETUP_SUITE)(struct test_harness *); 43 | 44 | typedef bool (*TEARDOWN_SUITE)(void); 45 | 46 | #ifdef __cplusplus 47 | } 48 | #endif 49 | 50 | #endif /* MEMCACHED_ENGINE_TESTAPP_H */ 51 | -------------------------------------------------------------------------------- /t/etc/too_many_eviction_big_work.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 3; 12 | my $running = 0; 13 | 14 | # default engine start option : -m 512 15 | # example) ./memcached -E .libs/default_engine.so -X .libs/ascii_scrub.so -m 512 16 | 17 | while ($running < $threads) { 18 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 19 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 20 | my $cpid = fork(); 21 | if ($cpid) { 22 | $running++; 23 | print "Launched $cpid. Running $running threads.\n"; 24 | } else { 25 | data_work($sock); 26 | exit 0; 27 | } 28 | } 29 | 30 | while ($running > 0) { 31 | wait(); 32 | print "stopped. Running $running threads.\n"; 33 | $running--; 34 | } 35 | 36 | sub data_work { 37 | my $sock = shift; 38 | my $i; 39 | my $expire = 86400; 40 | for ($i = 0; $i < 800; $i++) { 41 | my $keyrand = int(rand(900000000)); 42 | my $valrand = 7900; 43 | my $key = "dash$keyrand"; 44 | my $val = "B" x $valrand; 45 | my $len = length($val); 46 | sleep(0.01); 47 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 48 | my $res = scalar <$sock>; 49 | if ($res ne "STORED\r\n") { 50 | print "set $key $len: $res\r\n"; 51 | } 52 | if (($i % 100) == 99) { 53 | print "$i added\n"; 54 | } 55 | } 56 | print "data_work end\n"; 57 | } 58 | 59 | #undef $server; 60 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 2003, Danga Interactive, Inc. 2 | Copyright (c) 2010-2012, NHN Corp. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following disclaimer 14 | in the documentation and/or other materials provided with the 15 | distribution. 16 | 17 | * Neither the name of the Danga Interactive nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /engines/demo/dm_assoc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * arcus-memcached - Arcus memory cache server 3 | * Copyright 2016 JaM2in Co., Ltd. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #ifndef DM_ASSOC_H 18 | #define DM_ASSOC_H 19 | 20 | struct dm_assoc { 21 | uint32_t hashsize; /* hash table size */ 22 | uint32_t hashmask; /* hash bucket mask */ 23 | 24 | /* cache item hash table : an array of hash tables */ 25 | hash_item** hashtable; 26 | 27 | /* Number of items in the hash table. */ 28 | uint64_t hash_items; 29 | }; 30 | 31 | /* associative array */ 32 | ENGINE_ERROR_CODE dm_assoc_init(struct demo_engine *engine); 33 | void dm_assoc_final(struct demo_engine *engine); 34 | 35 | hash_item * dm_assoc_find(struct demo_engine *engine, uint32_t hash, 36 | const char *key, const size_t nkey); 37 | int dm_assoc_insert(struct demo_engine *engine, uint32_t hash, hash_item *item); 38 | void dm_assoc_delete(struct demo_engine *engine, uint32_t hash, 39 | const char *key, const size_t nkey); 40 | #endif 41 | -------------------------------------------------------------------------------- /LICENSE-memcached: -------------------------------------------------------------------------------- 1 | Copyright (c) 2003, Danga Interactive, Inc. 2 | Copyright (c) 2010-2012, NHN Corp. 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are 7 | met: 8 | 9 | * Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following disclaimer 14 | in the documentation and/or other materials provided with the 15 | distribution. 16 | 17 | * Neither the name of the Danga Interactive nor the names of its 18 | contributors may be used to endorse or promote products derived from 19 | this software without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | -------------------------------------------------------------------------------- /docs/install.md: -------------------------------------------------------------------------------- 1 | # Build & Install 2 | ## 패키지 설치 3 | ``` 4 | yum install gcc make which libtool (CentOS / Redhat) 5 | apt-get install build-essential libtool (Ubuntu) 6 | brew install autoconf automake libtool (OSX) 7 | ``` 8 | ## Source 가져오기 9 | ``` 10 | wget https://github.com/naver/arcus-memcached/releases/download//arcus-memcached-.tar.gz 11 | tar -zxvf arcus-memcached-.tar.gz 12 | cd arcus-memcached- 13 | ``` 14 | 또는 15 | ``` 16 | git clone https://github.com/naver/arcus-memcached.git 17 | cd arcus-memcached 18 | git switch -d 19 | ./config/autorun.sh 20 | ``` 21 | ## Compile 22 | [libevent](https://github.com/libevent/libevent), [arcus-zookeeper](https://github.com/naver/arcus-zookeeper) 설치 23 | ``` 24 | ./deps/install.sh 25 | ``` 26 | arcus-memcached 설치 27 | ``` 28 | ./configure 29 | make 30 | make install 31 | ``` 32 | `./configure` 수행 시 다음과 같은 option을 사용할 수 있습니다. 33 | - `--prefix=`: arcus-memcached가 설치될 경로 지정. (default=`/usr/local`) 34 | - `--with-libevent=`: libevent가 설치된 경로 지정 (default=`` 또는 `/usr/local`) 35 | - `--enable-zk-integration`: zookeeper based clustering 사용 36 | - `--enable-zk-reconfig`: zookeeper reconfig 기능 사용 37 | - `--with-zookeeper=`: arcus-zookeeper가 설치된 경로 지정 (default=`` 또는 `/usr/local`) 38 | 39 | # Test 40 | ``` 41 | yum install perl-core 42 | ``` 43 | unit test 44 | ``` 45 | make test 46 | ``` 47 | 특정 테스트만 수행 48 | ``` 49 | perl ./t/.t 50 | ``` 51 | 동시성 관련 문제(used port 등)로 테스트 실패하는 경우 52 | ```perl 53 | # run_test.pl 54 | my $opt = '--job 1'; # --job N : run N test jobs in parallel 55 | ``` 56 | -------------------------------------------------------------------------------- /t/readable_expiretime.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 10; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | =head 10 | get foo 11 | set foo 0 0 6 12 | fooval 13 | getattr foo expiretime 14 | delete foo 15 | 16 | get foo 17 | set foo 0 999 6 18 | fooval 19 | getattr foo expiretime 20 | delete foo 21 | =cut 22 | 23 | my $engine = shift; 24 | my $server = get_memcached($engine); 25 | my $sock = $server->sock; 26 | 27 | my $cmd; 28 | my $val; 29 | my $rst; 30 | 31 | # Case 1 32 | $cmd = "get foo"; $rst = "END"; 33 | mem_cmd_is($sock, $cmd, "", $rst); 34 | 35 | $cmd = "set foo 0 0 6"; $val = "fooval"; $rst = "STORED"; 36 | mem_cmd_is($sock, $cmd, $val, $rst); 37 | $cmd = "get foo"; 38 | $rst = "VALUE foo 0 6 39 | fooval 40 | END"; 41 | mem_cmd_is($sock, $cmd, "", $rst); 42 | 43 | $cmd = "getattr foo expiretime"; 44 | $rst = "ATTR expiretime=0 45 | END"; 46 | mem_cmd_is($sock, $cmd, "", $rst, "expiretime=0 ok"); 47 | 48 | $cmd = "delete foo"; $rst = "DELETED"; 49 | mem_cmd_is($sock, $cmd, "", $rst); 50 | 51 | # Case 2 52 | $cmd = "get foo"; $rst = "END"; 53 | mem_cmd_is($sock, $cmd, "", $rst); 54 | 55 | $cmd = "set foo 0 999 6"; $val = "fooval"; $rst = "STORED"; 56 | mem_cmd_is($sock, $cmd, $val, $rst); 57 | $cmd = "get foo"; 58 | $rst = "VALUE foo 0 6 59 | fooval 60 | END"; 61 | mem_cmd_is($sock, $cmd, "", $rst); 62 | 63 | $cmd = "getattr foo expiretime"; 64 | $rst = "ATTR expiretime=999 65 | END"; 66 | mem_cmd_is($sock, $cmd, "", $rst, "expiretime=999 ok"); 67 | 68 | $cmd = "delete foo"; $rst = "DELETED"; 69 | mem_cmd_is($sock, $cmd, "", $rst); 70 | 71 | # after test 72 | release_memcached($engine, $server); 73 | -------------------------------------------------------------------------------- /t/etc/too_many_eviction_w_load.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 128; 12 | my $running = 0; 13 | 14 | # default engine start option : -m 1024 15 | # example) ./memcached -E .libs/default_engine.so -X .libs/ascii_scrub.so -m 512 16 | 17 | while ($running < $threads) { 18 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 19 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 20 | my $cpid = fork(); 21 | if ($cpid) { 22 | $running++; 23 | print "Launched $cpid. Running $running threads.\n"; 24 | } else { 25 | data_load($sock); 26 | exit 0; 27 | } 28 | } 29 | 30 | while ($running > 0) { 31 | wait(); 32 | print "stopped. Running $running threads.\n"; 33 | $running--; 34 | } 35 | 36 | sub data_load { 37 | my $sock = shift; 38 | my $i; 39 | my $expire; 40 | for ($i = 0; $i < 1000000; $i++) { 41 | my $digit = 1 + int(rand(30)); 42 | my $power = $digit * $digit; 43 | my $keyrand = int(rand(9000000)); 44 | my $valrand = 10 + int(rand($power)); 45 | my $key = "dash$keyrand"; 46 | my $val = "B" x $valrand; 47 | my $len = length($val); 48 | my $res; 49 | $expire = 86400; 50 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 51 | $res = scalar <$sock>; 52 | if ($res ne "STORED\r\n") { 53 | print "set $key $len: $res\r\n"; 54 | } 55 | } 56 | print "data_load end\n"; 57 | } 58 | 59 | #undef $server; 60 | -------------------------------------------------------------------------------- /t/whitespace.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | use strict; 3 | use FindBin qw($Bin); 4 | our @files; 5 | 6 | BEGIN { 7 | chdir "$Bin/.." or die; 8 | 9 | my @exempted = qw(Makefile.am win32/Makefile.mingw m4/c99-backport.m4); 10 | push(@exempted, glob("*/Makefile.am")); 11 | push(@exempted, glob("Makefile.*")); 12 | push(@exempted, glob("ChangeLog*")); 13 | push(@exempted, glob("README.md*")); 14 | push(@exempted, glob("CONTRIBUTING.md*")); 15 | push(@exempted, glob("doc/*.xml")); 16 | push(@exempted, glob("doc/xml2rfc/*.xsl")); 17 | push(@exempted, glob("m4/*backport*m4")); 18 | push(@exempted, glob("deps/*.tar.gz")); 19 | my %exempted_hash = map { $_ => 1 } @exempted; 20 | 21 | my @stuff = split /\0/, `git ls-files -z -c -m -o --exclude-standard`; 22 | @files = grep { ! $exempted_hash{$_} } @stuff; 23 | 24 | # We won't find any files if git isn't installed. If git isn't 25 | # installed, they're probably not doing any useful development, or 26 | # at the very least am will clean up whitespace when we receive 27 | # their patch. 28 | unless (@files) { 29 | use Test::More; 30 | plan skip_all => "Skipping tests probably because you don't have git."; 31 | exit 0; 32 | } 33 | } 34 | 35 | use Test::More tests => scalar(@files); 36 | 37 | foreach my $f (@files) { 38 | open(my $fh, $f) or die "$f (failed file open)"; 39 | my $before = do { local $/; <$fh>; }; 40 | close ($fh); 41 | my $after = $before; 42 | $after =~ s/\t/ /g; 43 | $after =~ s/ +$//mg; 44 | $after .= "\n" unless $after =~ /\n$/; 45 | ok ($after eq $before, "$f (see devtools/clean-whitespace.pl)"); 46 | } 47 | -------------------------------------------------------------------------------- /doc/CONTRIBUTORS: -------------------------------------------------------------------------------- 1 | MEMCACHED CONTRIBUTORS 2 | 3 | This file contains a list of people who have contributed code and 4 | effort to the memcached project. If you don't see your name mentioned 5 | send email to the memcached mailing list so you can be immortalized. 6 | 7 | Also see the ChangeLog for even more people who have helped over the 8 | years by submitting fixes, patches and reporting bugs. 9 | 10 | 11 | Major authors: 12 | -------------- 13 | 14 | Brad Fitzpatrick -- maintainer, original implementations 15 | 16 | Anatoly Vorobey -- lots of the modern server code 17 | 18 | Steven Grimm -- iov writing (less CPU), UDP mode, 19 | non-2.0 slab mantissas, multithread, ... 20 | 21 | Other Contributors 22 | ------------------ 23 | 24 | Evan Martin 25 | Nathan Neulinger 26 | Eric Hodel 27 | Michael Johnson 28 | Paul Querna 29 | Jamie McCarthy 30 | Philip Neustrom 31 | Andrew O'Brien 32 | Josh Rotenberg 33 | Robin H. Johnson 34 | Tim Yardley 35 | Paolo Borelli 36 | Eli Bingham 37 | Jean-Francois Bustarret 38 | Paul G 39 | Paul Lindner 40 | Dormando 41 | Dustin Sallings 42 | Chris Goffinet 43 | Tomash Brechko 44 | Brian Aker 45 | Trond Norbye 46 | -------------------------------------------------------------------------------- /devtools/svn-tarballs.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use FindBin qw($Bin); 5 | 6 | my %branch = ( 7 | '1.2.x' => "http://code.sixapart.com/svn/memcached/trunk/server", 8 | '1.1.x' => "http://code.sixapart.com/svn/memcached/branches/memcached-1.1.x", 9 | ); 10 | 11 | foreach my $b (keys %branch) { 12 | chdir $Bin or die; 13 | my $url = $branch{$b}; 14 | my $out = `svn info $b`; 15 | unless ($out =~ /^URL: (.+)/m && $1 eq $url) { 16 | system("rm -rf $b"); 17 | system("svn", "co", $url, $b) 18 | and die "Failed to checkout $url\n"; 19 | } else { 20 | chdir "$Bin/$b" or die; 21 | system("svn up") and die "Failed to svn up"; 22 | } 23 | 24 | chdir "$Bin/$b" or die; 25 | $out = `svn info .`; 26 | 27 | my ($maxrev) = $out =~ /^Last Changed Rev: (\d+)/m 28 | or die "No max rev?"; 29 | 30 | print "$b = $maxrev\n"; 31 | my $distfile = "memcached-$b-svn$maxrev.tar.gz"; 32 | next if -f $distfile && -s _; 33 | 34 | open(my $fh, "configure.ac") or die "no configure.ac in $b?"; 35 | my $ac = do { local $/; <$fh>; }; 36 | close($fh); 37 | $ac =~ s!AC_INIT\(memcached,.+?\)!AC_INIT(memcached, $b-svn$maxrev, brad\@danga.com)! 38 | or die "Failed to replace"; 39 | open (my $fh, ">configure.ac") or die "failed to write configure.ac writeable: $!"; 40 | print $fh $ac; 41 | close ($fh); 42 | 43 | system("./autogen.sh") and die "Autogen failed. Missing autotools?"; 44 | system("./configure") and die "configure failed"; 45 | system("make dist") and die "make dist failed"; 46 | die "Failed to make dist $distfile." unless -s $distfile; 47 | } 48 | 49 | 50 | -------------------------------------------------------------------------------- /docs/administration/userlog.md: -------------------------------------------------------------------------------- 1 | # Userlog Logger Extension 2 | 3 | Userlog Logger Extension은 루트 권한 없이도 접근 가능한 파일 기반 로그 기록을 지원하는 확장 모듈이다. 4 | 5 | ## 실행 방식 6 | 7 | Userlog Logger 기능은 memcached 실행 시 extension 옵션(`-X`)을 지정하여 활성화할 수 있다. 8 | 9 | ```bash 10 | $INSTALL_PATH/bin/memcached -E $INSTALL_PATH/lib/default_engine.so \ 11 | -X $INSTALL_PATH/lib/userlog_logger.so 12 | ``` 13 | 14 | ## 로그 저장 및 관리 방식 15 | 16 | Userlog Logger의 저장 및 관리 방식은 다음과 같다. 17 | 18 | - **저장 경로** 19 | 20 | 로그 파일은 memcached를 실행한 위치를 기준으로 자동 생성되는 ARCUSlog 디렉토리에 저장된다. 21 | ```bash 22 | $PWD/ARCUSlog 23 | ``` 24 | 25 | - **로그 파일 이름 형식** 26 | 27 | ```bash 28 | arcus{index}_{YYYY_MM_DD} 29 | ``` 30 | - `index` : 0~4 사이 값을 가지는 로그 파일 인덱스 31 | - `YYYY_MM_DD` : 로그 파일 생성 날짜 32 | 33 | - **로그 파일 순환**: 34 | 35 | - 최대 5개(0~4)까지 로그 파일을 유지하며, 각 파일은 최대 20MB까지 저장한다. 36 | - 모든 파일이 용량 한도에 도달하면, 가장 오래된 파일을 삭제하고 해당 이름으로 새 로그 파일을 생성한다. 37 | 38 | ## 환경 변수 설정 39 | 40 | `userlog_logger` 기능은 다음 환경 변수를 통해 로그 출력 동작을 제어할 수 있다. 41 | 42 | 1. `UserLogRateLimitInterval` 43 | 44 | 일정 시간 동안 기록되는 로그 개수를 제한하는 간격(초) 45 | > ※ 이 값을 0으로 설정하면 로그 제한 기능이 비활성화되어, 개수 제한 없이 로그가 기록된다. 46 | - **기본값**: 5초 47 | - **최대값**: 60초 48 | ```bash 49 | export UserLogRateLimitInterval=10 50 | ``` 51 | 52 | 2. `UserLogRateLimitBurst` 53 | 54 | `UserLogRateLimitInterval` 내에 허용되는 최대 로그 개수 55 | - **기본값**: 200개 56 | - **최대값**: 50,000개 57 | ```bash 58 | export UserLogRateLimitBurst=1000 59 | ``` 60 | 61 | 3. `UserLogReduction` 62 | 63 | 동일한 로그 메시지가 반복될 경우 하나로 압축해 출력하는 기능 64 | - 연속된 동일 메시지는 1회만 출력하며, 반복 종료 시 반복 횟수를 함께 출력 65 | - **기본값**: false 66 | ```bash 67 | export UserLogReduction=on 68 | ``` 69 | -------------------------------------------------------------------------------- /scripts/memcached.sysv: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # chkconfig: - 55 45 4 | # description: The memcached daemon is a network memory cache service. 5 | # processname: memcached 6 | # config: /etc/sysconfig/memcached 7 | 8 | # Source function library. 9 | . /etc/rc.d/init.d/functions 10 | 11 | PORT=11211 12 | USER=nobody 13 | MAXCONN=1024 14 | CACHESIZE=64 15 | OPTIONS="" 16 | 17 | if [ -f /etc/sysconfig/memcached ];then 18 | . /etc/sysconfig/memcached 19 | fi 20 | 21 | # Check that networking is up. 22 | if [ "$NETWORKING" = "no" ] 23 | then 24 | exit 0 25 | fi 26 | 27 | RETVAL=0 28 | prog="memcached" 29 | 30 | start () { 31 | echo -n $"Starting $prog: " 32 | # insure that /var/run/memcached has proper permissions 33 | chown $USER /var/run/memcached 34 | daemon memcached -d -p $PORT -u $USER -m $CACHESIZE -c $MAXCONN -P /var/run/memcached/memcached.pid $OPTIONS 35 | RETVAL=$? 36 | echo 37 | [ $RETVAL -eq 0 ] && touch /var/lock/subsys/memcached 38 | } 39 | stop () { 40 | echo -n $"Stopping $prog: " 41 | killproc memcached 42 | RETVAL=$? 43 | echo 44 | if [ $RETVAL -eq 0 ] ; then 45 | rm -f /var/lock/subsys/memcached 46 | rm -f /var/run/memcached.pid 47 | fi 48 | } 49 | 50 | restart () { 51 | stop 52 | start 53 | } 54 | 55 | 56 | # See how we were called. 57 | case "$1" in 58 | start) 59 | start 60 | ;; 61 | stop) 62 | stop 63 | ;; 64 | status) 65 | status memcached 66 | ;; 67 | restart|reload) 68 | restart 69 | ;; 70 | condrestart) 71 | [ -f /var/lock/subsys/memcached ] && restart || : 72 | ;; 73 | *) 74 | echo $"Usage: $0 {start|stop|status|restart|reload|condrestart}" 75 | exit 1 76 | esac 77 | 78 | exit $? 79 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | Ideally, you want to make a static binary, otherwise the dynamic 2 | linker pollutes your address space with shared libs right in the 3 | middle. (NOTE: actually, this shouldn't matter so much anymore, now 4 | that we only allocate huge, fixed-size slabs) 5 | 6 | Make sure your libevent has epoll (Linux) or kqueue (BSD) support. 7 | Using poll or select only is slow, and works for testing, but 8 | shouldn't be used for high-traffic memcache installations. 9 | 10 | To build libevent with epoll on Linux, you need two things. First, 11 | you need /usr/include/sys/epoll.h . To get it, you can install the 12 | userspace epoll library, epoll-lib. The link to the latest version 13 | is buried inside 14 | http://www.xmailserver.org/linux-patches/nio-improve.html ; currently 15 | it's http://www.xmailserver.org/linux-patches/epoll-lib-0.9.tar.gz . 16 | If you're having any trouble building/installing it, you can just copy 17 | epoll.h from that tarball to /usr/include/sys as that's the only thing 18 | from there that libevent really needs. 19 | 20 | Secondly, you need to declare syscall numbers of epoll syscalls, so 21 | libevent can use them. Put these declarations somewhere 22 | inside : 23 | 24 | #define __NR_epoll_create 254 25 | #define __NR_epoll_ctl 255 26 | #define __NR_epoll_wait 256 27 | 28 | After this you should be able to build libevent with epoll support. 29 | Once you build/install libevent, you don't need to 30 | compile memcache or link it against libevent. Don't forget that for epoll 31 | support to actually work at runtime you need to use a kernel with epoll 32 | support patch applied, as explained in the README file. 33 | 34 | BSD users are luckier, and will get kqueue support by default. 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /cluster_config.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | /* 3 | * arcus-memcached - Arcus memory cache server 4 | * Copyright 2010-2014 NAVER Corp. 5 | * Copyright 2015 JaM2in Co., Ltd. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | #ifndef MEMCACHED_CLUSTER_CONFIG_H 20 | #define MEMCACHED_CLUSTER_CONFIG_H 21 | 22 | #include "memcached/extension_loggers.h" 23 | 24 | struct cluster_config; 25 | 26 | struct cluster_config *cluster_config_init(const char *node_name, 27 | EXTENSION_LOGGER_DESCRIPTOR *logger, 28 | int verbose); 29 | void cluster_config_final(struct cluster_config *config); 30 | 31 | int cluster_config_reconfigure(struct cluster_config *config, 32 | char **node_strs, uint32_t num_nodes, 33 | int *num_added, int *num_removed); 34 | int cluster_config_get_self_id(struct cluster_config *config); 35 | int cluster_config_key_is_mine(struct cluster_config *config, 36 | const char *key, uint32_t nkey, bool *mine, 37 | uint32_t *key_id, uint32_t *self_id); 38 | #endif 39 | -------------------------------------------------------------------------------- /arcus_hb.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | /* 3 | * arcus-memcached - Arcus memory cache server 4 | * Copyright 2010-2014 NAVER Corp. 5 | * Copyright 2015-2021 JaM2in Co., Ltd. 6 | * 7 | * Licensed under the Apache License, Version 2.0 (the "License"); 8 | * you may not use this file except in compliance with the License. 9 | * You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, software 14 | * distributed under the License is distributed on an "AS IS" BASIS, 15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | * See the License for the specific language governing permissions and 17 | * limitations under the License. 18 | */ 19 | #ifndef _ARCUS_HB_ 20 | #define _ARCUS_HB_ 21 | 22 | #include "memcached/extension_loggers.h" 23 | 24 | #ifdef ENABLE_ZK_INTEGRATION 25 | typedef struct { 26 | uint64_t count; /* mc heartbeat accumulated count */ 27 | uint64_t latency; /* mc heartbeat accumulated latency (unit: ms) */ 28 | } arcus_hb_stats; 29 | 30 | typedef struct { 31 | uint32_t timeout; /* mc heartbeat timeout (unit: ms) */ 32 | uint32_t failstop; /* mc heartbeat failstop (unit: ms) */ 33 | } arcus_hb_confs; 34 | 35 | int arcus_hb_init(int port, EXTENSION_LOGGER_DESCRIPTOR *logger, 36 | void (*cb_shutdown_server)(void)); 37 | void arcus_hb_final(void); 38 | 39 | int arcus_hb_get_timeout(void); 40 | int arcus_hb_set_timeout(int timeout); 41 | int arcus_hb_get_failstop(void); 42 | int arcus_hb_set_failstop(int failstop); 43 | 44 | void arcus_hb_get_stats(arcus_hb_stats *stats); 45 | void arcus_hb_get_confs(arcus_hb_confs *confs); 46 | #endif 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /t/issue_3.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 11; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val; 14 | my $rst; 15 | my $msg; 16 | my $key = "del_key"; 17 | 18 | $cmd = "delete $key"; $rst = "NOT_FOUND"; 19 | mem_cmd_is($sock, $cmd, "", $rst); 20 | 21 | $cmd = "delete $key 10"; $rst = "CLIENT_ERROR bad command line format. Usage: delete [noreply]"; 22 | mem_cmd_is($sock, $cmd, "", $rst); 23 | 24 | $cmd = "add $key 0 0 1"; $val = "x"; $rst = "STORED"; $msg = "Add before a broken delete."; 25 | mem_cmd_is($sock, $cmd, $val, $rst, $msg); 26 | 27 | $cmd = "delete $key 10 noreply"; $rst = ""; 28 | mem_cmd_is($sock, $cmd, "", $rst); 29 | # Does not reply 30 | # is (scalar <$sock>, "ERROR\r\n", "Even more invalid delete"); 31 | 32 | $cmd = "add $key 0 0 1"; $val = "x"; $rst = "NOT_STORED"; 33 | $msg = "Failed to add after failed silent delete."; 34 | mem_cmd_is($sock, $cmd, $val, $rst, $msg); 35 | 36 | $cmd = "delete $key noreply"; $rst = ""; 37 | mem_cmd_is($sock, $cmd, "", $rst); 38 | # Will not reply, so let's do a set and check that. 39 | 40 | $cmd = "set $key 0 0 1"; $val = "x"; $rst = "STORED"; 41 | mem_cmd_is($sock, $cmd, $val, $rst); 42 | 43 | $cmd = "delete $key"; $rst = "DELETED"; 44 | mem_cmd_is($sock, $cmd, "", $rst); 45 | 46 | $cmd = "set $key 0 0 1"; $val = "x"; $rst = "STORED"; 47 | mem_cmd_is($sock, $cmd, $val, $rst); 48 | 49 | $cmd = "delete $key noreply"; $rst = ""; 50 | mem_cmd_is($sock, $cmd, "", $rst); 51 | 52 | # will not reply, but a subsequent add will succeed 53 | 54 | $cmd = "add $key 0 0 1"; $val = "x"; $rst = "STORED"; 55 | mem_cmd_is($sock, $cmd, $val, $rst); 56 | 57 | # after test 58 | release_memcached($engine, $server); 59 | -------------------------------------------------------------------------------- /stdin_check.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #include 3 | #include 4 | #include 5 | 6 | #include "stdin_check.h" 7 | 8 | union c99hack { 9 | void *pointer; 10 | void (*exit_function)(void); 11 | }; 12 | 13 | static void* check_stdin_thread(void* arg) 14 | { 15 | pthread_detach(pthread_self()); 16 | 17 | while (!feof(stdin)) { 18 | getc(stdin); 19 | } 20 | 21 | fprintf(stderr, "EOF on stdin. Exiting\n"); 22 | union c99hack ch = { .pointer = arg }; 23 | ch.exit_function(); 24 | /* NOTREACHED */ 25 | return NULL; 26 | } 27 | 28 | static const char *get_name(void) { 29 | return "stdin_check"; 30 | } 31 | 32 | static EXTENSION_DAEMON_DESCRIPTOR descriptor = { 33 | .get_name = get_name 34 | }; 35 | 36 | #if defined (__SUNPRO_C) && (__SUNPRO_C >= 0x550) 37 | __global 38 | #elif defined __GNUC__ 39 | __attribute__ ((visibility("default"))) 40 | #endif 41 | EXTENSION_ERROR_CODE memcached_extensions_initialize(const char *config, 42 | GET_SERVER_API get_server_api) { 43 | 44 | SERVER_HANDLE_V1 *server = get_server_api(); 45 | if (server == NULL) { 46 | return EXTENSION_FATAL; 47 | } 48 | 49 | if (!server->extension->register_extension(EXTENSION_DAEMON, &descriptor)) { 50 | return EXTENSION_FATAL; 51 | } 52 | 53 | union c99hack ch = { .exit_function = server->core->shutdown }; 54 | 55 | pthread_t t; 56 | if (pthread_create(&t, NULL, check_stdin_thread, ch.pointer) != 0) { 57 | perror("couldn't create stdin checking thread."); 58 | server->extension->unregister_extension(EXTENSION_DAEMON, &descriptor); 59 | return EXTENSION_FATAL; 60 | } 61 | 62 | return EXTENSION_SUCCESS; 63 | } 64 | -------------------------------------------------------------------------------- /win32/dlfcn.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | * Keep track if the user tried to call dlopen(NULL, xx) to be able to give a sane 9 | * error message 10 | */ 11 | static bool self = false; 12 | 13 | void* dlopen(const char* path, int mode) { 14 | if (path == NULL) { 15 | // We don't support opening ourself 16 | self = true; 17 | return NULL; 18 | } 19 | 20 | void* handle = LoadLibrary(path); 21 | if (handle == NULL) { 22 | char *buf = malloc(strlen(path) + 20); 23 | sprintf(buf, "%s.dll", path); 24 | handle = LoadLibrary(buf); 25 | free(buf); 26 | } 27 | 28 | return handle; 29 | } 30 | 31 | void* dlsym(void* handle, const char* symbol) { 32 | return GetProcAddress(handle, symbol); 33 | } 34 | 35 | int dlclose(void* handle) { 36 | // dlclose returns zero on success. 37 | // FreeLibrary returns nonzero on success. 38 | return FreeLibrary(handle) != 0; 39 | } 40 | 41 | static char dlerror_buf[200]; 42 | 43 | const char *dlerror(void) { 44 | if (self) { 45 | return "not supported"; 46 | } 47 | 48 | DWORD err = GetLastError(); 49 | LPVOID error_msg; 50 | if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 51 | FORMAT_MESSAGE_FROM_SYSTEM | 52 | FORMAT_MESSAGE_IGNORE_INSERTS, 53 | NULL, err, 0, (LPTSTR)&error_msg, 0, NULL) != 0) { 54 | strncpy(dlerror_buf, error_msg, sizeof(dlerror_buf)); 55 | dlerror_buf[sizeof(dlerror_buf) - 1] = '\0'; 56 | LocalFree(error_msg); 57 | } else { 58 | return "Failed to get error message"; 59 | } 60 | 61 | return dlerror_buf; 62 | } 63 | -------------------------------------------------------------------------------- /devtools/bench_noreply.pl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/perl 2 | # 3 | use warnings; 4 | use strict; 5 | 6 | use IO::Socket::INET; 7 | 8 | use FindBin; 9 | 10 | @ARGV == 1 or @ARGV == 2 11 | or die "Usage: $FindBin::Script HOST:PORT [COUNT]\n"; 12 | 13 | # Note that it's better to run the test over the wire, because for 14 | # localhost the task may become CPU bound. 15 | my $addr = $ARGV[0]; 16 | my $count = $ARGV[1] || 10_000; 17 | 18 | my $sock = IO::Socket::INET->new(PeerAddr => $addr, 19 | Timeout => 3); 20 | die "$!\n" unless $sock; 21 | 22 | 23 | # By running 'noreply' test first we also ensure there are no reply 24 | # packets left in the network. 25 | foreach my $noreply (1, 0) { 26 | use Time::HiRes qw(gettimeofday tv_interval); 27 | 28 | print "'noreply' is ", $noreply ? "enabled" : "disabled", ":\n"; 29 | my $param = $noreply ? 'noreply' : ''; 30 | my $start = [gettimeofday]; 31 | foreach (1 .. $count) { 32 | print $sock "add foo 0 0 1 $param\r\n1\r\n"; 33 | scalar<$sock> unless $noreply; 34 | print $sock "set foo 0 0 1 $param\r\n1\r\n"; 35 | scalar<$sock> unless $noreply; 36 | print $sock "replace foo 0 0 1 $param\r\n1\r\n"; 37 | scalar<$sock> unless $noreply; 38 | print $sock "append foo 0 0 1 $param\r\n1\r\n"; 39 | scalar<$sock> unless $noreply; 40 | print $sock "prepend foo 0 0 1 $param\r\n1\r\n"; 41 | scalar<$sock> unless $noreply; 42 | print $sock "incr foo 1 $param\r\n"; 43 | scalar<$sock> unless $noreply; 44 | print $sock "decr foo 1 $param\r\n"; 45 | scalar<$sock> unless $noreply; 46 | print $sock "delete foo $param\r\n"; 47 | scalar<$sock> unless $noreply; 48 | } 49 | my $end = [gettimeofday]; 50 | printf("update commands: %.2f secs\n\n", tv_interval($start, $end)); 51 | } 52 | -------------------------------------------------------------------------------- /t/etc/too_many_eviction_s_fast.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 128; 12 | my $running = 0; 13 | 14 | # default engine start option : -m 1024 15 | # example) ./memcached -E .libs/default_engine.so -X .libs/ascii_scrub.so -m 512 16 | 17 | while ($running < $threads) { 18 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 19 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 20 | my $cpid = fork(); 21 | if ($cpid) { 22 | $running++; 23 | print "Launched $cpid. Running $running threads.\n"; 24 | } else { 25 | data_work($sock); 26 | exit 0; 27 | } 28 | } 29 | 30 | while ($running > 0) { 31 | wait(); 32 | print "stopped. Running $running threads.\n"; 33 | $running--; 34 | } 35 | 36 | sub data_work { 37 | my $sock = shift; 38 | my $i; 39 | my $expire; 40 | for ($i = 0; $i < 50000000; $i++) { 41 | my $keyrand = int(rand(90000000)); 42 | my $valrand = 30 + int(rand(30)); 43 | my $key = "dash$keyrand"; 44 | my $val = "B" x $valrand; 45 | my $len = length($val); 46 | my $res; 47 | my $meth = int(rand(10)); 48 | if (($meth ge 0) and ($meth le 7)) { 49 | $expire = 86400; 50 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 51 | $res = scalar <$sock>; 52 | if ($res ne "STORED\r\n") { 53 | print "set $key $len: $res\r\n"; 54 | } 55 | } else { 56 | print $sock "get $key\r\n"; 57 | $res = scalar <$sock>; 58 | if ($res =~ /^VALUE/) { 59 | $res .= scalar(<$sock>) . scalar(<$sock>); 60 | } 61 | } 62 | } 63 | print "data_work end\n"; 64 | } 65 | 66 | #undef $server; 67 | -------------------------------------------------------------------------------- /config/version.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # If you think this is stupid/overkill, blame dormando 3 | 4 | use warnings; 5 | use strict; 6 | 7 | my $version = `git describe`; 8 | chomp $version; 9 | # Test the various versions. 10 | #my $version = 'foob'; 11 | #my $version = '1.4.2-30-gf966dba'; 12 | #my $version = '1.4.3-rc1'; 13 | #my $version = '1.4.3'; 14 | my $default_version = '1.15.0-unknown'; 15 | 16 | unless ($version =~ m/^\d+\.\d+\.\d+/) { 17 | write_file('m4/version.m4', "m4_define([VERSION_NUMBER], [$default_version])\n"); 18 | exit; 19 | } 20 | 21 | my @version_tokens = split /-/, $version; 22 | if (scalar @version_tokens > 2) { 23 | # discard commit number 24 | pop(@version_tokens); 25 | } 26 | $version = join('-', @version_tokens); 27 | 28 | write_file('m4/version.m4', "m4_define([VERSION_NUMBER], [$version])\n"); 29 | my ($VERSION, $FULLVERSION, $RELEASE); 30 | 31 | if ($version =~ m/^(\d+\.\d+\.\d+)_rc(\d+)$/) { 32 | $VERSION = $1; 33 | $FULLVERSION = $version; 34 | $RELEASE = '0.1.rc' . $2; 35 | } elsif ($version =~ m/^(\d+\.\d+\.\d+)-(.+)$/) { 36 | $VERSION = $1; 37 | $FULLVERSION = $version; 38 | $RELEASE = '1.' . $2; 39 | } elsif ($version =~ m/^(\d+\.\d+\.\d+)$/) { 40 | $VERSION = $1; 41 | $FULLVERSION = $version; 42 | $RELEASE = '1'; 43 | } 44 | 45 | my $spec = read_file('memcached.spec.in'); 46 | $spec =~ s/\@VERSION\@/$VERSION/gm; 47 | $spec =~ s/\@FULLVERSION\@/$FULLVERSION/gm; 48 | $spec =~ s/\@RELEASE\@/$RELEASE/gm; 49 | 50 | write_file('memcached.spec', $spec); 51 | 52 | sub write_file { 53 | my $file = shift; 54 | my $data = shift; 55 | open(my $fh, "> $file") or die "Can't open $file: $!"; 56 | print $fh $data; 57 | close($fh); 58 | } 59 | 60 | sub read_file { 61 | my $file = shift; 62 | local $/ = undef; 63 | open(my $fh, "< $file") or die "Can't open $file: $!"; 64 | my $data = <$fh>; 65 | close($fh); 66 | return $data; 67 | } 68 | -------------------------------------------------------------------------------- /t/etc/too_many_eviction_s_slow.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 12; 12 | my $running = 0; 13 | 14 | # default engine start option : -m 1024 15 | # example) ./memcached -E .libs/default_engine.so -X .libs/ascii_scrub.so -m 512 16 | 17 | while ($running < $threads) { 18 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 19 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 20 | my $cpid = fork(); 21 | if ($cpid) { 22 | $running++; 23 | print "Launched $cpid. Running $running threads.\n"; 24 | } else { 25 | data_work($sock); 26 | exit 0; 27 | } 28 | } 29 | 30 | while ($running > 0) { 31 | wait(); 32 | print "stopped. Running $running threads.\n"; 33 | $running--; 34 | } 35 | 36 | sub data_work { 37 | my $sock = shift; 38 | my $i; 39 | my $expire; 40 | for ($i = 0; $i < 50000000; $i++) { 41 | my $keyrand = int(rand(90000000)); 42 | my $valrand = 30 + int(rand(30)); 43 | my $key = "dash$keyrand"; 44 | my $val = "B" x $valrand; 45 | my $len = length($val); 46 | my $res; 47 | sleep(0.01); 48 | my $meth = int(rand(10)); 49 | if (($meth ge 0) and ($meth le 5)) { 50 | $expire = 86400; 51 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 52 | $res = scalar <$sock>; 53 | if ($res ne "STORED\r\n") { 54 | print "set $key $len: $res\r\n"; 55 | } 56 | } else { 57 | print $sock "get $key\r\n"; 58 | $res = scalar <$sock>; 59 | if ($res =~ /^VALUE/) { 60 | $res .= scalar(<$sock>) . scalar(<$sock>); 61 | } 62 | } 63 | } 64 | print "data_work end\n"; 65 | } 66 | 67 | #undef $server; 68 | -------------------------------------------------------------------------------- /t/flush-all.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 14; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $expire; 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | my $msg; 17 | 18 | $cmd = "set foo 0 0 6"; $val = "fooval"; $rst = "STORED"; 19 | mem_cmd_is($sock, $cmd, $val, $rst); 20 | 21 | $cmd = "get foo"; 22 | $rst = "VALUE foo 0 6 23 | fooval 24 | END"; 25 | mem_cmd_is($sock, $cmd, "", $rst); 26 | $cmd = "flush_all"; $rst = "OK"; $msg = "did flush_all"; 27 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 28 | $cmd = "get foo"; $rst = "END"; 29 | mem_cmd_is($sock, $cmd, "", $rst); 30 | 31 | # Test flush_all with zero delay. 32 | $cmd = "set foo 0 0 6"; $val = "fooval"; $rst = "STORED"; 33 | mem_cmd_is($sock, $cmd, $val, $rst); 34 | 35 | $cmd = "get foo"; 36 | $rst = "VALUE foo 0 6 37 | fooval 38 | END"; 39 | mem_cmd_is($sock, $cmd, "", $rst); 40 | $cmd = "flush_all 0"; $rst = "OK"; $msg = "did flush_all"; 41 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 42 | $cmd = "get foo"; $rst = "END"; 43 | mem_cmd_is($sock, $cmd, "", $rst); 44 | 45 | # check that flush_all doesn't blow away items that immediately get set 46 | $cmd = "set foo 0 0 3"; $val = "new"; $rst = "STORED"; 47 | mem_cmd_is($sock, $cmd, $val, $rst); 48 | $cmd = "get foo"; 49 | $rst = "VALUE foo 0 3 50 | new 51 | END"; 52 | mem_cmd_is($sock, $cmd, "", $rst); 53 | 54 | # and the other form, specifying a flush_all time... 55 | my $expire = time() + 2; 56 | $cmd = "flush_all $expire"; $rst = "OK"; $msg = "did flush_all in future"; 57 | mem_cmd_is($sock, $cmd, "", $rst); 58 | $cmd = "set foo 0 0 4"; $val = "1234"; $rst = "STORED"; 59 | mem_cmd_is($sock, $cmd, $val, $rst); 60 | $cmd = "get foo"; 61 | $rst = "VALUE foo 0 4 62 | 1234 63 | END"; 64 | mem_cmd_is($sock, $cmd, "", $rst); 65 | sleep(2.2); 66 | $cmd = "get foo"; $rst = "END"; 67 | mem_cmd_is($sock, $cmd, "", $rst); 68 | 69 | # after test 70 | release_memcached($engine, $server); 71 | -------------------------------------------------------------------------------- /t/coll_sop_segfault_p012611.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 20; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | 17 | # SOP test sub routines 18 | sub sop_insert { 19 | my ($key, $from, $to, $create) = @_; 20 | my $index; 21 | my $vleng; 22 | 23 | for ($index = $from; $index <= $to; $index++) { 24 | $val = "datum$index"; 25 | $vleng = length($val); 26 | if ($index == $from) { 27 | $cmd = "sop insert $key $vleng $create"; 28 | $rst = "CREATED_STORED"; 29 | } else { 30 | $cmd = "sop insert $key $vleng"; 31 | $rst = "STORED"; 32 | } 33 | mem_cmd_is($sock, $cmd, $val, $rst); 34 | } 35 | } 36 | 37 | # testSOPSegFault : Basic 38 | $cmd = "get skey"; $rst = "END"; 39 | mem_cmd_is($sock, $cmd, "", $rst); 40 | 41 | sop_insert("skey", 0, 9, "create 13 0 0"); 42 | sop_get_is($sock, "skey 0", 13, 10, 43 | "datum0,datum1,datum2,datum3,datum4,datum5,datum6,datum7,datum8,datum9"); 44 | 45 | $cmd = "sop delete skey 6"; $val="datum1"; $rst = "DELETED"; 46 | mem_cmd_is($sock, $cmd, $val, $rst); 47 | $cmd = "sop delete skey 6"; $val="datum3"; $rst = "DELETED"; 48 | mem_cmd_is($sock, $cmd, $val, $rst); 49 | $cmd = "sop delete skey 6"; $val="datum5"; $rst = "DELETED"; 50 | mem_cmd_is($sock, $cmd, $val, $rst); 51 | $cmd = "sop delete skey 6"; $val="datum7"; $rst = "DELETED"; 52 | mem_cmd_is($sock, $cmd, $val, $rst); 53 | $cmd = "sop delete skey 6"; $val="datum9"; $rst = "DELETED"; 54 | mem_cmd_is($sock, $cmd, $val, $rst); 55 | sop_get_is($sock, "skey 0", 13, 5, 56 | "datum0,datum2,datum4,datum6,datum8"); 57 | 58 | $cmd = "delete skey"; $rst = "DELETED"; 59 | mem_cmd_is($sock, $cmd, "", $rst); 60 | $cmd = "get skey"; $rst = "END"; 61 | mem_cmd_is($sock, $cmd, "", $rst); 62 | 63 | # after test 64 | release_memcached($engine, $server); 65 | -------------------------------------------------------------------------------- /engines/default/chkpt_snapshot.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | /* 3 | * arcus-memcached - Arcus memory cache server 4 | * Copyright 2019 JaM2in Co., Ltd. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef CHKPT_SNAPSHOT_H 19 | #define CHKPT_SNAPSHOT_H 20 | 21 | #ifdef ENABLE_PERSISTENCE 22 | enum chkpt_snapshot_mode { 23 | CHKPT_SNAPSHOT_MODE_KEY = 0, 24 | CHKPT_SNAPSHOT_MODE_DATA, 25 | CHKPT_SNAPSHOT_MODE_CHKPT, 26 | CHKPT_SNAPSHOT_MODE_MAX 27 | }; 28 | 29 | typedef void (*CB_SNAPSHOT_DONE)(void*); 30 | 31 | ENGINE_ERROR_CODE chkpt_snapshot_init(void *engine_ptr); 32 | void chkpt_snapshot_final(void); 33 | 34 | ENGINE_ERROR_CODE chkpt_snapshot_direct(enum chkpt_snapshot_mode mode, 35 | const char *prefix, const int nprefix, 36 | const char *filepath, size_t *filesize); 37 | 38 | ENGINE_ERROR_CODE chkpt_snapshot_start(enum chkpt_snapshot_mode mode, 39 | const char *prefix, const int nprefix, 40 | const char *filepath, 41 | CB_SNAPSHOT_DONE callback); 42 | void chkpt_snapshot_stop(void); 43 | void chkpt_snapshot_stats(ADD_STAT add_stat, const void *cookie); 44 | 45 | int chkpt_snapshot_check_file_validity(const int fd, size_t *filesize); 46 | int chkpt_snapshot_file_apply(const char *filepath); 47 | #endif 48 | 49 | #endif 50 | 51 | -------------------------------------------------------------------------------- /t/etc/too_many_eviction_w_work.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 128; 12 | my $running = 0; 13 | 14 | # default engine start option : -m 1024 15 | # example) ./memcached -E .libs/default_engine.so -X .libs/ascii_scrub.so -m 512 16 | 17 | while ($running < $threads) { 18 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 19 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 20 | my $cpid = fork(); 21 | if ($cpid) { 22 | $running++; 23 | print "Launched $cpid. Running $running threads.\n"; 24 | } else { 25 | data_work($sock); 26 | exit 0; 27 | } 28 | } 29 | 30 | while ($running > 0) { 31 | wait(); 32 | print "stopped. Running $running threads.\n"; 33 | $running--; 34 | } 35 | 36 | sub data_work { 37 | my $sock = shift; 38 | my $i; 39 | my $expire; 40 | for ($i = 0; $i < 1000000; $i++) { 41 | my $digit = 1 + int(rand(30)); 42 | my $power = $digit * $digit; 43 | my $keyrand = int(rand(900000000)); 44 | my $valrand = 10 + int(rand($power)); 45 | my $key = "dash$keyrand"; 46 | my $val = "B" x $valrand; 47 | my $len = length($val); 48 | my $res; 49 | my $ratio = int(rand(100)); 50 | sleep(0.1); 51 | if (($ratio ge 0) and ($ratio le 9)) { 52 | $expire = 86400; 53 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 54 | $res = scalar <$sock>; 55 | if ($res ne "STORED\r\n") { 56 | print "set $key $len: $res\r\n"; 57 | } 58 | } else { 59 | print $sock "get $key\r\n"; 60 | $res = scalar <$sock>; 61 | if ($res =~ /^VALUE/) { 62 | $res .= scalar(<$sock>) . scalar(<$sock>); 63 | } 64 | } 65 | } 66 | print "data_work end\n"; 67 | } 68 | 69 | #undef $server; 70 | -------------------------------------------------------------------------------- /include/memcached/mock_server.h: -------------------------------------------------------------------------------- 1 | #ifndef MEMCACHED_MOCK_SERVER_H 2 | #define MEMCACHED_MOCK_SERVER_H 3 | 4 | #include 5 | 6 | #ifdef __cplusplus 7 | extern "C" { 8 | #endif 9 | 10 | struct mock_connstruct { 11 | uint64_t magic; 12 | const char *uname; 13 | const char *config; 14 | void *engine_data; 15 | bool connected; 16 | struct mock_connstruct *next; 17 | int sfd; 18 | ENGINE_ERROR_CODE status; 19 | uint64_t evictions; 20 | int nblocks; /* number of ewouldblocks */ 21 | bool handle_ewouldblock; 22 | pthread_mutex_t mutex; 23 | pthread_cond_t cond; 24 | }; 25 | 26 | struct mock_callbacks { 27 | EVENT_CALLBACK cb; 28 | const void *cb_data; 29 | struct mock_callbacks *next; 30 | }; 31 | 32 | struct mock_stats { 33 | uint64_t astat; 34 | }; 35 | 36 | MEMCACHED_PUBLIC_API SERVER_HANDLE_V1 *get_mock_server_api(void); 37 | 38 | MEMCACHED_PUBLIC_API void init_mock_server(ENGINE_HANDLE *server_engine); 39 | 40 | MEMCACHED_PUBLIC_API 41 | struct mock_connstruct *mk_mock_connection(const char *user, 42 | const char *config); 43 | 44 | MEMCACHED_PUBLIC_API const void *create_mock_cookie(void); 45 | 46 | MEMCACHED_PUBLIC_API void destroy_mock_cookie(const void *cookie); 47 | 48 | MEMCACHED_PUBLIC_API void mock_set_ewouldblock_handling(const void *cookie, bool enable); 49 | 50 | MEMCACHED_PUBLIC_API void lock_mock_cookie(const void *cookie); 51 | 52 | MEMCACHED_PUBLIC_API void unlock_mock_cookie(const void *cookie); 53 | 54 | MEMCACHED_PUBLIC_API void waitfor_mock_cookie(const void *cookie); 55 | 56 | 57 | MEMCACHED_PUBLIC_API void disconnect_mock_connection(struct mock_connstruct *c); 58 | 59 | MEMCACHED_PUBLIC_API void disconnect_all_mock_connections(struct mock_connstruct *c); 60 | 61 | MEMCACHED_PUBLIC_API void destroy_mock_event_callbacks_rec(struct mock_callbacks *h); 62 | 63 | MEMCACHED_PUBLIC_API void destroy_mock_event_callbacks(void); 64 | 65 | #ifdef __cplusplus 66 | } 67 | #endif 68 | 69 | #endif /* MEMCACHED_MOCK_SERVER_H */ 70 | -------------------------------------------------------------------------------- /t/gat.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests =>13; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | my $expire; 17 | 18 | # Initialize 19 | $cmd = "set key 0 0 5"; $val = "datum"; $rst = "STORED"; 20 | mem_cmd_is($sock, $cmd, $val, $rst); 21 | 22 | # Success Cases 23 | # key value 24 | $cmd = "gat 1 key"; 25 | $rst = "VALUE key 0 5\n" 26 | . "datum\n" 27 | . "END"; 28 | mem_cmd_is($sock, $cmd, "", $rst); 29 | $cmd = "getattr key expiretime"; 30 | $rst = "ATTR expiretime=1\n" 31 | . "END"; 32 | mem_cmd_is($sock, $cmd, "", $rst); 33 | # gats command 34 | $cmd = "gats 1 key"; 35 | $rst = "VALUE key 0 5 1\n" 36 | . "datum\n" 37 | . "END"; 38 | mem_cmd_is($sock, $cmd, "", $rst); 39 | $cmd = "getattr key expiretime"; 40 | $rst = "ATTR expiretime=1\n" 41 | . "END"; 42 | mem_cmd_is($sock, $cmd, "", $rst); 43 | 44 | # Fail Cases 45 | # bad value 46 | $cmd = "set key 0 0 5"; $val = "datum"; $rst = "STORED"; 47 | mem_cmd_is($sock, $cmd, $val, $rst); 48 | $cmd = "gat str key"; $rst = "CLIENT_ERROR invalid exptime argument"; 49 | mem_cmd_is($sock, $cmd, "", $rst); 50 | # exist key and not exist key 51 | $cmd = "gat 1 key key1"; 52 | $rst = "VALUE key 0 5\n" 53 | . "datum\n" 54 | . "END"; 55 | mem_cmd_is($sock, $cmd, "", $rst); 56 | # not exist key 57 | $expire = time() - 1; 58 | $cmd = "gat $expire key"; 59 | $rst = "VALUE key 0 5\n" 60 | . "datum\n" 61 | . "END"; 62 | mem_cmd_is($sock, $cmd, "", $rst); 63 | $cmd = "gat 1 key"; $rst = "END"; 64 | mem_cmd_is($sock, $cmd, "", $rst); 65 | # collection type 66 | $cmd = "lop create lkey 0 0 5"; $rst = "CREATED"; 67 | mem_cmd_is($sock, $cmd, "", $rst); 68 | $cmd = "gat 1 lkey"; $rst = "END"; 69 | mem_cmd_is($sock, $cmd, "", $rst); 70 | $cmd = "getattr lkey expiretime"; 71 | $rst = "ATTR expiretime=0\n" 72 | . "END"; 73 | mem_cmd_is($sock, $cmd, "", $rst); 74 | 75 | # after test 76 | release_memcached($engine, $server); 77 | -------------------------------------------------------------------------------- /t/issue_22.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | ### [ARCUS] CHANGED FOLLOWING TEST ### 5 | # Arcus-memcached allowed more memory to be allocated. 6 | #use Test::More tests => 84; 7 | use Test::More tests => 104; 8 | ###################################### 9 | use FindBin qw($Bin); 10 | use lib "$Bin/lib"; 11 | use MemcachedTest; 12 | 13 | ### [ARCUS] CHANGED FOLLOWING TEST ### 14 | # ENABLE_MIGRATION: hash_item structure has more fields in migration. 15 | #my $server = get_memcached($engine, "-m 3"); 16 | my $engine = shift; 17 | my $server = get_memcached($engine, "-m 3 -n 32"); 18 | ###################################### 19 | my $sock = $server->sock; 20 | my $cmd; 21 | my $val = "B"x77320; 22 | my $rst; 23 | my $key = 0; 24 | 25 | ### [ARCUS] CHANGED FOLLOWING TEST ### 26 | # Arcus-memcached allowed more memory to be allocated. 27 | #for ($key = 0; $key < 40; $key++) { 28 | for ($key = 0; $key < 60; $key++) { 29 | ###################################### 30 | $cmd = "set key$key 0 0 77320"; $rst = "STORED"; 31 | mem_cmd_is($sock, $cmd, $val, $rst); 32 | } 33 | 34 | my $first_stats = mem_stats($sock, "items"); 35 | my $first_evicted = $first_stats->{"items:31:evicted"}; 36 | # I get 1 eviction on a 32 bit binary, but 4 on a 64 binary.. 37 | # Just check that I have evictions... 38 | isnt ($first_evicted, "0", "check evicted"); 39 | 40 | $cmd = "stats reset"; $rst = "RESET"; 41 | mem_cmd_is($sock, $cmd, "", $rst); 42 | 43 | my $second_stats = mem_stats($sock, "items"); 44 | my $second_evicted = $second_stats->{"items:31:evicted"}; 45 | is ($second_evicted, "0", "check evicted"); 46 | 47 | ### [ARCUS] CHANGED FOLLOWING TEST ### 48 | # Arcus-memcached allowed more memory to be allocated. 49 | #for ($key = 40; $key < 80; $key++) { 50 | for ($key = 60; $key < 100; $key++) { 51 | ###################################### 52 | $cmd = "set key$key 0 0 77320"; $rst = "STORED"; 53 | mem_cmd_is($sock, $cmd, $val, $rst); 54 | } 55 | 56 | my $last_stats = mem_stats($sock, "items"); 57 | my $last_evicted = $last_stats->{"items:31:evicted"}; 58 | is ($last_evicted, "40", "check evicted"); 59 | 60 | # after test 61 | release_memcached($engine, $server); 62 | -------------------------------------------------------------------------------- /docs/ascii-protocol/ch10-command-item-attribute.md: -------------------------------------------------------------------------------- 1 | # Chapter 10. Item Attribute 명령 2 | 3 | Item attributes를 조회하는 getattr 명령과 변경하는 setattr 명령을 소개한다. 4 | 5 | ARCUS에서 어떤 item attributes를 제공하는 지를 알고자 한다면, 6 | [Item Attibute 설명](ch03-item-attributes.md)을 참고 바란다. 7 | 8 | 9 | ## getattr (Item Attribute 조회) 10 | 11 | Item attributes를 조회하는 getattr 명령은 아래와 같다. 12 | 13 | ``` 14 | getattr [ ...]\r\n 15 | ``` 16 | 17 | - \ - 대상 item의 key string 18 | - [\ ...] - 조회할 attribute name을 순차적으로 지정하는 것이며, 19 | 이를 생략하면, item 유형에 따라 조회가능한 모든 attributes 값을 조회한다. 20 | 21 | 성공 시의 response string은 아래와 같다. 22 | getattr 명령의 인자로 지정한 attribute name 순서대로 name과 value의 쌍을 리턴한다. 23 | 24 | ``` 25 | ATTR =\r\n 26 | ATTR =\r\n 27 | ... 28 | END\r\n 29 | ``` 30 | 31 | 실패 시의 response string과 그 의미는 아래와 같다. 32 | 33 | | Response String | 설명 | 34 | |-----------------------------------------|------------------------ | 35 | | "NOT_FOUND" | key miss 36 | | "ATTR_ERROR not found" | 인자로 지정한 attribute가 존재하지 않거나 해당 item 유형에서 지원되지 않는 attribute임. 37 | | "CLIENT_ERROR bad command line format" | protocol syntax 틀림 38 | 39 | 40 | ## setattr (Item Attribute 변경) 41 | 42 | Item attributes를 변경하는 setattr 명령은 아래와 같다. 43 | 모든 attributes에 대해 조회가 가능하지만, 변경은 일부 attributes에 대해서만 가능하다. 44 | 변경가능한 attributes로는 expiretime, maxcount, overflowaction, readable, maxbkeyrange가 있다. 45 | 46 | ``` 47 | setattr = [= ...]\r\n 48 | ``` 49 | 50 | - \ - 대상 item의 key string 51 | - \=\ - 변경할 attribute의 name과 value 쌍을 하나 이상 명시하여야 한다. 52 | 53 | 이 명령의 response string과 그 의미는 아래와 같다. 54 | 55 | | Response String | 설명 | 56 | |-----------------------------------------|------------------------ | 57 | | "OK" | 성공 58 | | "NOT_FOUND" | key miss 59 | | "ATTR_ERROR not found" | 인자로 지정한 attribute가 존재하지 않거나 해당 item 유형에서 지원되지 않는 attribute임. 60 | | "ATTR_ERROR bad value" | 해당 attribute에 대해 새로 변경하고자 하는 value가 allowed value가 아님. 61 | | "CLIENT_ERROR bad command line format" | protocol syntax 틀림 62 | -------------------------------------------------------------------------------- /scripts/memcached-init: -------------------------------------------------------------------------------- 1 | #! /bin/sh 2 | # 3 | # skeleton example file to build /etc/init.d/ scripts. 4 | # This file should be used to construct scripts for /etc/init.d. 5 | # 6 | # Written by Miquel van Smoorenburg . 7 | # Modified for Debian 8 | # by Ian Murdock . 9 | # 10 | # Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl 11 | # 12 | ### BEGIN INIT INFO 13 | # Provides: memcached 14 | # Required-Start: $syslog 15 | # Required-Stop: $syslog 16 | # Default-Start: 2 3 4 5 17 | # Default-Stop: 0 1 6 18 | # Short-Description: Start memcached daemon at boot time 19 | # Description: Enable memcached server 20 | ### END INIT INFO 21 | 22 | 23 | PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin 24 | DAEMON=/usr/bin/memcached 25 | DAEMONBOOTSTRAP=/usr/share/memcached/scripts/start-memcached 26 | NAME=memcached 27 | DESC=memcached 28 | PIDFILE=/var/run/$NAME.pid 29 | 30 | test -x $DAEMON || exit 0 31 | test -x $DAEMONBOOTSTRAP || exit 0 32 | 33 | set -e 34 | 35 | case "$1" in 36 | start) 37 | echo -n "Starting $DESC: " 38 | start-stop-daemon --start --quiet --exec $DAEMONBOOTSTRAP 39 | echo "$NAME." 40 | ;; 41 | stop) 42 | echo -n "Stopping $DESC: " 43 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --exec $DAEMON 44 | echo "$NAME." 45 | rm -f $PIDFILE 46 | ;; 47 | 48 | restart|force-reload) 49 | # 50 | # If the "reload" option is implemented, move the "force-reload" 51 | # option to the "reload" entry above. If not, "force-reload" is 52 | # just the same as "restart". 53 | # 54 | echo -n "Restarting $DESC: " 55 | start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE 56 | rm -f $PIDFILE 57 | sleep 1 58 | start-stop-daemon --start --quiet --exec $DAEMONBOOTSTRAP 59 | echo "$NAME." 60 | ;; 61 | *) 62 | N=/etc/init.d/$NAME 63 | # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 64 | echo "Usage: $N {start|stop|restart|force-reload}" >&2 65 | exit 1 66 | ;; 67 | esac 68 | 69 | exit 0 70 | -------------------------------------------------------------------------------- /t/coll_mop_update.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 11; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | =head 10 | get mkey1 11 | 12 | mop insert mkey1 f3 6 create 11 0 0 13 | datum3 14 | mop insert mkey1 f2 6 15 | datum2 16 | mop insert mkey1 f1 6 17 | datum1 18 | mop get mkey1 8 3 19 | f3 f2 f1 20 | 21 | mop update mkey1 f3 8 22 | datum333 23 | mop update mkey1 f2 8 24 | datum222 25 | mop update mkey1 f1 6 26 | datum0 27 | mop get mkey1 8 3 28 | f3 f2 f1 29 | 30 | mop update mket1 f4 9 31 | datum444 32 | 33 | delete mkey1 34 | =cut 35 | 36 | my $engine = shift; 37 | my $server = get_memcached($engine); 38 | my $sock = $server->sock; 39 | 40 | my $cmd; 41 | my $val; 42 | my $rst; 43 | 44 | # Initialize 45 | $cmd = "get mkey1"; $rst = "END"; 46 | mem_cmd_is($sock, $cmd, "", $rst); 47 | $cmd = "mop insert mkey1 f3 6 create 11 0 0"; $val = "datum3"; $rst = "CREATED_STORED"; 48 | mem_cmd_is($sock, $cmd, $val, $rst); 49 | $cmd = "mop insert mkey1 f2 6"; $val = "datum2"; $rst = "STORED"; 50 | mem_cmd_is($sock, $cmd, $val, $rst); 51 | $cmd = "mop insert mkey1 f1 6"; $val = "datum1"; $rst = "STORED"; 52 | mem_cmd_is($sock, $cmd, $val, $rst); 53 | $cmd = "mop get mkey1 8 3"; $val = "f3 f2 f1"; 54 | $rst = "VALUE 11 3 55 | f3 6 datum3 56 | f2 6 datum2 57 | f1 6 datum1 58 | END"; 59 | mem_cmd_is($sock, $cmd, $val, $rst); 60 | 61 | # Success Cases 62 | $cmd = "mop update mkey1 f3 8"; $val = "datum333"; $rst = "UPDATED"; 63 | mem_cmd_is($sock, $cmd, $val, $rst); 64 | $cmd = "mop update mkey1 f2 8"; $val = "datum222"; $rst = "UPDATED"; 65 | mem_cmd_is($sock, $cmd, $val, $rst); 66 | $cmd = "mop update mkey1 f1 6"; $val = "datum0"; $rst = "UPDATED"; 67 | mem_cmd_is($sock, $cmd, $val, $rst); 68 | $cmd = "mop get mkey1 8 3"; $val = "f3 f2 f1"; 69 | $rst = "VALUE 11 3 70 | f3 8 datum333 71 | f2 8 datum222 72 | f1 6 datum0 73 | END"; 74 | mem_cmd_is($sock, $cmd, $val, $rst); 75 | 76 | # Fail Cases 77 | $cmd = "mop update mkey1 f4 8"; $val = "datum444"; $rst = "NOT_FOUND_ELEMENT"; 78 | mem_cmd_is($sock, $cmd, $val, $rst); 79 | 80 | # Finalize 81 | $cmd = "delete mkey1"; $rst = "DELETED"; 82 | mem_cmd_is($sock, $cmd, "", $rst); 83 | 84 | # after test 85 | release_memcached($engine, $server); 86 | -------------------------------------------------------------------------------- /t/multiversioning.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 13; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $sock2 = $server->new_sock; 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | my $msg; 17 | 18 | ok($sock != $sock2, "have two different connections open"); 19 | 20 | # set large value 21 | my $size = 256 * 1024; # 256 kB 22 | my $bigval = "0123456789abcdef" x ($size / 16); 23 | $bigval =~ s/^0/\[/; $bigval =~ s/f$/\]/; 24 | my $bigval2 = uc($bigval); 25 | 26 | $cmd = "set big 0 0 $size"; $val = "$bigval"; $rst = "STORED"; 27 | mem_cmd_is($sock, $cmd, $val, $rst); 28 | $cmd = "get big"; $msg = "big value got correctly"; 29 | $rst = "VALUE big 0 $size 30 | $bigval 31 | END"; 32 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 33 | 34 | print $sock "get big\r\n"; 35 | my $buf; 36 | is(read($sock, $buf, $size / 2), $size / 2, "read half the answer back"); 37 | like($buf, qr/VALUE big/, "buf has big value header in it"); 38 | like($buf, qr/abcdef/, "buf has some data in it"); 39 | unlike($buf, qr/abcde\]/, "buf doesn't yet close"); 40 | 41 | # sock2 interrupts (maybe sock1 is slow) and deletes stuff: 42 | $cmd = "delete big"; $rst = "DELETED"; $msg = "deleted big from sock2 while sock1's still reading it"; 43 | mem_cmd_is($sock2, $cmd, "", $rst, $msg); 44 | $cmd = "get big"; $rst = "END"; $msg = "nothing from sock2 now. gone from namespace."; 45 | mem_cmd_is($sock2, $cmd, "", $rst, $msg); 46 | $cmd = "set big 0 0 $size"; $val = "$bigval2"; $rst = "STORED"; 47 | $msg = "stored big w/ val2"; 48 | mem_cmd_is($sock2, $cmd, $val, $rst, $msg); 49 | $cmd = "get big"; $msg = "big value2 got correctly"; 50 | $rst = "VALUE big 0 $size 51 | $bigval2 52 | END"; 53 | mem_cmd_is($sock2, $cmd, "", $rst, $msg); 54 | 55 | # sock1 resumes reading... 56 | $buf .= <$sock>; 57 | $buf .= <$sock>; 58 | like($buf, qr/abcde\]/, "buf now closes"); 59 | 60 | # and if sock1 reads again, it's the uppercase version: 61 | $cmd = "get big"; $msg = "big value2 got correctly from sock1"; 62 | $rst = "VALUE big 0 $size 63 | $bigval2 64 | END"; 65 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 66 | 67 | # after test 68 | release_memcached($engine, $server); 69 | -------------------------------------------------------------------------------- /lqdetect.h: -------------------------------------------------------------------------------- 1 | #ifndef LQDETECT_H 2 | #define LQDETECT_H 3 | 4 | #include 5 | #include 6 | 7 | #include "memcached/types.h" 8 | #include "memcached/extension.h" 9 | 10 | #define DETECT_LONG_QUERY 11 | 12 | extern bool lqdetect_in_use; 13 | 14 | int lqdetect_init(EXTENSION_LOGGER_DESCRIPTOR *logger); 15 | void lqdetect_final(void); 16 | char *lqdetect_result_get(int *size); 17 | int lqdetect_start(uint32_t threshold, bool *already_started); 18 | void lqdetect_stop(bool *already_stopped); 19 | char *lqdetect_stats(void); 20 | 21 | void lqdetect_lop_insert(char *client_ip, char *key, int coll_index); 22 | void lqdetect_lop_delete(char *client_ip, char *key, uint32_t del_count, 23 | int32_t from_index, int32_t to_index, const bool drop_if_empty); 24 | void lqdetect_lop_get(char *client_ip, char *key, uint32_t elem_count, 25 | int32_t from_index, int32_t to_index, const bool delete, const bool drop_if_empty); 26 | void lqdetect_sop_get(char *client_ip, char *key, uint32_t elem_count, 27 | uint32_t count, const bool delete, const bool drop_if_empty); 28 | void lqdetect_mop_get(char *client_ip, char *key, uint32_t elem_count, 29 | uint32_t coll_numkeys, const bool delete, const bool drop_if_empty); 30 | void lqdetect_mop_delete(char *client_ip, char *key, uint32_t del_count, 31 | uint32_t coll_numkeys, const bool drop_if_empty); 32 | void lqdetect_bop_gbp(char *client_ip, char *key, uint32_t elem_count, 33 | uint32_t from_posi, uint32_t to_posi, ENGINE_BTREE_ORDER order); 34 | void lqdetect_bop_get(char *client_ip, char *key, uint32_t access_count, 35 | const bkey_range *bkrange, const eflag_filter *efilter, 36 | uint32_t offset, uint32_t count, const bool delete, const bool drop_if_empty); 37 | void lqdetect_bop_count(char *client_ip, char *key, uint32_t access_count, 38 | const bkey_range *bkrange, const eflag_filter *efilter); 39 | void lqdetect_bop_delete(char *client_ip, char *key, uint32_t access_count, 40 | const bkey_range *bkrange, const eflag_filter *efilter, 41 | uint32_t count, const bool drop_if_empty); 42 | #endif 43 | -------------------------------------------------------------------------------- /docs/ascii-protocol/ch99-appendix.md: -------------------------------------------------------------------------------- 1 | # ARCUS Telnet Interface 2 | 3 | ARCUS cache server의 동작을 간단히 확인하는 방법으로, telnet interface를 이용할 수 있다. 4 | 5 | ## Telnet 사용법 6 | 7 | OS prompt 상에서 아래와 같이 telnet 명령을 실행시킨다. 8 | telnet 명령의 인자로는 연결하고자 하는 ARCUS cache server인 memcached의 IP와 port number를 준다. 9 | 10 | ``` 11 | $ telnet {memcached-ip} {memcached-port} 12 | ``` 13 | 14 | ## Telnet 연결 15 | 16 | Localhost에 11211 포트 번호로 memcached가 구동되어 있다고 가정한다. 17 | telnet 명령으로 해당 memcached에 연결하기 위해, 18 | OS prompt 상에서 아래의 명령을 수행한다. 19 | 20 | ``` 21 | $ telnet localhost 11211 22 | Trying 127.0.0.1... 23 | Connected to localhost.localdomain (127.0.0.1). 24 | Escape character is '^]'. 25 | ``` 26 | 27 | telnet 명령으로 memcached에 연결한 이후에는 ARCUS ASCII 명령을 직접 수행해 볼 수 있다. 28 | 아래에서 그 예들을 든다. ARCUS ASCII 명령의 자세한 설명은 [ARCUS cache server ascii protocol](README.md)을 참고하기 바란다. 29 | 30 | 31 | ### 예제 1. get/set 32 | 33 | 하나의 key-value item으로 <"foo", "fooval">을 저장하기 위해, set 명령을 입력한다. 34 | 35 | ``` 36 | set foo 0 0 6 37 | fooval 38 | ``` 39 | 40 | set 명령의 수행 결과로 정상적으로 key-value item이 저장되었다는 string이 리턴된다. 41 | 42 | ``` 43 | STORED 44 | ``` 45 | 46 | 저장된 foo item을 조회하기 위해, get 명령을 입력한다. 47 | 48 | 49 | ``` 50 | get foo 51 | ``` 52 | 53 | get 명령으로 조회한 foo item 결과는 아래와 같다. 54 | 55 | 56 | ``` 57 | VALUE foo 0 6 58 | fooval 59 | END 60 | ``` 61 | 62 | ### 예제 2. b+tree 63 | 64 | 하나의 b+tree item을 생성하면서 5개의 elements를 추가하기 위해, 65 | 아래의 5개 bop insert 명령을 차례로 수행한다. 66 | 67 | ``` 68 | bop insert bkey1 90 6 create 11 0 0 69 | datum9 70 | bop insert bkey1 70 6 71 | datum7 72 | bop insert bkey1 50 6 73 | datum5 74 | bop insert bkey1 30 6 75 | datum3 76 | bop insert bkey1 10 6 77 | datum1 78 | ``` 79 | 80 | 5개 bop insert 명령의 수행 결과는 아래와 같다. 81 | 82 | 83 | ``` 84 | CREATED_STORED 85 | STORED 86 | STORED 87 | STORED 88 | STORED 89 | ``` 90 | 91 | b+tree에서 30부터 80까지의 bkey(b+tree key) range에 속하는 elements를 조회하기 위하여, 92 | bop get 명령을 입력한다. 93 | 94 | 95 | ``` 96 | bop get bkey1 30..80 97 | ``` 98 | 99 | bop get 명령으로 조회한 결과는 아래와 같다. 100 | 101 | 102 | ``` 103 | VALUE 11 3 104 | 30 6 datum3 105 | 50 6 datum5 106 | 70 6 datum7 107 | END 108 | ``` 109 | 110 | ## Telnet 종료 111 | 112 | 현재의 telnet 연결을 종료하려면, quit 명령을 입력한다. 113 | 114 | ``` 115 | quit 116 | ``` 117 | -------------------------------------------------------------------------------- /t/coll_mop_insert.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 13; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | =head 10 | get kvkey 11 | get mkey1 12 | mop insert mkey1 field1 6 create 11 0 0 13 | datum9 14 | mop insert mkey1 field2 6 15 | datum7 16 | mop get mkey1 13 2 17 | field1 field2 18 | 19 | mop insert mkey2 field1 6 20 | datum2 21 | set kvkey 0 0 6 22 | datumx 23 | mop insert kvkey field1 6 24 | datum2 25 | setattr mkey1 maxcount=5 26 | mop insert mkey1 field1 6 27 | datum0 28 | setattr mkey1 maxcount=4000 29 | 30 | delete kvkey 31 | delete mkey1 32 | =cut 33 | 34 | my $engine = shift; 35 | my $server = get_memcached($engine); 36 | my $sock = $server->sock; 37 | 38 | my $cmd; 39 | my $val; 40 | my $rst; 41 | 42 | # Initialize 43 | $cmd = "get kvkey"; $rst = "END"; 44 | mem_cmd_is($sock, $cmd, "", $rst); 45 | $cmd = "get mkey1"; $rst = "END"; 46 | mem_cmd_is($sock, $cmd, "", $rst); 47 | # Success Cases 48 | $cmd = "mop insert mkey1 field1 6 create 11 0 0"; $val = "datum9"; $rst = "CREATED_STORED"; 49 | mem_cmd_is($sock, $cmd, $val, $rst); 50 | $cmd = "mop insert mkey1 field2 6"; $val = "datum7"; $rst = "STORED"; 51 | mem_cmd_is($sock, $cmd, $val, $rst); 52 | $cmd = "mop get mkey1 13 2"; $val = "field1 field2"; 53 | $rst = "VALUE 11 2 54 | field1 6 datum9 55 | field2 6 datum7 56 | END"; 57 | mem_cmd_is($sock, $cmd, $val, $rst); 58 | 59 | # Fail Cases 60 | $cmd = "mop insert mkey2 field1 6"; $val = "datum2"; $rst = "NOT_FOUND"; 61 | mem_cmd_is($sock, $cmd, $val, $rst); 62 | $cmd = "set kvkey 0 0 6"; $val = "datumx"; $rst = "STORED"; 63 | mem_cmd_is($sock, $cmd, $val, $rst); 64 | $cmd = "mop insert kvkey field1 6"; $val = "datum2"; $rst = "TYPE_MISMATCH"; 65 | mem_cmd_is($sock, $cmd, $val, $rst); 66 | $cmd = "setattr mkey1 maxcount=5"; $rst = "OK"; 67 | mem_cmd_is($sock, $cmd, "", $rst); 68 | $cmd = "mop insert mkey1 field1 6"; $val = "datum0"; $rst = "ELEMENT_EXISTS"; 69 | mem_cmd_is($sock, $cmd, $val, $rst); 70 | $cmd = "setattr mkey1 maxcount=4000"; $rst = "OK"; 71 | mem_cmd_is($sock, $cmd, "", $rst); 72 | 73 | # Finalize 74 | $cmd = "delete kvkey"; $rst = "DELETED"; 75 | mem_cmd_is($sock, $cmd, "", $rst); 76 | $cmd = "delete mkey1"; $rst = "DELETED"; 77 | mem_cmd_is($sock, $cmd, "", $rst); 78 | 79 | # after test 80 | release_memcached($engine, $server); 81 | -------------------------------------------------------------------------------- /t/etc/stress-workload-change.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | #my $server = get_memcached($engine, '-m 1024'); 10 | 11 | my $threads = 256; 12 | my $running = 0; 13 | 14 | while ($running < $threads) { 15 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 16 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 17 | my $cpid = fork(); 18 | if ($cpid) { 19 | $running++; 20 | print "Launched $cpid. Running $running threads.\n"; 21 | } else { 22 | stress($sock); 23 | exit 0; 24 | } 25 | } 26 | while ($running > 0) { 27 | wait(); 28 | print "stopped. Running $running threads.\n"; 29 | $running--; 30 | } 31 | 32 | 33 | sub stress { 34 | my $sock = shift; 35 | my $i; 36 | for ($i = 0; $i < 60; $i++) { 37 | my $keyrand = int(rand(1000000)); 38 | my $valrand = 50000; 39 | my $key = "key1$keyrand"; 40 | my $val = "B" x $valrand; 41 | my $len = length($val); 42 | my $res; 43 | print $sock "set $key 0 0 $len\r\n$val\r\n"; 44 | $res = scalar <$sock>; 45 | if ($res ne "STORED\r\n") { 46 | print "set $key $len: $res\r\n"; 47 | } 48 | } 49 | for ($i = 0; $i < 2000; $i++) { 50 | my $keyrand = int(rand(1000000)); 51 | my $valrand = 200; 52 | my $key = "key2$keyrand"; 53 | my $val = "B" x $valrand; 54 | my $len = length($val); 55 | my $res; 56 | print $sock "set $key 0 0 $len\r\n$val\r\n"; 57 | $res = scalar <$sock>; 58 | if ($res ne "STORED\r\n") { 59 | print "set $key $len: $res\r\n"; 60 | } 61 | } 62 | for ($i = 0; $i < 5000; $i++) { 63 | my $keyrand = int(rand(1000000)); 64 | my $valrand = int(rand(5000)); 65 | my $key = "dash$keyrand"; 66 | my $val = "B" x $valrand; 67 | my $len = length($val); 68 | my $res; 69 | print $sock "set $key 0 0 $len\r\n$val\r\n"; 70 | $res = scalar <$sock>; 71 | if ($res ne "STORED\r\n") { 72 | print "set $key $len: $res\r\n"; 73 | } 74 | } 75 | print "stress end\n"; 76 | } 77 | 78 | -------------------------------------------------------------------------------- /t/00-startup.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 18; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server; 11 | my $stats; 12 | eval { 13 | $server = get_memcached($engine); 14 | ok($server, "started the server"); 15 | }; 16 | is($@, '', 'Basic startup works'); 17 | 18 | eval { 19 | $server = get_memcached($engine, "-l fooble"); 20 | }; 21 | ok($@, "Died with illegal -l args"); 22 | 23 | eval { 24 | $server = get_memcached($engine, "-l 127.0.0.1"); 25 | }; 26 | is($@,'', "-l 127.0.0.1 works"); 27 | 28 | eval { 29 | $server = get_memcached($engine, '-C'); 30 | $stats = mem_stats($server->sock, 'settings'); 31 | is('no', $stats->{'cas_enabled'}); 32 | }; 33 | is($@, '', "-C works"); 34 | 35 | eval { 36 | $server = get_memcached($engine, '-b 8675'); 37 | $stats = mem_stats($server->sock, 'settings'); 38 | is('8675', $stats->{'tcp_backlog'}); 39 | }; 40 | is($@, '', "-b works"); 41 | 42 | foreach my $val ('auto', 'ascii') { 43 | eval { 44 | $server = get_memcached($engine, "-B $val"); 45 | $stats = mem_stats($server->sock, 'settings'); 46 | ok($stats->{'binding_protocol'} =~ /$val/, "$val works"); 47 | }; 48 | is($@, '', "$val works"); 49 | } 50 | 51 | # For the binary test, we just verify it starts since we don't have an easy bin client. 52 | eval { 53 | $server = get_memcached($engine, "-B binary"); 54 | }; 55 | is($@, '', "binary works"); 56 | 57 | eval { 58 | $server = get_memcached($engine, "-vv -B auto"); 59 | }; 60 | is($@, '', "auto works"); 61 | 62 | eval { 63 | $server = get_memcached($engine, "-vv -B ascii"); 64 | }; 65 | is($@, '', "ascii works"); 66 | 67 | 68 | # For the binary test, we just verify it starts since we don't have an easy bin client. 69 | eval { 70 | $server = get_memcached($engine, "-vv -B binary"); 71 | }; 72 | is($@, '', "binary works"); 73 | 74 | 75 | # Should blow up with something invalid. 76 | eval { 77 | $server = get_memcached($engine, "-B http"); 78 | }; 79 | ok($@, "Died with illegal -B arg."); 80 | 81 | # Should not allow -t 0 82 | eval { 83 | $server = get_memcached($engine, "-t 0"); 84 | }; 85 | ok($@, "Died with illegal 0 thread count"); 86 | 87 | # after test 88 | release_memcached($engine, $server); 89 | -------------------------------------------------------------------------------- /t/mget2.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 2002; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | 17 | # BOP test sub routines 18 | sub prepare_kv_mget { 19 | my ($key_cnt) = @_; 20 | my $kcnt; 21 | my $key; 22 | 23 | for ($kcnt = 0; $kcnt < $key_cnt; $kcnt += 1) { 24 | $key = "mget_test:mget_test_key_$kcnt"; 25 | $val = "mget_test_value_$kcnt"; 26 | my $len = length($val); 27 | $cmd = "set $key 0 0 $len"; $rst = "STORED"; 28 | mem_cmd_is($sock, $cmd, $val, $rst); 29 | } 30 | } 31 | 32 | sub assert_kv_mget_old { 33 | my ($key_len, $key_cnt, $key_str) = @_; 34 | my $kcnt; 35 | 36 | # old kv mget command 37 | $cmd = "get $key_str"; $rst = ""; 38 | 39 | for ($kcnt = 0; $kcnt < $key_cnt; $kcnt += 1) { 40 | my $kstr = "mget_test:mget_test_key_$kcnt"; 41 | my $data = "mget_test_value_$kcnt"; 42 | my $vlen = length($data); 43 | $rst .= "VALUE $kstr 0 $vlen\n$data\n"; 44 | } 45 | $rst .= "END"; 46 | mem_cmd_is($sock, $cmd, "", $rst); 47 | } 48 | 49 | sub assert_kv_mget_new { 50 | my ($key_len, $key_cnt, $key_str) = @_; 51 | my $kcnt; 52 | 53 | # new kv mget command 54 | $cmd = "mget $key_len $key_cnt"; $val = "$key_str"; $rst = ""; 55 | 56 | for ($kcnt = 0; $kcnt < $key_cnt; $kcnt += 1) { 57 | my $kstr = "mget_test:mget_test_key_$kcnt"; 58 | my $data = "mget_test_value_$kcnt"; 59 | my $vlen = length($data); 60 | $rst .= "VALUE $kstr 0 $vlen\n$data\n"; 61 | } 62 | $rst .= "END"; 63 | mem_cmd_is($sock, $cmd, $val, $rst); 64 | } 65 | 66 | # testKVMGet 67 | my $key_cnt = 2000; 68 | my $key_str; 69 | my $key_len; 70 | my $kcnt; 71 | 72 | prepare_kv_mget($key_cnt); 73 | 74 | $key_str = "mget_test:mget_test_key_0"; 75 | for ($kcnt = 1; $kcnt < $key_cnt; $kcnt += 1) { 76 | $key_str = "$key_str mget_test:mget_test_key_$kcnt"; 77 | } 78 | $key_len = length($key_str); 79 | 80 | # kv mget old 81 | assert_kv_mget_old($key_len, $key_cnt, $key_str); 82 | 83 | # kv mget new 84 | assert_kv_mget_new($key_len, $key_cnt, $key_str); 85 | 86 | # after test 87 | release_memcached($engine, $server); 88 | -------------------------------------------------------------------------------- /t/lru.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 149; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | # assuming max slab is 1M and default mem is 64M 10 | my $engine = shift; 11 | my $server = get_memcached($engine); 12 | my $sock = $server->sock; 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | my $msg; 17 | 18 | # create a big value for the largest slab 19 | my $max = 1024 * 1024; 20 | my $big = 'x' x (1024 * 1024 - 250); 21 | 22 | ok(length($big) > 512 * 1024, "buffer is bigger than 512k"); 23 | ok(length($big) < 1024 * 1024, "buffer is less than 1m"); 24 | 25 | # test that an even bigger value is rejected while we're here 26 | my $too_big = $big . $big . $big; 27 | my $len = length($too_big); 28 | $cmd = "set too_big 0 0 $len"; $val = "$too_big"; 29 | $rst = "CLIENT_ERROR object too large for cache"; $msg = "too_big not stored"; 30 | mem_cmd_is($sock, $cmd, $val, $rst, $msg); 31 | 32 | # set the big value 33 | my $len = length($big); 34 | $cmd = "set big 0 0 $len"; $val = "$big"; $rst = "STORED"; $msg = "stored big"; 35 | mem_cmd_is($sock, $cmd, $val, $rst, $msg); 36 | $cmd = "get big"; 37 | $rst = "VALUE big 0 $len 38 | $big 39 | END"; 40 | mem_cmd_is($sock, $cmd, "", $rst); 41 | 42 | # no evictions yet 43 | my $stats = mem_stats($sock); 44 | is($stats->{"evictions"}, "0", "no evictions to start"); 45 | 46 | # set many big items, enough to get evictions 47 | for (my $i = 0; $i < 100; $i++) { 48 | $cmd = "set item_$i 0 0 $len"; $val = "$big"; $rst = "STORED"; $msg = "stored item_$i"; 49 | mem_cmd_is($sock, $cmd, $val, $rst, $msg); 50 | } 51 | 52 | # some evictions should have happened 53 | my $stats = mem_stats($sock); 54 | my $evictions = int($stats->{"evictions"}); 55 | ok($evictions == 37, "some evictions happened"); 56 | 57 | # the first big value should be gone 58 | $cmd = "get big"; $rst = "END"; 59 | mem_cmd_is($sock, $cmd, "", $rst); 60 | 61 | # the earliest items should be gone too 62 | for (my $i = 0; $i < $evictions - 1; $i++) { 63 | $cmd = "get item_$i"; $rst = "END"; 64 | mem_cmd_is($sock, $cmd, "", $rst); 65 | } 66 | 67 | # check that the non-evicted are the right ones 68 | for (my $i = $evictions - 1; $i < $evictions + 4; $i++) { 69 | $cmd = "get item_$i"; 70 | $rst = "VALUE item_$i 0 $len\n" 71 | . "$big\n" 72 | . "END"; 73 | mem_cmd_is($sock, $cmd, "", $rst); 74 | } 75 | 76 | # after test 77 | release_memcached($engine, $server); 78 | -------------------------------------------------------------------------------- /include/memcached/callback.h: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #ifndef MEMCACHED_CALLBACK_H 3 | #define MEMCACHED_CALLBACK_H 4 | 5 | #include "memcached/engine_common.h" 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | /** 12 | * Event types for callbacks to the engine indicating state 13 | * changes in the server. 14 | */ 15 | typedef enum { 16 | ON_CONNECT = 0, /**< A new connection was established. */ 17 | ON_DISCONNECT = 1, /**< A connection was terminated. */ 18 | ON_AUTH = 2, /**< A connection was authenticated. */ 19 | ON_SWITCH_CONN = 3, /**< Processing a different connection on this thread. */ 20 | ON_LOG_LEVEL = 4 /**< Changed log level */ 21 | } ENGINE_EVENT_TYPE; 22 | 23 | #define MAX_ENGINE_EVENT_TYPE 5 24 | 25 | /** 26 | * Callback for server events. 27 | * 28 | * @param cookie The cookie provided by the frontend 29 | * @param type the type of event 30 | * @param event_data additional event-specific data. 31 | * @param cb_data data as registered 32 | */ 33 | typedef void (*EVENT_CALLBACK)(const void *cookie, 34 | ENGINE_EVENT_TYPE type, 35 | const void *event_data, 36 | const void *cb_data); 37 | 38 | /** 39 | * The API provided by the server to manipulate callbacks 40 | */ 41 | typedef struct { 42 | /** 43 | * Register an event callback. 44 | * 45 | * @param type the type of event to register 46 | * @param cb the callback to fire when the event occurs 47 | * @param cb_data opaque data to be given back to the caller 48 | * on event 49 | */ 50 | void (*register_callback)(ENGINE_HANDLE *engine, 51 | ENGINE_EVENT_TYPE type, 52 | EVENT_CALLBACK cb, 53 | const void *cb_data); 54 | 55 | /** 56 | * Fire callbacks 57 | */ 58 | void (*perform_callbacks)(ENGINE_EVENT_TYPE type, 59 | const void *data, 60 | const void *cookie); 61 | } SERVER_CALLBACK_API; 62 | 63 | #ifdef __cplusplus 64 | } 65 | #endif 66 | 67 | #endif 68 | -------------------------------------------------------------------------------- /docs/ascii-protocol/README.md: -------------------------------------------------------------------------------- 1 | # ARCUS Cache Server ASCII Protocol 2 | 3 | ARCUS Cache Server가 제공하는 명령들의 ASCII Protocol을 기술한다. 4 | Binary protocol은 현재 지원하지 않으므로, 논의에서 제외한다. 5 | 6 | 본 문서는 ARCUS cache client 개발자를 주 대상으로 하며, 7 | ARCUS Cache Server에 관심있는 독자의 경우도 참고할 수 있다. 8 | 9 | Collection Support 10 | ------------------ 11 | 12 | ASCII Protocol 관점에서 ARCUS Cache Server는 기존 memcached 기능 외에 collection 기능을 제공한다. 13 | 하나의 data만을 가지는 simple key-value 외에도 여러 data를 구조화된 형태로 저장/조회할 수 있으며, 14 | 제공하는 collection 유형은 아래와 같다. 15 | 16 | - list : 데이터들의 linked list 구조 17 | - set : 유일한 데이터들의 집합으로 membership 검사에 적합 18 | - map : \쌍으로 구성된 데이터들의 집합으로 field 기준의 hash 구조 19 | - b+tree : b+tree 키 기준으로 정렬된 데이터들의 집합으로 range scan 처리에 적합 20 | 21 | Basic Concepts 22 | -------------- 23 | 24 | ARCUS Cache Server를 사용함에 있어 필요한 cache key, item, slab 등의 기본 용어와 개념은 25 | [ARCUS 기본 개념](ch01-arcus-basic-concept.md)에서 설명하므로, 이를 먼저 읽어보길 권한다. 26 | 27 | ARCUS Cache Server가 제공하는 collection과 element 구조, b+tree key, element flag 등의 28 | 중요 요소들은 [Collection 기본 개념](ch02-collection-items.md)에서 소개한다. 29 | 30 | Collection 기능을 제공함에 따라 item 속성들이 확장되었으며, 31 | 이들은 [Item 속성 설명](ch03-item-attributes.md)에서 자세히 다룬다. 32 | 33 | Simple Key-Value 기능 34 | --------------------- 35 | 36 | ARCUS Cache Server는 memcached 1.4 기준의 key-value 명령을 그대로 제공하며, 일부에 대해 확장된 명령을 제공한다. 37 | 따라서, 기존 memcached 1.4에서 사용한 명령들은 ARCUS Cache Server에서도 그대로 사용 가능하다. 38 | [Key-Value 명령](ch04-command-key-value.md)에서 key-value 유형의 item에 대해 수행가능한 명령들을 소개한다. 39 | 40 | Collection 기능 41 | --------------- 42 | 43 | Collection 명령의 자세한 설명은 아래를 참고 바랍니다. 44 | 45 | - [List collection 명령](ch05-command-list-collection.md) 46 | - [Set collection 명령](ch06-command-set-collection.md) 47 | - [Map collection 명령](ch07-command-map-collection.md) 48 | - [B+tree collection 명령](ch08-command-btree-collection.md) 49 | 50 | Collection 일부 명령들은 command pipelining 처리가 가능하며, 51 | [Command Pipelining 기능](ch09-command-pipelining.md)에서 설명한다. 52 | 53 | Item Attributes 기능 54 | -------------------- 55 | 56 | Collection 지원으로 인해 item 유형이 다양해 졌으며, 다양한 item 유형에 따라 item attributes도 확장되었다. 57 | Item attributes를 조회하거나 변경하기 위하여 [Item Attribute 명령](ch10-command-item-attribute.md)을 제공한다. 58 | 59 | Scan 기능 60 | -------------------- 61 | 조건에 맞는 item 혹은 prefix 목록을 가져오는 기능으로 [Scan 명령](ch11-command-scan.md)을 제공한다. 62 | 63 | Admin & Monitoring 기능 64 | ----------------------- 65 | 66 | ARCUS Cache Server의 운영 상에 필요한 기능들은 [Admin & Monitoring 명령](ch12-command-administration.md)으로 제공한다. 67 | -------------------------------------------------------------------------------- /t/coll_mop_upsert.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 14; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | =head 10 | get kvkey 11 | get mkey1 12 | mop upsert mkey1 field1 6 create 11 0 0 13 | datum9 14 | mop upsert mkey1 field2 6 15 | datum7 16 | setattr mkey1 maxcount=2 17 | mop upsert mkey1 field1 6 18 | datum5 19 | mop get mkey1 13 2 20 | field1 field2 21 | 22 | mop upsert mkey2 field1 6 23 | datum2 24 | set kvkey 0 0 6 25 | datumx 26 | mop upsert kvkey field1 6 27 | datum2 28 | mop upsert mkey1 field1 6 29 | datum4 30 | setattr mkey1 maxcount=4000 31 | 32 | delete kvkey 33 | delete mkey1 34 | =cut 35 | 36 | my $engine = shift; 37 | my $server = get_memcached($engine); 38 | my $sock = $server->sock; 39 | 40 | my $cmd; 41 | my $val; 42 | my $rst; 43 | 44 | # Initialize 45 | $cmd = "get kvkey"; $rst = "END"; 46 | mem_cmd_is($sock, $cmd, "", $rst); 47 | $cmd = "get mkey1"; $rst = "END"; 48 | mem_cmd_is($sock, $cmd, "", $rst); 49 | 50 | # Success Cases 51 | $cmd = "mop upsert mkey1 field1 6 create 11 0 0"; $val = "datum9"; $rst = "CREATED_STORED"; 52 | mem_cmd_is($sock, $cmd, $val, $rst); 53 | $cmd = "mop upsert mkey1 field2 6"; $val = "datum7"; $rst = "STORED"; 54 | mem_cmd_is($sock, $cmd, $val, $rst); 55 | $cmd = "setattr mkey1 maxcount=2"; $rst = "OK"; 56 | mem_cmd_is($sock, $cmd, "", $rst); 57 | $cmd = "mop upsert mkey1 field1 6"; $val = "datum0"; $rst = "REPLACED"; 58 | mem_cmd_is($sock, $cmd, $val, $rst); 59 | $cmd = "mop get mkey1 13 2"; $val = "field1 field2"; 60 | $rst = "VALUE 11 2 61 | field1 6 datum0 62 | field2 6 datum7 63 | END"; 64 | mem_cmd_is($sock, $cmd, $val, $rst); 65 | 66 | # Fail Cases 67 | $cmd = "mop upsert mkey2 field1 6"; $val = "datum2"; $rst = "NOT_FOUND"; 68 | mem_cmd_is($sock, $cmd, $val, $rst); 69 | $cmd = "set kvkey 0 0 6"; $val = "datumx"; $rst = "STORED"; 70 | mem_cmd_is($sock, $cmd, $val, $rst); 71 | $cmd = "mop upsert kvkey field1 6"; $val = "datum2"; $rst = "TYPE_MISMATCH"; 72 | mem_cmd_is($sock, $cmd, $val, $rst); 73 | $cmd = "mop upsert mkey1 field3 6"; $val = "datum5"; $rst = "OVERFLOWED"; 74 | mem_cmd_is($sock, $cmd, $val, $rst); 75 | $cmd = "setattr mkey1 maxcount=4000"; $rst = "OK"; 76 | mem_cmd_is($sock, $cmd, "", $rst); 77 | 78 | # Finalize 79 | $cmd = "delete kvkey"; $rst = "DELETED"; 80 | mem_cmd_is($sock, $cmd, "", $rst); 81 | $cmd = "delete mkey1"; $rst = "DELETED"; 82 | mem_cmd_is($sock, $cmd, "", $rst); 83 | 84 | # after test 85 | release_memcached($engine, $server); 86 | 87 | -------------------------------------------------------------------------------- /t/tlist/engine_default_s.txt: -------------------------------------------------------------------------------- 1 | ./t/00-startup.t 2 | ./t/64bit.t 3 | ./t/arcus_ping_test.t 4 | ./t/ascii_ext_protocol.t 5 | ./t/binary_crash.t 6 | ./t/binary-get.t 7 | ./t/binary-sasl.t 8 | ./t/binary.t 9 | ./t/bogus-commands.t 10 | ./t/cas.t 11 | ./t/cmd_extensions.t 12 | ./t/coll_max_elembytes_test.t 13 | ./t/coll_bkeymismatch_test.t 14 | ./t/coll_bkeyoor_test.t 15 | ./t/coll_bop_attr_min_max_bkey.t 16 | ./t/coll_bop_count.t 17 | ./t/coll_bop_delete.t 18 | ./t/coll_bop_eflag.t 19 | ./t/coll_bop_get.t 20 | ./t/coll_bop_incrdecr.t 21 | ./t/coll_bop_insert_getrim.t 22 | ./t/coll_bop_insert.t 23 | ./t/coll_bop_maxbkeyrange.t 24 | ./t/coll_bop_mget_1.t 25 | ./t/coll_bop_mget_2.t 26 | ./t/coll_bop_smget_bkey_byte.t 27 | ./t/coll_bop_smget_bkey_uint.t 28 | ./t/coll_bop_smget_issues.t 29 | ./t/coll_bop_smget_trim_test.t 30 | ./t/coll_bop_smget_unique_test.t 31 | ./t/coll_bop_trimmed_test.t 32 | ./t/coll_bop_unittest.t 33 | ./t/coll_bop_update.t 34 | ./t/coll_bop_upsert.t 35 | ./t/coll_lop_large.t 36 | ./t/coll_lop_unittest.t 37 | ./t/coll_mop_delete.t 38 | ./t/coll_mop_get.t 39 | ./t/coll_mop_insert.t 40 | ./t/coll_mop_upsert.t 41 | ./t/coll_mop_update.t 42 | ./t/coll_pipeline_general.t 43 | ./t/coll_pipeline_sop_exist.t 44 | ./t/coll_readable_attr.t 45 | ./t/coll_sop_segfault_p012611.t 46 | ./t/coll_sop_unittest.t 47 | ./t/daemonize.t 48 | ./t/dash-M.t 49 | ./t/evictions.t 50 | ./t/expirations.t 51 | ./t/flags.t 52 | ./t/flush-prefix.t 53 | ./t/flush-all.t 54 | ./t/getset.t 55 | ./t/incrdecr.t 56 | ./t/issue_104.t 57 | ./t/issue_108.t 58 | ./t/issue_14.t 59 | ./t/issue_152.t 60 | ./t/issue_163.t 61 | ./t/issue_22.t 62 | ./t/issue_29.t 63 | ./t/issue_3.t 64 | ./t/issue_41.t 65 | ./t/issue_42.t 66 | ./t/issue_50.t 67 | ./t/issue_61.t 68 | ./t/issue_67.t 69 | ./t/issue_68.t 70 | ./t/issue_70.t 71 | ./t/issue_arcus_151.t 72 | ./t/issue_arcus_655.t 73 | ./t/issue_ee_599.t 74 | ./t/item_size_max.t 75 | ./t/line-lengths.t 76 | ./t/longkey.t 77 | ./t/long_query_detect_issue.t 78 | ./t/lru.t 79 | ./t/maxconns.t 80 | ./t/mget2.t 81 | ./t/mget.t 82 | ./t/mgets.t 83 | ./t/multiversioning.t 84 | ./t/noreply.t 85 | ./t/readable_expiretime.t 86 | ./t/scrub.t 87 | ./t/set_with_largest_slab.t 88 | ./t/stats-detail.t 89 | ./t/stats_prefixes.t 90 | ./t/stats.t 91 | ./t/topkeys.t 92 | ./t/udp.t 93 | ./t/unixsocket.t 94 | ./t/verbosity.t 95 | ./t/whitespace.t 96 | ./t/nested_prefix.t 97 | ./t/keyscan.t 98 | ./t/prefixscan.t 99 | ./t/touch.t 100 | -------------------------------------------------------------------------------- /t/touch.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests =>19; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | my $expire; 17 | 18 | # Initialize 19 | $cmd = "set key 0 0 5"; $val = "datum"; $rst = "STORED"; 20 | mem_cmd_is($sock, $cmd, $val, $rst); 21 | $cmd = "lop create lkey 0 0 1 error"; $rst = "CREATED"; 22 | mem_cmd_is($sock, $cmd, "", $rst); 23 | $cmd = "sop create skey 0 0 1 error"; $rst = "CREATED"; 24 | mem_cmd_is($sock, $cmd, "", $rst); 25 | $cmd = "mop create mkey 0 0 1 error"; $rst = "CREATED"; 26 | mem_cmd_is($sock, $cmd, "", $rst); 27 | $cmd = "bop create bkey 0 0 1 error"; $rst = "CREATED"; 28 | mem_cmd_is($sock, $cmd, "", $rst); 29 | 30 | # Success Cases 31 | # key value 32 | $cmd = "touch key 1"; $rst = "TOUCHED"; 33 | mem_cmd_is($sock, $cmd, "", $rst); 34 | $cmd = "getattr key expiretime"; 35 | $rst = "ATTR expiretime=1\n" 36 | . "END"; 37 | mem_cmd_is($sock, $cmd, "", $rst); 38 | # list 39 | $cmd = "touch lkey 1"; $rst = "TOUCHED"; 40 | mem_cmd_is($sock, $cmd, "", $rst); 41 | $cmd = "getattr lkey expiretime"; 42 | $rst = "ATTR expiretime=1\n" 43 | . "END"; 44 | mem_cmd_is($sock, $cmd, "", $rst); 45 | # set 46 | $cmd = "touch skey 1"; $rst = "TOUCHED"; 47 | mem_cmd_is($sock, $cmd, "", $rst); 48 | $cmd = "getattr skey expiretime"; 49 | $rst = "ATTR expiretime=1\n" 50 | . "END"; 51 | mem_cmd_is($sock, $cmd, "", $rst); 52 | # map 53 | $cmd = "touch mkey 1"; $rst = "TOUCHED"; 54 | mem_cmd_is($sock, $cmd, "", $rst); 55 | $cmd = "getattr mkey expiretime"; 56 | $rst = "ATTR expiretime=1\n" 57 | . "END"; 58 | mem_cmd_is($sock, $cmd, "", $rst); 59 | #btree 60 | $cmd = "touch bkey 1"; $rst = "TOUCHED"; 61 | mem_cmd_is($sock, $cmd, "", $rst); 62 | $cmd = "getattr bkey expiretime"; 63 | $rst = "ATTR expiretime=1\n" 64 | . "END"; 65 | mem_cmd_is($sock, $cmd, "", $rst); 66 | 67 | # Fail Cases 68 | # bad value 69 | $cmd = "set key 0 0 5"; $val = "datum"; $rst = "STORED"; 70 | mem_cmd_is($sock, $cmd, $val, $rst); 71 | $cmd = "touch key str"; $rst = "CLIENT_ERROR bad value"; 72 | mem_cmd_is($sock, $cmd, "", $rst); 73 | # not exist key 74 | $expire = time() - 1; 75 | $cmd = "touch key $expire"; $rst = "TOUCHED"; 76 | mem_cmd_is($sock, $cmd, "", $rst); 77 | $cmd = "touch key 1"; $rst = "NOT_FOUND"; 78 | mem_cmd_is($sock, $cmd, "", $rst); 79 | 80 | # after test 81 | release_memcached($engine, $server); 82 | -------------------------------------------------------------------------------- /include/memcached/config_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * arcus-memcached - Arcus memory cache server 3 | * Copyright 2010-2014 NAVER Corp. 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); 6 | * you may not use this file except in compliance with the License. 7 | * You may obtain a copy of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | * See the License for the specific language governing permissions and 15 | * limitations under the License. 16 | */ 17 | #ifndef CONFIG_PARSER_H 18 | #define CONFIG_PARSER_H 19 | 20 | #include // for using FILE structure. 21 | #include 22 | #include 23 | 24 | #ifdef __cplusplus 25 | extern "C" { 26 | #endif 27 | 28 | /** 29 | * The supported datatypes the config file parser can handle 30 | */ 31 | enum config_datatype { 32 | DT_SIZE, 33 | DT_UINT32, 34 | DT_FLOAT, 35 | DT_BOOL, 36 | DT_STRING, 37 | DT_CONFIGFILE, 38 | DT_CHAR 39 | }; 40 | 41 | /** 42 | * I don't like casting, so let's create a union to keep all the values in 43 | */ 44 | union config_value { 45 | size_t *dt_size; 46 | uint32_t *dt_uint32; 47 | float *dt_float; 48 | bool *dt_bool; 49 | char **dt_string; 50 | char *dt_char; 51 | }; 52 | 53 | /** 54 | * An entry for a single item in the config file. 55 | */ 56 | struct config_item { 57 | /** The name of the key */ 58 | const char* key; 59 | /** The datatype for the value */ 60 | enum config_datatype datatype; 61 | /** Where to store the value from the config file */ 62 | union config_value value; 63 | /** If the item was found in the config file or not */ 64 | bool found; 65 | }; 66 | 67 | /** 68 | * Parse the configuration argument and populate the values into the 69 | * config items. 70 | * 71 | * @param str the encoded configuration string 72 | * @param items the config items to look for 73 | * @param error stream to write error messages to 74 | * @return 0 if config successfully parsed 75 | * 1 if config successfully parsed, but unknown tokens found 76 | * -1 if illegal values was found in the config 77 | */ 78 | MEMCACHED_PUBLIC_API int parse_config(const char *str, struct config_item items[], FILE *error); 79 | 80 | #ifdef __cplusplus 81 | } 82 | #endif 83 | 84 | #endif 85 | -------------------------------------------------------------------------------- /extension_loggers.c: -------------------------------------------------------------------------------- 1 | /* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | static EXTENSION_LOG_LEVEL current_log_level = EXTENSION_LOG_WARNING; 9 | SERVER_HANDLE_V1 *sapi; 10 | 11 | static const char *stderror_get_name(void) { 12 | return "standard error"; 13 | } 14 | 15 | static void stderror_logger_log(EXTENSION_LOG_LEVEL severity, 16 | const void* client_cookie, 17 | const char *fmt, ...) 18 | { 19 | if (severity >= current_log_level) { 20 | (void)client_cookie; 21 | 22 | va_list ap; 23 | va_start(ap, fmt); 24 | vfprintf(stderr, fmt, ap); 25 | va_end(ap); 26 | fflush(stderr); 27 | } 28 | } 29 | 30 | static EXTENSION_LOGGER_DESCRIPTOR stderror_logger_descriptor = { 31 | .get_name = stderror_get_name, 32 | .log = stderror_logger_log 33 | }; 34 | 35 | static void on_log_level(const void *cookie, 36 | ENGINE_EVENT_TYPE type, 37 | const void *event_data, 38 | const void *cb_data) { 39 | if (sapi != NULL) { 40 | current_log_level = sapi->log->get_level(); 41 | } 42 | } 43 | 44 | EXTENSION_ERROR_CODE memcached_initialize_stderr_logger(GET_SERVER_API get_server_api) { 45 | sapi = get_server_api(); 46 | if (sapi == NULL) { 47 | return EXTENSION_FATAL; 48 | } 49 | 50 | current_log_level = sapi->log->get_level(); 51 | sapi->callback->register_callback(NULL, ON_LOG_LEVEL, 52 | on_log_level, NULL); 53 | 54 | return EXTENSION_SUCCESS; 55 | } 56 | 57 | static const char *null_get_name(void) { 58 | return "/dev/null"; 59 | } 60 | 61 | static void null_logger_log(EXTENSION_LOG_LEVEL severity, 62 | const void* client_cookie, 63 | const char *fmt, ...) 64 | { 65 | (void)severity; 66 | (void)client_cookie; 67 | (void)fmt; 68 | /* EMPTY */ 69 | } 70 | 71 | static EXTENSION_LOGGER_DESCRIPTOR null_logger_descriptor = { 72 | .get_name = null_get_name, 73 | .log = null_logger_log 74 | }; 75 | 76 | EXTENSION_LOGGER_DESCRIPTOR* get_null_logger(void) { 77 | return &null_logger_descriptor; 78 | } 79 | 80 | EXTENSION_LOGGER_DESCRIPTOR* get_stderr_logger(void) { 81 | return &stderror_logger_descriptor; 82 | } 83 | -------------------------------------------------------------------------------- /t/etc/eager_item_invalidation.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 128; 12 | my $running = 0; 13 | 14 | while ($running < $threads) { 15 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 16 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 17 | my $cpid = fork(); 18 | if ($cpid) { 19 | $running++; 20 | print "Launched $cpid. Running $running threads.\n"; 21 | } else { 22 | stress($sock); 23 | exit 0; 24 | } 25 | } 26 | 27 | while ($running > 0) { 28 | wait(); 29 | print "stopped. Running $running threads.\n"; 30 | $running--; 31 | } 32 | 33 | sub stress { 34 | my $sock = shift; 35 | my $i; 36 | my $expire; 37 | for ($i = 0; $i < 5000000; $i++) { 38 | my $keyrand = int(rand(2000000)); 39 | my $valrand = int(rand(500)); 40 | my $key = "dash$keyrand"; 41 | my $val = "B" x $valrand; 42 | my $len = length($val); 43 | my $res; 44 | my $meth = int(rand(10)); 45 | if (($meth ge 0) and ($meth le 7)) { 46 | if ($meth le 4) { 47 | $expire = 30 + int(rand(30)); 48 | } elsif (($meth ge 5) and ($meth le 6)) { 49 | $expire = 120 + int(rand(300)); 50 | } else { 51 | $expire = 0; 52 | } 53 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 54 | $res = scalar <$sock>; 55 | if ($res ne "STORED\r\n") { 56 | print "set $key $len: $res\r\n"; 57 | } 58 | } elsif (($meth ge 8) and ($meth le 9)) { 59 | print $sock "get $key\r\n"; 60 | $res = scalar <$sock>; 61 | if ($res =~ /^VALUE/) { 62 | $res .= scalar(<$sock>) . scalar(<$sock>); 63 | } 64 | # print $sock "add $key 0 0 $len\r\n$val\r\n"; 65 | # $res = scalar <$sock>; 66 | # if (($res ne "STORED\r\n") and ($res ne "NOT_STORED\r\n")) { 67 | # print "add $key $len: $res\r\n"; 68 | # } 69 | } else { 70 | print $sock "delete $key\r\n"; 71 | $res = scalar <$sock>; 72 | if (($res ne "DELETED\r\n") and ($res ne "NOT_FOUND\r\n")) { 73 | print "delete $key: $res\r\n"; 74 | } 75 | } 76 | } 77 | print "stress end\n"; 78 | } 79 | 80 | #undef $server; 81 | -------------------------------------------------------------------------------- /isasl.h: -------------------------------------------------------------------------------- 1 | #ifndef ISASL_H 2 | #define ISASL_H 1 3 | 4 | #define SASL_CB_LIST_END 0 /* end of list */ 5 | 6 | #define SASL_USERNAME 0 /* pointer to NUL terminated user name */ 7 | #define ISASL_CONFIG 20 /* Just so we don't have to implement all the auxprop stuff */ 8 | 9 | typedef struct sasl_callback { 10 | unsigned long id; 11 | int (*proc)(void); 12 | void *context; 13 | } sasl_callback_t; 14 | 15 | typedef struct sasl_conn { 16 | char *username; 17 | char *config; 18 | } sasl_conn_t; 19 | 20 | typedef struct user_db_entry { 21 | char *username; 22 | char *password; 23 | char *config; 24 | struct user_db_entry *next; 25 | } user_db_entry_t; 26 | 27 | void sasl_dispose(sasl_conn_t **pconn); 28 | 29 | void sasl_done(void); 30 | 31 | int sasl_server_init(const sasl_callback_t *callbacks, 32 | const char *appname); 33 | 34 | int sasl_server_new(const char *service, 35 | const char *serverFQDN, 36 | const char *user_realm, 37 | const char *iplocalport, 38 | const char *ipremoteport, 39 | const sasl_callback_t *callbacks, 40 | unsigned flags, 41 | sasl_conn_t **pconn); 42 | 43 | int sasl_listmech(sasl_conn_t *conn, 44 | const char *user, 45 | const char *prefix, 46 | const char *sep, 47 | const char *suffix, 48 | const char **result, 49 | unsigned *plen, 50 | int *pcount); 51 | 52 | int sasl_server_start(sasl_conn_t *conn, 53 | const char *mech, 54 | const char *clientin, 55 | unsigned clientinlen, 56 | const char **serverout, 57 | unsigned *serveroutlen); 58 | 59 | int sasl_server_step(sasl_conn_t *conn, 60 | const char *clientin, 61 | unsigned clientinlen, 62 | const char **serverout, 63 | unsigned *serveroutlen); 64 | 65 | int sasl_getprop(sasl_conn_t *conn, int propnum, 66 | const void **pvalue); 67 | 68 | #define SASL_CONTINUE 1 69 | #define SASL_OK 0 70 | #define SASL_FAIL -1 /* generic failure */ 71 | #define SASL_NOMEM -2 /* memory shortage failure */ 72 | #define SASL_BADPARAM -7 /* invalid parameter supplied */ 73 | #define SASL_NOUSER -20 /* user not found */ 74 | 75 | #endif /* ISASL_H */ 76 | -------------------------------------------------------------------------------- /t/mgets.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 14; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | 17 | # set 18 | $cmd = "set key1 0 0 6"; $val = "value1"; $rst = "STORED"; 19 | mem_cmd_is($sock, $cmd, $val, $rst); 20 | $cmd = "set key2 0 0 6"; $val = "value2"; $rst = "STORED"; 21 | mem_cmd_is($sock, $cmd, $val, $rst); 22 | $cmd = "set key3 0 0 6"; $val = "value3"; $rst = "STORED"; 23 | mem_cmd_is($sock, $cmd, $val, $rst); 24 | $cmd = "set key4 0 0 6"; $val = "value4"; $rst = "STORED"; 25 | mem_cmd_is($sock, $cmd, $val, $rst); 26 | $cmd = "set key5 0 0 6"; $val = "value5"; $rst = "STORED"; 27 | mem_cmd_is($sock, $cmd, $val, $rst); 28 | 29 | 30 | # mgets (NEW command) 31 | $cmd = "mgets 24 5"; $val = "key1 key2 key3 key4 key5"; 32 | $rst = "VALUE key1 0 6 1 33 | value1 34 | VALUE key2 0 6 2 35 | value2 36 | VALUE key3 0 6 3 37 | value3 38 | VALUE key4 0 6 4 39 | value4 40 | VALUE key5 0 6 5 41 | value5 42 | END"; 43 | mem_cmd_is($sock, $cmd, $val, $rst); 44 | $cmd = "mgets 24 5"; $val = "key5 key4 key3 key2 key1"; 45 | $rst = "VALUE key5 0 6 5 46 | value5 47 | VALUE key4 0 6 4 48 | value4 49 | VALUE key3 0 6 3 50 | value3 51 | VALUE key2 0 6 2 52 | value2 53 | VALUE key1 0 6 1 54 | value1 55 | END"; 56 | mem_cmd_is($sock, $cmd, $val, $rst); 57 | $cmd = "mgets 29 6"; $val = "key1 key2 key3 key4 key5 key6"; 58 | $rst = "VALUE key1 0 6 1 59 | value1 60 | VALUE key2 0 6 2 61 | value2 62 | VALUE key3 0 6 3 63 | value3 64 | VALUE key4 0 6 4 65 | value4 66 | VALUE key5 0 6 5 67 | value5 68 | END"; 69 | mem_cmd_is($sock, $cmd, $val, $rst); 70 | $cmd = "mgets 29 6"; $val = "key6 key5 key4 key3 key2 key1"; 71 | $rst = "VALUE key5 0 6 5 72 | value5 73 | VALUE key4 0 6 4 74 | value4 75 | VALUE key3 0 6 3 76 | value3 77 | VALUE key2 0 6 2 78 | value2 79 | VALUE key1 0 6 1 80 | value1 81 | END"; 82 | mem_cmd_is($sock, $cmd, $val, $rst); 83 | 84 | # delete 85 | $cmd = "delete key1"; $rst ="DELETED"; 86 | mem_cmd_is($sock, $cmd, "", $rst); 87 | $cmd = "delete key2"; $rst ="DELETED"; 88 | mem_cmd_is($sock, $cmd, "", $rst); 89 | $cmd = "delete key3"; $rst ="DELETED"; 90 | mem_cmd_is($sock, $cmd, "", $rst); 91 | $cmd = "delete key4"; $rst ="DELETED"; 92 | mem_cmd_is($sock, $cmd, "", $rst); 93 | $cmd = "delete key5"; $rst ="DELETED"; 94 | mem_cmd_is($sock, $cmd, "", $rst); 95 | 96 | # after test 97 | release_memcached($engine, $server); 98 | 99 | 100 | -------------------------------------------------------------------------------- /arcus_zk.h: -------------------------------------------------------------------------------- 1 | /* 2 | * arcus-memcached - Arcus memory cache server 3 | * Copyright 2010-2014 NAVER Corp. 4 | * Copyright 2015 JaM2in Co., Ltd. 5 | * 6 | * Licensed under the Apache License, Version 2.0 (the "License"); 7 | * you may not use this file except in compliance with the License. 8 | * You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, software 13 | * distributed under the License is distributed on an "AS IS" BASIS, 14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | * See the License for the specific language governing permissions and 16 | * limitations under the License. 17 | */ 18 | #ifndef _ARCUS_H_ 19 | #define _ARCUS_H_ 20 | 21 | #include "config.h" 22 | #include "memcached/extension_loggers.h" 23 | #include "memcached/engine.h" 24 | 25 | #ifdef ENABLE_ZK_INTEGRATION 26 | 27 | typedef struct { 28 | const char *zk_libversion; // Zookeeper client version 29 | uint32_t zk_timeout; // Zookeeper session timeout (unit: ms) 30 | bool zk_failstop; // memcached automatic failstop 31 | } arcus_zk_confs; 32 | 33 | typedef struct { 34 | bool zk_connected; // ZooKeeper-memcached connection state 35 | bool zk_ready; // cache-list znode created? 36 | #ifdef ENABLE_ZK_RECONFIG 37 | bool zk_reconfig_needed; // ZK dynamic reconfig is needed? 38 | bool zk_reconfig_enabled; // ZK dynamic reconfig enabled in ZK? 39 | int64_t zk_reconfig_version; // ZK dynamic reconfig version 40 | #endif 41 | } arcus_zk_stats; 42 | 43 | /* Interface between memcached.c and arcus_zk.c */ 44 | 45 | void arcus_zk_init(char *ensemble_list, int zk_to, 46 | EXTENSION_LOGGER_DESCRIPTOR *logger, 47 | int verbose, size_t maxbytes, int port, 48 | #ifdef PROXY_SUPPORT 49 | char *proxy, 50 | #endif 51 | ENGINE_HANDLE_V1 *engine); 52 | void arcus_zk_final(const char *msg); 53 | void arcus_zk_destroy(void); 54 | 55 | int arcus_zk_set_ensemble(char *ensemble_list); 56 | int arcus_zk_get_ensemble(char *buf, int size); 57 | int arcus_zk_rejoin_ensemble(void); 58 | 59 | void arcus_zk_set_failstop(bool failstop); 60 | bool arcus_zk_get_failstop(void); 61 | void arcus_zk_get_confs(arcus_zk_confs *confs); 62 | void arcus_zk_get_stats(arcus_zk_stats *stats); 63 | 64 | bool arcus_zk_initalized(void); 65 | #ifdef ENABLE_CLUSTER_AWARE 66 | int arcus_key_is_mine(const char *key, size_t nkey, bool *mine); 67 | #endif 68 | 69 | #endif /* ENABLE_ZK_INTEGRATION */ 70 | 71 | #endif /* !defined(_ARCUS_H_) */ 72 | -------------------------------------------------------------------------------- /win32/config.h: -------------------------------------------------------------------------------- 1 | #ifndef _CONFIG_H 2 | #define _CONFIG_H 3 | 4 | /* Name of package */ 5 | #define PACKAGE "memcached" 6 | 7 | /* Define to the address where bug reports for this package should be sent. */ 8 | #define PACKAGE_BUGREPORT "memcached@googlegroups.com" 9 | 10 | /* Define to the full name of this package. */ 11 | #define PACKAGE_NAME "memcached" 12 | 13 | /* Define to the full name and version of this package. */ 14 | #define PACKAGE_DESCRIPTION "memcached is a high-performance, distributed memory object caching system, generic in nature, but intended for use in speeding up dynamic web applications by alleviating database load." 15 | 16 | /* Define to the one symbol short name of this package. */ 17 | #define PACKAGE_TARNAME "memcached" 18 | 19 | #include "config_version.h" 20 | 21 | /* Define to 1 if you have the ANSI C header files. */ 22 | #define STDC_HEADERS 1 23 | 24 | /* machine is littleendian */ 25 | #define ENDIAN_LITTLE 1 26 | 27 | #define ENABLE_ISASL 1 28 | 29 | #define HAVE_DLFCN_H 1 30 | 31 | #define HAVE_STDBOOL_H 32 | 33 | #include "config_static.h" 34 | 35 | /* Define to empty if `const' does not conform to ANSI C. */ 36 | /* #undef const */ 37 | 38 | /* define to int if socklen_t not available */ 39 | /* #undef socklen_t */ 40 | /* Windows-specific includes */ 41 | #include 42 | #include 43 | #include "win32.h" 44 | #include 45 | #include 46 | #include 47 | /* PRIu64 */ 48 | #include 49 | #include 50 | 51 | /*******************************/ 52 | /* HACKS to compile under UNIX */ 53 | 54 | #define S_ISSOCK(mode) 0 55 | #define RLIMIT_CORE 4 56 | #define RLIM_INFINITY ((unsigned long int) (-0UL)) 57 | #define RLIMIT_NOFILE 7 58 | 59 | /* Create expected type and struct definitions */ 60 | 61 | typedef short int _uid_t; 62 | 63 | struct passwd { 64 | char * pw_name; 65 | char * pw_passwd; 66 | _uid_t pw_uid; 67 | _uid_t pw_gid; 68 | char * pw_gecos; 69 | char * pw_dir; 70 | char * pw_shell; 71 | }; 72 | 73 | struct sockaddr_un { 74 | unsigned short int sun_family; 75 | char sun_path[108]; 76 | }; 77 | 78 | struct rlimit { 79 | unsigned long int rlim_cur, rlim_max; 80 | }; 81 | 82 | /* Function prototypes expected by UNIX code 83 | * - function definitions in dummy_defs.c 84 | */ 85 | 86 | int lstat(const char *path, struct stat *tstat); 87 | int getrlimit(int __resource, struct rlimit * __rlimits); 88 | int setrlimit(int __resource, struct rlimit * __rlimits); 89 | _uid_t getuid(void); 90 | _uid_t geteuid(void); 91 | struct passwd *getpwnam(const char *name); 92 | int setuid(_uid_t uid); 93 | int setgid(_uid_t gid); 94 | #endif // _CONFIG_H 95 | -------------------------------------------------------------------------------- /t/etc/too_many_eviction_issue.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 128; 12 | my $running = 0; 13 | 14 | # default engine start option : -m 512 15 | # example) ./memcached -E .libs/default_engine.so -X .libs/ascii_scrub.so -m 512 16 | 17 | while ($running < $threads) { 18 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 19 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 20 | my $cpid = fork(); 21 | if ($cpid) { 22 | $running++; 23 | print "Launched $cpid. Running $running threads.\n"; 24 | } else { 25 | data_load($sock); 26 | sleep(10); 27 | data_work($sock); 28 | exit 0; 29 | } 30 | } 31 | 32 | while ($running > 0) { 33 | wait(); 34 | print "stopped. Running $running threads.\n"; 35 | $running--; 36 | } 37 | 38 | sub data_load { 39 | my $sock = shift; 40 | my $i; 41 | my $expire; 42 | for ($i = 0; $i < 100000; $i++) { 43 | my $keyrand = int(rand(9000000)); 44 | my $valrand = 30 + int(rand(50)); 45 | my $key = "dash$keyrand"; 46 | my $val = "B" x $valrand; 47 | my $len = length($val); 48 | my $res; 49 | $expire = 86400; 50 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 51 | $res = scalar <$sock>; 52 | if ($res ne "STORED\r\n") { 53 | print "set $key $len: $res\r\n"; 54 | } 55 | } 56 | print "data_load end\n"; 57 | } 58 | 59 | sub data_work { 60 | my $sock = shift; 61 | my $i; 62 | my $expire; 63 | for ($i = 0; $i < 50000000; $i++) { 64 | my $keyrand = int(rand(900000000)); 65 | my $valrand = 120 + int(rand(20)); 66 | # my $valrand = 300 + int(rand(1000)); 67 | my $key = "dash$keyrand"; 68 | my $val = "B" x $valrand; 69 | my $len = length($val); 70 | my $res; 71 | my $meth = int(rand(10)); 72 | sleep(0.1); 73 | if (($meth ge 0) and ($meth le 7)) { 74 | $expire = 86400; 75 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 76 | $res = scalar <$sock>; 77 | if ($res ne "STORED\r\n") { 78 | print "set $key $len: $res\r\n"; 79 | } 80 | } else { 81 | print $sock "get $key\r\n"; 82 | $res = scalar <$sock>; 83 | if ($res =~ /^VALUE/) { 84 | $res .= scalar(<$sock>) . scalar(<$sock>); 85 | } 86 | } 87 | } 88 | print "data_work end\n"; 89 | } 90 | 91 | #undef $server; 92 | -------------------------------------------------------------------------------- /t/expirations.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 15; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $expire; 13 | my $cmd; 14 | my $val; 15 | my $rst; 16 | my $msg; 17 | 18 | sub wait_for_early_second { 19 | my $have_hires = eval "use Time::HiRes (); 1"; 20 | if ($have_hires) { 21 | my $tsh = Time::HiRes::time(); 22 | my $ts = int($tsh); 23 | return if ($tsh - $ts) < 0.5; 24 | } 25 | 26 | my $ts = int(time()); 27 | while (1) { 28 | my $t = int(time()); 29 | return if $t != $ts; 30 | select undef, undef, undef, 0.10; # 1/10th of a second sleeps until time changes. 31 | } 32 | } 33 | 34 | wait_for_early_second(); 35 | 36 | $cmd = "set foo 0 1 6"; $val = "fooval"; $rst = "STORED"; 37 | mem_cmd_is($sock, $cmd, $val, $rst); 38 | 39 | $cmd = "get foo"; 40 | $rst = "VALUE foo 0 6 41 | fooval 42 | END"; 43 | mem_cmd_is($sock, $cmd, "", $rst); 44 | sleep(1.5); 45 | $cmd = "get foo"; 46 | $rst = "END"; 47 | mem_cmd_is($sock, $cmd, "", $rst); 48 | 49 | $expire = time() - 1; 50 | $cmd = "set foo 0 $expire 6"; $val = "fooval"; $rst = "STORED"; 51 | mem_cmd_is($sock, $cmd, $val, $rst); 52 | $cmd = "get foo"; $rst = "END"; $msg = "already expired"; 53 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 54 | 55 | $expire = time() + 1; 56 | $cmd = "set foo 0 $expire 6"; $val = "foov+1"; $rst = "STORED"; 57 | mem_cmd_is($sock, $cmd, $val, $rst); 58 | $cmd = "get foo"; 59 | $rst = "VALUE foo 0 6 60 | foov+1 61 | END"; 62 | mem_cmd_is($sock, $cmd, "", $rst); 63 | sleep(2.2); 64 | $cmd = "get foo"; $rst = "END"; $msg = "now expired"; 65 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 66 | 67 | $expire = time() - 20; 68 | $cmd = "set boo 0 $expire 6"; $val = "booval"; $rst = "STORED"; 69 | mem_cmd_is($sock, $cmd, $val, $rst); 70 | $cmd = "get boo"; $rst = "END"; $msg = "now expired"; 71 | mem_cmd_is($sock, $cmd, "", $rst, $msg); 72 | 73 | $cmd = "add add 0 2 6"; $val = "addval"; $rst = "STORED"; 74 | mem_cmd_is($sock, $cmd, $val, $rst); 75 | $cmd = "get add"; 76 | $rst = "VALUE add 0 6 77 | addval 78 | END"; 79 | mem_cmd_is($sock, $cmd, "", $rst); 80 | # second add fails 81 | $cmd = "add add 0 2 7"; $val = "addval2"; $rst = "NOT_STORED"; $msg = "add failure"; 82 | mem_cmd_is($sock, $cmd, $val, $rst, $msg); 83 | sleep(2.3); 84 | $cmd = "add add 0 2 7"; $val = "addval3"; $rst = "STORED"; $msg = "stored add again"; 85 | mem_cmd_is($sock, $cmd, $val, $rst, $msg); 86 | $cmd = "get add"; 87 | $rst = "VALUE add 0 7 88 | addval3 89 | END"; 90 | mem_cmd_is($sock, $cmd, "", $rst); 91 | 92 | # after test 93 | release_memcached($engine, $server); 94 | -------------------------------------------------------------------------------- /t/noreply.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 20; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | my $cmd; 13 | my $val; 14 | my $rst; 15 | 16 | # Test that commands can take 'noreply' parameter. 17 | $rst = ""; 18 | $cmd = "flush_all noreply"; 19 | mem_cmd_is($sock, $cmd, "", $rst); 20 | $cmd = "flush_all 0 noreply"; 21 | mem_cmd_is($sock, $cmd, "", $rst); 22 | $cmd = "add noreply:foo 0 0 1 noreply"; $val = "1"; 23 | mem_cmd_is($sock, $cmd, $val, $rst); 24 | 25 | $cmd = "get noreply:foo"; 26 | $rst = "VALUE noreply:foo 0 1 27 | 1 28 | END"; 29 | mem_cmd_is($sock, $cmd, "", $rst); 30 | 31 | $cmd = "set noreply:foo 0 0 1 noreply"; $val = "2"; $rst = ""; 32 | mem_cmd_is($sock, $cmd, $val, $rst); 33 | $cmd = "get noreply:foo"; $val = "2"; 34 | $rst = "VALUE noreply:foo 0 1 35 | 2 36 | END"; 37 | mem_cmd_is($sock, $cmd, "", $rst); 38 | 39 | $cmd = "set noreply:foo 0 0 1 noreply"; $val = "3"; $rst = ""; 40 | mem_cmd_is($sock, $cmd, $val, $rst); 41 | $cmd = "get noreply:foo"; $val = "3"; 42 | $rst = "VALUE noreply:foo 0 1 43 | 3 44 | END"; 45 | mem_cmd_is($sock, $cmd, "", $rst); 46 | 47 | $cmd = "set noreply:foo 0 0 1 noreply"; $val = "4"; $rst = ""; 48 | mem_cmd_is($sock, $cmd, $val, $rst); 49 | $cmd = "get noreply:foo"; $val = "4"; 50 | $rst = "VALUE noreply:foo 0 1 51 | 4 52 | END"; 53 | mem_cmd_is($sock, $cmd, "", $rst); 54 | 55 | $cmd = "set noreply:foo 0 0 1 noreply"; $val = "5"; $rst = ""; 56 | mem_cmd_is($sock, $cmd, $val, $rst); 57 | $cmd = "get noreply:foo"; $val = "5"; 58 | $rst = "VALUE noreply:foo 0 1 59 | 5 60 | END"; 61 | mem_cmd_is($sock, $cmd, "", $rst); 62 | 63 | my @result = mem_gets($sock, "noreply:foo"); 64 | 65 | $cmd = "cas noreply:foo 0 0 1 $result[0] noreply"; $val = "6"; $rst = ""; 66 | mem_cmd_is($sock, $cmd, $val, $rst); 67 | $cmd = "get noreply:foo"; $val = "6"; 68 | $rst = "VALUE noreply:foo 0 1 69 | 6 70 | END"; 71 | mem_cmd_is($sock, $cmd, "", $rst); 72 | 73 | $cmd = "incr noreply:foo 3 noreply"; $rst = ""; 74 | mem_cmd_is($sock, $cmd, "", $rst); 75 | $cmd = "get noreply:foo"; $val = "9"; 76 | $rst = "VALUE noreply:foo 0 1 77 | 9 78 | END"; 79 | mem_cmd_is($sock, $cmd, "", $rst); 80 | 81 | $cmd = "decr noreply:foo 2 noreply"; $rst = ""; 82 | mem_cmd_is($sock, $cmd, "", $rst); 83 | $cmd = "get noreply:foo"; $val = "7"; 84 | $rst = "VALUE noreply:foo 0 1 85 | 7 86 | END"; 87 | mem_cmd_is($sock, $cmd, "", $rst); 88 | 89 | $cmd = "delete noreply:foo noreply"; $rst = ""; 90 | mem_cmd_is($sock, $cmd, "", $rst); 91 | $cmd = "get noreply:foo"; $rst = "END"; 92 | mem_cmd_is($sock, $cmd, "", $rst); 93 | 94 | # after test 95 | release_memcached($engine, $server); 96 | -------------------------------------------------------------------------------- /t/tlist/engine_default_b.txt: -------------------------------------------------------------------------------- 1 | ./t/coll_bop_large_tree.bt 2 | ./t/coll_bop_random_insert.bt 3 | ./t/coll_bop_position_test.bt 4 | ./t/coll_bop_smget_many_btrees.bt 5 | ./t/coll_lop_large_test.bt 6 | ./t/coll_mop_large_test.bt 7 | ./t/coll_scrub_stale.bt 8 | ./t/00-startup.t 9 | ./t/64bit.t 10 | ./t/arcus_ping_test.t 11 | ./t/ascii_ext_protocol.t 12 | ./t/binary_crash.t 13 | ./t/binary-get.t 14 | ./t/binary-sasl.t 15 | ./t/binary.t 16 | ./t/bogus-commands.t 17 | ./t/cas.t 18 | ./t/cmd_extensions.t 19 | ./t/coll_max_elembytes_test.t 20 | ./t/coll_bkeymismatch_test.t 21 | ./t/coll_bkeyoor_test.t 22 | ./t/coll_bop_attr_min_max_bkey.t 23 | ./t/coll_bop_count.t 24 | ./t/coll_bop_delete.t 25 | ./t/coll_bop_eflag.t 26 | ./t/coll_bop_get.t 27 | ./t/coll_bop_incrdecr.t 28 | ./t/coll_bop_insert_getrim.t 29 | ./t/coll_bop_insert.t 30 | ./t/coll_bop_maxbkeyrange.t 31 | ./t/coll_bop_mget_1.t 32 | ./t/coll_bop_mget_2.t 33 | ./t/coll_bop_smget_bkey_byte.t 34 | ./t/coll_bop_smget_bkey_uint.t 35 | ./t/coll_bop_smget_issues.t 36 | ./t/coll_bop_smget_trim_test.t 37 | ./t/coll_bop_smget_unique_test.t 38 | ./t/coll_bop_trimmed_test.t 39 | ./t/coll_bop_unittest.t 40 | ./t/coll_bop_update.t 41 | ./t/coll_bop_upsert.t 42 | ./t/coll_lop_large.t 43 | ./t/coll_lop_unittest.t 44 | ./t/coll_mop_delete.t 45 | ./t/coll_mop_get.t 46 | ./t/coll_mop_insert.t 47 | ./t/coll_mop_upsert.t 48 | ./t/coll_mop_update.t 49 | ./t/coll_pipeline_general.t 50 | ./t/coll_pipeline_sop_exist.t 51 | ./t/coll_readable_attr.t 52 | ./t/coll_sop_segfault_p012611.t 53 | ./t/coll_sop_unittest.t 54 | ./t/daemonize.t 55 | ./t/dash-M.t 56 | ./t/evictions.t 57 | ./t/expirations.t 58 | ./t/flags.t 59 | ./t/flush-prefix.t 60 | ./t/flush-all.t 61 | ./t/getset.t 62 | ./t/incrdecr.t 63 | ./t/issue_104.t 64 | ./t/issue_108.t 65 | ./t/issue_14.t 66 | ./t/issue_152.t 67 | ./t/issue_163.t 68 | ./t/issue_22.t 69 | ./t/issue_29.t 70 | ./t/issue_3.t 71 | ./t/issue_41.t 72 | ./t/issue_42.t 73 | ./t/issue_50.t 74 | ./t/issue_61.t 75 | ./t/issue_67.t 76 | ./t/issue_68.t 77 | ./t/issue_70.t 78 | ./t/issue_arcus_151.t 79 | ./t/issue_arcus_655.t 80 | ./t/issue_ee_599.t 81 | ./t/item_size_max.t 82 | ./t/line-lengths.t 83 | ./t/longkey.t 84 | ./t/long_query_detect_issue.t 85 | ./t/lru.t 86 | ./t/maxconns.t 87 | ./t/mget2.t 88 | ./t/mget.t 89 | ./t/mgets.t 90 | ./t/multiversioning.t 91 | ./t/noreply.t 92 | ./t/readable_expiretime.t 93 | ./t/scrub.t 94 | ./t/set_with_largest_slab.t 95 | ./t/stats-detail.t 96 | ./t/stats_prefixes.t 97 | ./t/stats.t 98 | ./t/topkeys.t 99 | ./t/udp.t 100 | ./t/unixsocket.t 101 | ./t/verbosity.t 102 | ./t/whitespace.t 103 | ./t/nested_prefix.t 104 | ./t/keyscan.t 105 | ./t/prefixscan.t 106 | ./t/touch.t 107 | -------------------------------------------------------------------------------- /t/coll_bkeymismatch_test.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 17; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | =head 10 | get bkey1 11 | bop create bkey1 1 0 0 12 | setattr bkey1 maxbkeyrange=0x1000 13 | bop insert bkey1 1 6 14 | datum2 15 | delete bkey1 16 | 17 | bop create bkey1 10 0 0 18 | bop insert bkey1 1 6 19 | datum2 20 | setattr bkey1 maxbkeyrange=0x1000 21 | delete bkey1 22 | 23 | bop create bkey1 1 0 0 24 | setattr bkey1 maxbkeyrange=10 25 | bop insert bkey1 0x0001 6 26 | datum2 27 | delete bkey1 28 | 29 | bop create bkey1 10 0 0 30 | bop insert bkey1 0x0011 6 31 | datum2 32 | setattr bkey1 maxbkeyrange=10 33 | delete bkey1 34 | =cut 35 | 36 | my $engine = shift; 37 | my $server = get_memcached($engine); 38 | my $sock = $server->sock; 39 | 40 | my $cmd; 41 | my $val; 42 | my $rst; 43 | 44 | # Initialize 45 | $cmd = "get bkey1"; $rst = "END"; 46 | mem_cmd_is($sock, $cmd, "", $rst); 47 | 48 | # Success Cases 49 | $cmd = "bop create bkey1 1 0 0"; $rst = "CREATED"; 50 | mem_cmd_is($sock, $cmd, "", $rst); 51 | $cmd = "setattr bkey1 maxbkeyrange=0x1000"; $rst = "OK"; 52 | mem_cmd_is($sock, $cmd, "", $rst); 53 | $cmd = "bop insert bkey1 1 6"; $val = "datum2"; $rst = "BKEY_MISMATCH"; 54 | mem_cmd_is($sock, $cmd, $val, $rst); 55 | 56 | # Finalize 57 | $cmd = "delete bkey1"; $rst = "DELETED"; 58 | mem_cmd_is($sock, $cmd, "", $rst); 59 | 60 | $cmd = "bop create bkey1 10 0 0"; $rst = "CREATED"; 61 | mem_cmd_is($sock, $cmd, "", $rst); 62 | $cmd = "bop insert bkey1 1 6"; $val = "datum2"; $rst = "STORED"; 63 | mem_cmd_is($sock, $cmd, $val, $rst); 64 | $cmd = "setattr bkey1 maxbkeyrange=0x1000"; $rst = "ATTR_ERROR bad value"; 65 | mem_cmd_is($sock, $cmd, "", $rst); 66 | 67 | # Finalize 68 | $cmd = "delete bkey1"; $rst = "DELETED"; 69 | mem_cmd_is($sock, $cmd, "", $rst); 70 | 71 | 72 | $cmd = "bop create bkey1 1 0 0"; $rst = "CREATED"; 73 | mem_cmd_is($sock, $cmd, "", $rst); 74 | $cmd = "setattr bkey1 maxbkeyrange=10"; $rst = "OK"; 75 | mem_cmd_is($sock, $cmd, "", $rst); 76 | $cmd = "bop insert bkey1 0x0001 6"; $val = "datum2"; $rst = "BKEY_MISMATCH"; 77 | mem_cmd_is($sock, $cmd, $val, $rst); 78 | 79 | # Finalize 80 | $cmd = "delete bkey1"; $rst = "DELETED"; 81 | mem_cmd_is($sock, $cmd, "", $rst); 82 | 83 | $cmd = "bop create bkey1 10 0 0"; $rst = "CREATED"; 84 | mem_cmd_is($sock, $cmd, "", $rst); 85 | $cmd = "bop insert bkey1 0x0011 6"; $val = "datum2"; $rst = "STORED"; 86 | mem_cmd_is($sock, $cmd, $val, $rst); 87 | $cmd = "setattr bkey1 maxbkeyrange=10"; $rst = "ATTR_ERROR bad value"; 88 | mem_cmd_is($sock, $cmd, "", $rst); 89 | 90 | # Finalize 91 | $cmd = "delete bkey1"; $rst = "DELETED"; 92 | mem_cmd_is($sock, $cmd, "", $rst); 93 | 94 | # after test 95 | release_memcached($engine, $server); 96 | -------------------------------------------------------------------------------- /t/etc/too_many_eviction_m_work.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 128; 12 | my $running = 0; 13 | 14 | # default engine start option : -m 512 15 | # example) ./memcached -E .libs/default_engine.so -X .libs/ascii_scrub.so -m 512 16 | 17 | while ($running < $threads) { 18 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 19 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 20 | my $cpid = fork(); 21 | if ($cpid) { 22 | $running++; 23 | print "Launched $cpid. Running $running threads.\n"; 24 | } else { 25 | data_work($sock); 26 | exit 0; 27 | } 28 | } 29 | 30 | while ($running > 0) { 31 | wait(); 32 | print "stopped. Running $running threads.\n"; 33 | $running--; 34 | } 35 | 36 | sub data_load { 37 | my $sock = shift; 38 | my $i; 39 | my $expire; 40 | for ($i = 0; $i < 100000; $i++) { 41 | my $keyrand = int(rand(9000000)); 42 | my $valrand = 30 + int(rand(50)); 43 | my $key = "dash$keyrand"; 44 | my $val = "B" x $valrand; 45 | my $len = length($val); 46 | my $res; 47 | $expire = 86400; 48 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 49 | $res = scalar <$sock>; 50 | if ($res ne "STORED\r\n") { 51 | print "set $key $len: $res\r\n"; 52 | } 53 | } 54 | print "data_load end\n"; 55 | } 56 | 57 | sub data_work { 58 | my $sock = shift; 59 | my $i; 60 | my $expire; 61 | for ($i = 0; $i < 50000000; $i++) { 62 | #my $keyrand = int(rand(9000000)); 63 | #my $valrand = 30 + int(rand(30)); 64 | my $keyrand = int(rand(90000000)); 65 | my $valrand = 100 + int(rand(100)); 66 | #my $keyrand = int(rand(900000000)); 67 | #my $valrand = 800 + int(rand(800)); 68 | my $key = "dash$keyrand"; 69 | my $val = "B" x $valrand; 70 | my $len = length($val); 71 | my $res; 72 | my $meth = int(rand(10)); 73 | if (($meth ge 0) and ($meth le 5)) { 74 | $expire = 86400; 75 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 76 | $res = scalar <$sock>; 77 | if ($res ne "STORED\r\n") { 78 | print "set $key $len: $res\r\n"; 79 | } 80 | } else { 81 | print $sock "get $key\r\n"; 82 | $res = scalar <$sock>; 83 | if ($res =~ /^VALUE/) { 84 | $res .= scalar(<$sock>) . scalar(<$sock>); 85 | } 86 | } 87 | } 88 | print "data_work end\n"; 89 | } 90 | 91 | #undef $server; 92 | -------------------------------------------------------------------------------- /deps/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | set -E 4 | trap "stop_build_and_install" ERR 5 | 6 | deps_path=$(dirname $0) 7 | libevent="libevent-2.1.12-stable" 8 | zookeeper="arcus-zookeeper-3.5.9-p3" 9 | cyrussasl="cyrus-sasl-2.1.28" 10 | 11 | ## Error handling 12 | stop_build_and_install() { 13 | echo -e "\nError has occurred. $0 has failed" 14 | echo "Check $deps_path/install.log" 15 | exit -1 16 | } 17 | 18 | ## Build and install function 19 | ## 20 | ## @param $1 dependency name 21 | ## @param $2 configure options 22 | build_and_install() { 23 | ## If the source directory of dependency already exists, remove it. 24 | if test -d $deps_path/$1 ; then 25 | rm -rf $deps_path/$1 26 | fi 27 | if [[ "$prefix" =~ "--prefix=$deps_path/$1" ]]; then 28 | echo "ERROR: Can't install to the same path which exists source files. ($deps_path/$1)" | tee $deps_path/install.log 29 | exit 1 30 | fi 31 | 32 | tar -xzf $deps_path/$1.tar.gz -C $deps_path/ >> $deps_path/install.log 2>&1 33 | pushd $deps_path/$1 > /dev/null 34 | echo -n "[$1 installation] .. START" 35 | echo -e "\n## LOG_RECORD [$1]\n" >> $deps_path/install.log 36 | ./configure $2 >> $deps_path/install.log 2>&1 37 | make >> $deps_path/install.log 2>&1 38 | make install >> $deps_path/install.log 2>&1 39 | rm -rf $deps_path/$1 > /dev/null 40 | popd > /dev/null 41 | echo -e "\r[$1 installation] .. SUCCEED" 42 | } 43 | 44 | ## If the path was not given, ask for prior consent about installation to system path. 45 | if [ -n "$1" ]; then 46 | set -- $(mkdir -p $1 && cd $1 && pwd) 47 | prefix="--prefix=$1" 48 | else 49 | echo "There is no argument given for the installation path." 50 | echo "After this operation, dependencies will be installed to system path." 51 | set -- "/usr/local" 52 | prefix="" 53 | fi 54 | 55 | ## Move to build.sh directory and 56 | ## convert relative path to absolute path 57 | pushd $deps_path > /dev/null 58 | deps_path=$PWD > $deps_path/install.log 59 | 60 | ## Information about installation 61 | echo "---------------------------------------------------" 62 | echo "ARCUS MEMCACHED DEPENDENCIES BUILD & INSTALL: START" 63 | echo "---------------------------------------------------" 64 | echo "INSTALL PATH : $1" 65 | echo "LOG PATH : $deps_path/install.log" 66 | echo "---------------------------------------------------" 67 | 68 | ## Install dependencies 69 | build_and_install $libevent "$prefix --disable-openssl" 70 | build_and_install $zookeeper $prefix 71 | build_and_install $cyrussasl $prefix 72 | 73 | popd > /dev/null 74 | 75 | echo "---------------------------------------------------" 76 | echo "ARCUS MEMCACHED DEPENDENCIES BUILD & INSTALL: END" 77 | echo "---------------------------------------------------" 78 | -------------------------------------------------------------------------------- /t/etc/stress-memcached.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | 4 | use strict; 5 | use lib '../../api/perl/lib'; 6 | use Cache::Memcached; 7 | use Time::HiRes qw(time); 8 | 9 | unless (@ARGV == 2) { 10 | die "Usage: stress-memcached.pl ip:port threads\n"; 11 | } 12 | 13 | my $host = shift; 14 | my $threads = shift; 15 | 16 | my $memc = new Cache::Memcached; 17 | $memc->set_servers([$host]); 18 | 19 | unless ($memc->set("foo", "bar") && 20 | $memc->get("foo") eq "bar") { 21 | die "memcached not running at $host ?\n"; 22 | } 23 | $memc->disconnect_all(); 24 | 25 | 26 | my $running = 0; 27 | while (1) { 28 | if ($running < $threads) { 29 | my $cpid = fork(); 30 | if ($cpid) { 31 | $running++; 32 | #print "Launched $cpid. Running $running threads.\n"; 33 | } else { 34 | stress(); 35 | exit 0; 36 | } 37 | } else { 38 | wait(); 39 | $running--; 40 | } 41 | } 42 | 43 | sub stress { 44 | undef $memc; 45 | $memc = new Cache::Memcached; 46 | $memc->set_servers([$host]); 47 | 48 | my ($t1, $t2); 49 | my $start = sub { $t1 = time(); }; 50 | my $stop = sub { 51 | my $op = shift; 52 | $t2 = time(); 53 | my $td = sprintf("%0.3f", $t2 - $t1); 54 | if ($td > 0.25) { print "Took $td seconds for: $op\n"; } 55 | }; 56 | 57 | my $max = rand(50); 58 | my $sets = 0; 59 | 60 | for (my $i = 0; $i < $max; $i++) { 61 | my $key = key($i); 62 | my $set = $memc->set($key, $key); 63 | $sets++ if $set; 64 | } 65 | 66 | for (1..int(rand(500))) { 67 | my $rand = int(rand($max)); 68 | my $key = key($rand); 69 | my $meth = int(rand(3)); 70 | my $exp = int(rand(3)); 71 | undef $exp unless $exp; 72 | $start->(); 73 | if ($meth == 0) { 74 | $memc->add($key, $key, $exp); 75 | $stop->("add"); 76 | } elsif ($meth == 1) { 77 | $memc->delete($key); 78 | $stop->("delete"); 79 | } else { 80 | $memc->set($key, $key, $exp); 81 | $stop->("set"); 82 | } 83 | $rand = int(rand($max)); 84 | $key = key($rand); 85 | $start->(); 86 | my $v = $memc->get($key); 87 | $stop->("get"); 88 | if ($v && $v ne $key) { die "Bogus: $v for key $rand\n"; } 89 | } 90 | 91 | $start->(); 92 | my $multi = $memc->get_multi(map { key(int(rand($max))) } (1..$max)); 93 | $stop->("get_multi"); 94 | } 95 | 96 | sub key { 97 | my $n = shift; 98 | $_ = sprintf("%04d", $n); 99 | if ($n % 2) { $_ .= "a"x20; } 100 | $_; 101 | } 102 | -------------------------------------------------------------------------------- /t/etc/too_many_eviction_l_work.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 128; 12 | my $running = 0; 13 | 14 | # default engine start option : -m 512 15 | # example) ./memcached -E .libs/default_engine.so -X .libs/ascii_scrub.so -m 512 16 | 17 | while ($running < $threads) { 18 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 19 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 20 | my $cpid = fork(); 21 | if ($cpid) { 22 | $running++; 23 | print "Launched $cpid. Running $running threads.\n"; 24 | } else { 25 | data_work($sock); 26 | exit 0; 27 | } 28 | } 29 | 30 | while ($running > 0) { 31 | wait(); 32 | print "stopped. Running $running threads.\n"; 33 | $running--; 34 | } 35 | 36 | sub data_load { 37 | my $sock = shift; 38 | my $i; 39 | my $expire; 40 | for ($i = 0; $i < 100000; $i++) { 41 | my $keyrand = int(rand(9000000)); 42 | my $valrand = 30 + int(rand(50)); 43 | my $key = "dash$keyrand"; 44 | my $val = "B" x $valrand; 45 | my $len = length($val); 46 | my $res; 47 | $expire = 86400; 48 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 49 | $res = scalar <$sock>; 50 | if ($res ne "STORED\r\n") { 51 | print "set $key $len: $res\r\n"; 52 | } 53 | } 54 | print "data_load end\n"; 55 | } 56 | 57 | sub data_work { 58 | my $sock = shift; 59 | my $i; 60 | my $expire; 61 | for ($i = 0; $i < 50000000; $i++) { 62 | #my $keyrand = int(rand(9000000)); 63 | #my $valrand = 30 + int(rand(30)); 64 | #my $keyrand = int(rand(90000000)); 65 | #my $valrand = 100 + int(rand(100)); 66 | my $keyrand = int(rand(900000000)); 67 | my $valrand = 800 + int(rand(800)); 68 | my $key = "dash$keyrand"; 69 | my $val = "B" x $valrand; 70 | my $len = length($val); 71 | my $res; 72 | my $meth = int(rand(10)); 73 | sleep(0.0001); 74 | if (($meth ge 0) and ($meth le 5)) { 75 | $expire = 86400; 76 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 77 | $res = scalar <$sock>; 78 | if ($res ne "STORED\r\n") { 79 | print "set $key $len: $res\r\n"; 80 | } 81 | } else { 82 | print $sock "get $key\r\n"; 83 | $res = scalar <$sock>; 84 | if ($res =~ /^VALUE/) { 85 | $res .= scalar(<$sock>) . scalar(<$sock>); 86 | } 87 | } 88 | } 89 | print "data_work end\n"; 90 | } 91 | 92 | #undef $server; 93 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Contributing 2 | Contribution 하기 위한 선행 작업으로 CLA(Contributor License Agreement)에 대해 3 | contributor의 sign이 필요합니다. 먼저, 아래 Apache CLA 내용을 자세히 읽어보시기 바랍니다. 4 | Apache CLA에 동의하시면 해당 CLA에 필수 사항 기재하고 sign하고 나서, singed CLA를 스캔한 이미지를 5 | junhyun.park@jam2in.com 메일 계정으로 보내 주시기 바랍니다. 6 | 7 | - [Apache ICLA(Individual Contributor License Agreement)](http://www.apache.org/licenses/icla.pdf) 8 | - [Apache CCLA(Corporate Contributor License Agreement)](http://www.apache.org/licenses/cla-corporate.txt) 9 | 10 | Contribution은 GitHub pull requests 방식을 사용해 주시기 바랍니다. 11 | 12 | ## Issues 13 | ARCUS-memcached 와 관련된 모든 사항(questing, bug report, feature proposal 등)을 자유롭게 issue로 등록 해 주세요. 14 | 새로운 issue를 생성하기 전 아래 사항을 고려해 주세요. 15 | - 생성하려는 issue가 이미 해결 되었는지 확인 하세요. 16 | - build가 실패했다면, [GitHub Actions CI status](https://github.com/naver/arcus-memcached/actions/workflows/CI.yml) 를 보고 현재 빌드 상태를 확인하세요. 17 | - 문제가 해결되지 않으면, 최대한 자세하게 설명 해주세요. 더 많은 정보를 제공할수록 빠른 해결이 가능합니다. 18 | 19 | ## Pull Requests 20 | ARCUS-memcached 의 최신 코드는 develop branch에 유지됩니다. 모든 PR은 develop branch를 기반으로 작성되어야 합니다. 21 | PR 작성 전에 다음 사항을 고려해 주세요. 22 | - 모든 변경은 develop branch를 기반으로 변경하고, develop branch로 요청 해주세요. 23 | - 모든 코드 파일에는 라이센스 주석 사본이 있어야 합니다. 기존 파일에서 복사할 수 있습니다. 24 | - 변경 범위가 큰 이슈일 경우 include/memcached/types.h 파일에 코드 태그를 생성하고 해당 태그를 이용하여 변경 코드들을 감싸주세요. 25 | - 새로운 기능을 추가하는 경우 해당 기능을 시험하는 unit test를 함께 작성해주세요. 26 | - PR 전 make test로 수행되는 unit test를 포함한 기본 테스트를 진행 해주세요. 27 | - 모든 소스 코드는 C coding style 를 기준으로 작성 해주시고, 같은 파일 내의 코드 수정은 파일 내 style을 따라주세요. 28 | - Commit message 작성은 "Classification: commit message" 형식을 지켜주세요. 29 | 30 | |Classification|내용| 31 | |:-------------|:----| 32 | |FIX|fix bugx| 33 | |FEATURE|new feature| 34 | |ENHANCE|enhancement or optimization| 35 | |CLEANUP|code cleanup, refactoring| 36 | |DOC|document related commit| 37 | |LEGAL|copylight, license 변경| 38 | |VERSION|version 변경| 39 | |TEST|add/remove/update tests| 40 | 41 | - 모든 PR은 담당자의 리뷰 후 반영됩니다. PR의 수정이 필요 할 경우 수정을 요청할 수 있습니다. 42 | 43 | ## Public Documents 44 | - [ARCUS 도입기](https://www.slideshare.net/JaM2in/arcus-190620954), ARCUS User Meetup 2019 Autumn 45 | - [ARCUS Persistence](https://www.slideshare.net/JaM2in/arcus-persistence), ARCUS User Meetup 2019 Autumn 46 | - [ARCUS & JaM2in, Replication, Java Client](https://www.slideshare.net/JaM2in/arcus-offline-meeting-2015-05-20-1), Offline metting 2015 47 | - [ARCUS 차별 기능, 사용 이슈 그리고 카카오 적용 사례](https://www.slideshare.net/JaM2in/arcus-offline-meeting-2015-05-20-1), DEVIEW 2014 48 | - [웹서비스 성능향상을 위한 오픈소스 Arcus 주요 기능과 활용 사례](https://www.slideshare.net/deview/2b3arcus), 네이버 오픈세미나 at 광주 49 | - [Arcus Collection 기능과 Open Source 전략](https://www.slideshare.net/deview/3aruc), Open Technet Summit 2014 50 | - [Arcus: NHN Memcached Cloud](https://www.slideshare.net/sdec2011/sdec2011-arcus-nhn-memcached-cloud-8467157), SDEC 2011 51 | -------------------------------------------------------------------------------- /t/etc/too_many_eviction_s_work.pl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/../lib"; 7 | use MemcachedTest; 8 | 9 | sleep 1; 10 | 11 | my $threads = 128; 12 | my $running = 0; 13 | 14 | # default engine start option : -m 512 15 | # example) ./memcached -E .libs/default_engine.so -X .libs/ascii_scrub.so -m 512 16 | 17 | while ($running < $threads) { 18 | # my $sock = IO::Socket::INET->new(PeerAddr => "$server->{host}:$server->{port}"); 19 | my $sock = IO::Socket::INET->new(PeerAddr => "localhost:11211"); 20 | my $cpid = fork(); 21 | if ($cpid) { 22 | $running++; 23 | print "Launched $cpid. Running $running threads.\n"; 24 | } else { 25 | data_work($sock); 26 | exit 0; 27 | } 28 | } 29 | 30 | while ($running > 0) { 31 | wait(); 32 | print "stopped. Running $running threads.\n"; 33 | $running--; 34 | } 35 | 36 | sub data_load { 37 | my $sock = shift; 38 | my $i; 39 | my $expire; 40 | for ($i = 0; $i < 100000; $i++) { 41 | my $keyrand = int(rand(9000000)); 42 | my $valrand = 30 + int(rand(50)); 43 | my $key = "dash$keyrand"; 44 | my $val = "B" x $valrand; 45 | my $len = length($val); 46 | my $res; 47 | $expire = 86400; 48 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 49 | $res = scalar <$sock>; 50 | if ($res ne "STORED\r\n") { 51 | print "set $key $len: $res\r\n"; 52 | } 53 | } 54 | print "data_load end\n"; 55 | } 56 | 57 | sub data_work { 58 | my $sock = shift; 59 | my $i; 60 | my $expire; 61 | for ($i = 0; $i < 50000000; $i++) { 62 | #my $keyrand = int(rand(9000000)); 63 | my $keyrand = int(rand(90000000)); 64 | my $valrand = 30 + int(rand(30)); 65 | #my $keyrand = int(rand(90000000)); 66 | #my $valrand = 100 + int(rand(100)); 67 | #my $keyrand = int(rand(900000000)); 68 | #my $valrand = 800 + int(rand(800)); 69 | my $key = "dash$keyrand"; 70 | my $val = "B" x $valrand; 71 | my $len = length($val); 72 | my $res; 73 | my $meth = int(rand(10)); 74 | if (($meth ge 0) and ($meth le 5)) { 75 | $expire = 86400; 76 | print $sock "set $key 0 $expire $len\r\n$val\r\n"; 77 | $res = scalar <$sock>; 78 | if ($res ne "STORED\r\n") { 79 | print "set $key $len: $res\r\n"; 80 | } 81 | } else { 82 | print $sock "get $key\r\n"; 83 | $res = scalar <$sock>; 84 | if ($res =~ /^VALUE/) { 85 | $res .= scalar(<$sock>) . scalar(<$sock>); 86 | } 87 | } 88 | } 89 | print "data_work end\n"; 90 | } 91 | 92 | #undef $server; 93 | -------------------------------------------------------------------------------- /t/coll_max_elembytes_test.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 19; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $cmd; 14 | my $rst; 15 | 16 | my $max16 = 16*1024; 17 | my $val16len = $max16 - 2; 18 | my $val16; 19 | for (1..$val16len) { $val16 .= chr( int(rand(25) + 65) ); } 20 | 21 | my $max32 = 32*1024; 22 | my $val32len = $max32 - 2; 23 | my $val32; 24 | for (1..$val32len) { $val32 .= chr( int(rand(25) + 65) ); } 25 | 26 | $cmd = "config max_element_bytes $max16"; $rst = "END"; 27 | mem_cmd_is($sock, $cmd, "", $rst); 28 | $rst = "CREATED_STORED"; 29 | $cmd = "lop insert lkey1 0 $val16len create 11 0 0"; 30 | mem_cmd_is($sock, $cmd, $val16, $rst); 31 | $cmd = "sop insert skey1 $val16len create 11 0 0"; 32 | mem_cmd_is($sock, $cmd, $val16, $rst); 33 | $cmd = "mop insert mkey1 0 $val16len create 11 0 0"; 34 | mem_cmd_is($sock, $cmd, $val16, $rst); 35 | $cmd = "bop insert bkey1 0 $val16len create 11 0 0"; 36 | mem_cmd_is($sock, $cmd, $val16, $rst); 37 | $rst = "CLIENT_ERROR too large value"; 38 | $cmd = "lop insert lkey2 0 $val32len create 11 0 0"; 39 | mem_cmd_is($sock, $cmd, $val32, $rst); 40 | $cmd = "sop insert skey2 $val32len create 11 0 0"; 41 | mem_cmd_is($sock, $cmd, $val32, $rst); 42 | $cmd = "mop insert mkey2 0 $val32len create 11 0 0"; 43 | mem_cmd_is($sock, $cmd, $val32, $rst); 44 | $cmd = "bop insert bkey2 0 $val32len create 11 0 0"; 45 | mem_cmd_is($sock, $cmd, $val32, $rst); 46 | 47 | $cmd = "config max_element_bytes $max32"; $rst = "END"; 48 | mem_cmd_is($sock, $cmd, "", $rst); 49 | $rst = "CREATED_STORED"; 50 | $cmd = "lop insert lkey3 0 $val32len create 11 0 0"; 51 | mem_cmd_is($sock, $cmd, $val32, $rst); 52 | $cmd = "sop insert skey3 $val32len create 11 0 0"; 53 | mem_cmd_is($sock, $cmd, $val32, $rst); 54 | $cmd = "mop insert mkey3 0 $val32len create 11 0 0"; 55 | mem_cmd_is($sock, $cmd, $val32, $rst); 56 | $cmd = "bop insert bkey3 0 $val32len create 11 0 0"; 57 | mem_cmd_is($sock, $cmd, $val32, $rst); 58 | 59 | $val16 = ""; 60 | for (1..$val16len) { $val16 .= 'a' ; } 61 | 62 | $val32 = ""; 63 | for (1..$val32len) { $val32 .= 'b'; } 64 | 65 | $cmd = "bop create bkey4 11 0 0"; $rst="CREATED"; 66 | mem_cmd_is($sock, $cmd, "", $rst); 67 | $rst = "STORED"; 68 | $cmd = "bop insert bkey4 0 $val16len"; 69 | mem_cmd_is($sock, $cmd, $val16, $rst); 70 | $cmd = "bop insert bkey4 1 $val32len"; 71 | mem_cmd_is($sock, $cmd, $val32, $rst); 72 | $cmd = "bop get bkey4 0"; 73 | $rst = "VALUE 11 1 74 | 0 $val16len $val16 75 | END"; 76 | mem_cmd_is($sock, $cmd, "", $rst); 77 | $cmd = "bop get bkey4 1"; 78 | $rst = "VALUE 11 1 79 | 1 $val32len $val32 80 | END"; 81 | mem_cmd_is($sock, $cmd, "", $rst); 82 | 83 | # after test 84 | release_memcached($engine, $server); 85 | -------------------------------------------------------------------------------- /t/item_size_max.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More tests => 5; 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $stats = mem_stats($sock, ' settings'); 14 | 15 | # Ensure default still works. 16 | is($stats->{item_size_max}, 1024 * 1024); 17 | $server->stop(); 18 | 19 | ### [ARCUS] CHANGED FOLLOWING TEST ### 20 | # The small memory allocator allocates chunk memory from existing slab allocator. 21 | # And, the chunk memory size is about 17MB. 22 | # Therefore, the minimum item size is changed from 1KB to 20KB. 23 | ###################################### 24 | 25 | # Should die. 26 | ### [ARCUS] CHANGED FOLLOWING TEST ### 27 | #eval { 28 | # $server = get_memcached($engine, '-I 1000'); 29 | #}; 30 | #ok($@ && $@ =~ m/^Failed/, "Shouldn't start with < 1k item max"); 31 | eval { 32 | $server = get_memcached($engine, '-I 20000'); 33 | }; 34 | ok($@ && $@ =~ m/^Failed/, "Shouldn't start with < 20k item max"); 35 | ###################################### 36 | 37 | eval { 38 | $server = get_memcached($engine, '-I 256m'); 39 | }; 40 | ok($@ && $@ =~ m/^Failed/, "Shouldn't start with > 128m item max"); 41 | 42 | # Minimum. 43 | ### [ARCUS] CHANGED FOLLOWING TEST ### 44 | #$server = get_memcached($engine, '-I 1024'); 45 | $server = get_memcached($engine, '-I 20480'); 46 | my $stats = mem_stats($server->sock, ' settings'); 47 | #is($stats->{item_size_max}, 1024); 48 | is($stats->{item_size_max}, 20480); 49 | $server->stop(); 50 | ###################################### 51 | 52 | # Reasonable but unreasonable. 53 | =pod 54 | $server = get_memcached($engine, '-I 1049600'); 55 | my $stats = mem_stats($server->sock, ' settings'); 56 | is($stats->{item_size_max}, 1049600); 57 | $server->stop(); 58 | =cut 59 | 60 | # Suffix kilobytes. 61 | $server = get_memcached($engine, '-I 512k'); 62 | my $stats = mem_stats($server->sock, ' settings'); 63 | is($stats->{item_size_max}, 524288); 64 | $server->stop(); 65 | 66 | # Suffix megabytes. 67 | =pod 68 | $server = get_memcached($engine, '-I 32m'); 69 | my $stats = mem_stats($server->sock, ' settings'); 70 | is($stats->{item_size_max}, 33554432); 71 | $server->stop(); 72 | =cut 73 | 74 | # Test sets up to a large size around 2MB. 75 | # Fot the time being, we disable the test below. 76 | =pod 77 | $server = get_memcached($engine, '-I 2m'); 78 | my $stats = mem_stats($server->sock, ' settings'); 79 | is($stats->{item_size_max}, 2097152); 80 | my $added_len = 128; # keylen + item meta size 81 | my $len = 2 * 1024 * 1024 - $added_len; 82 | my $val = "B"x$len; 83 | my $cmd = "set foo_$len 0 0 $len"; 84 | my $rst = "STORED"; 85 | my $msg = "stored size $len"; 86 | mem_cmd_is($server->sock, $cmd, $val, $rst); 87 | $server->stop(); 88 | =cut 89 | 90 | # after test 91 | release_memcached($engine, $server); 92 | -------------------------------------------------------------------------------- /t/keyscan.t: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | 3 | use strict; 4 | use Test::More; # see done_testing() 5 | use FindBin qw($Bin); 6 | use lib "$Bin/lib"; 7 | use MemcachedTest; 8 | 9 | my $engine = shift; 10 | my $server = get_memcached($engine); 11 | my $sock = $server->sock; 12 | 13 | my $cmd; 14 | my $key; 15 | my $rst; 16 | my $val = "val"; 17 | my $vlen = length($val); 18 | my @keyarr1 = (); 19 | my @keyarr2 = (); 20 | 21 | # SET ITEMS 22 | $key = "aa\\*aaa"; 23 | $cmd = "set $key 0 1000 $vlen"; $rst = "STORED"; 24 | mem_cmd_is($sock, $cmd, $val, $rst); 25 | push(@keyarr1, $key); 26 | $key = "bb\\*aab"; 27 | $cmd = "set $key 0 1000 $vlen"; $rst = "STORED"; 28 | mem_cmd_is($sock, $cmd, $val, $rst); 29 | push(@keyarr1, $key); 30 | $key = "c?\\*aaba"; 31 | $cmd = "set $key 0 1000 $vlen"; $rst = "STORED"; 32 | mem_cmd_is($sock, $cmd, $val, $rst); 33 | push(@keyarr1, $key); 34 | push(@keyarr2, $key); 35 | $key = "d?\\*abba"; 36 | $cmd = "set $key 0 1000 $vlen"; $rst = "STORED"; 37 | mem_cmd_is($sock, $cmd, $val, $rst); 38 | push(@keyarr1, $key); 39 | push(@keyarr2, $key); 40 | $key = "a?\\*aaaaa"; 41 | $cmd = "bop create $key 0 1000 3"; $rst = "CREATED"; 42 | mem_cmd_is($sock, $cmd, "", $rst); 43 | push(@keyarr1, $key); 44 | $key = "a?\\*aaaa"; 45 | $cmd = "sop create $key 0 1000 3"; $rst = "CREATED"; 46 | mem_cmd_is($sock, $cmd, "", $rst); 47 | push(@keyarr1, $key); 48 | 49 | # KEYSCAN 50 | my @scankeys = keyscan($sock, "0", 2000, "*", "A"); 51 | Test::More::is(scalar(@scankeys), scalar(@keyarr1)); 52 | my %keyset = map { $_ => 1 } @keyarr1; 53 | foreach $_ ( @scankeys ) { 54 | print("$_\n"); 55 | my ($key) = split(' ', $_); 56 | Test::More::ok(exists($keyset{$key})); 57 | } 58 | 59 | @scankeys = keyscan($sock, "0", 2000, "?\\?\\\\\\**a", "K"); 60 | Test::More::is(scalar(@scankeys), scalar(@keyarr2)); 61 | %keyset = map { $_ => 1 } @keyarr2; 62 | foreach $_ ( @scankeys ) { 63 | print("$_\n"); 64 | my ($key) = split(' ', $_); 65 | Test::More::ok(exists($keyset{$key})); 66 | } 67 | 68 | # FAIL CASES 69 | $cmd = "scan key a"; $rst = "CLIENT_ERROR invalid cursor."; 70 | mem_cmd_is($sock, $cmd, "", $rst); 71 | 72 | $cmd = "scan key 0 count 2001"; $rst = "CLIENT_ERROR bad count value"; 73 | mem_cmd_is($sock, $cmd, "", $rst); 74 | 75 | $cmd = "scan key 0 type V"; $rst = "CLIENT_ERROR bad item type"; 76 | mem_cmd_is($sock, $cmd, "", $rst); 77 | 78 | $cmd = "scan key 0 match ***asdds\\***"; $rst = "CLIENT_ERROR bad pattern string"; 79 | mem_cmd_is($sock, $cmd, "", $rst); 80 | 81 | $cmd = "scan key 0 match \\"; $rst = "CLIENT_ERROR bad pattern string"; 82 | mem_cmd_is($sock, $cmd, "", $rst); 83 | 84 | my $key = "a" x 65; 85 | $cmd = "scan key 0 match $key"; $rst = "CLIENT_ERROR bad pattern string"; 86 | mem_cmd_is($sock, $cmd, "", $rst); 87 | 88 | # It's difficult to calculate how many tests were run in keyscan() 89 | done_testing(); 90 | 91 | # after test 92 | release_memcached($engine, $server); 93 | --------------------------------------------------------------------------------