{"id":1842,"date":"2014-12-16T17:36:14","date_gmt":"2014-12-16T17:36:13","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1842"},"modified":"2014-12-16T17:36:14","modified_gmt":"2014-12-16T17:36:13","slug":"writing-your-own-storage-engine-memcached","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/","title":{"rendered":"Writing Your Own Storage Engine for Memcached"},"content":{"rendered":"<div class=\"post-body entry-content\">\n<p>I am working full time on <a href=\"https:\/\/membase.org\/\"><u><font color=\"#de7008\">membase<\/font><\/u><\/a>, which utilize the &#8220;<a href=\"https:\/\/github.com\/trondn\/memcached\/blob\/engine\/include\/memcached\/engine.h#L212\"><u><font color=\"#de7008\">engine interface<\/font><\/u><\/a>&#8221; we&#39;re adding to <a href=\"https:\/\/www.memcached.org\/\"><u><font color=\"#de7008\">Memcached<\/font><\/u><\/a>. Being the one who designed the API and wrote the documentation, I can say that we do need more (and better) documentation without insulting anyone. This blog entry will be the first entry in mini-tutorial on how to write your own storage engine. I will try to cover all aspects of the engine interface while we&#39;re building an engine that stores all of the keys on files on the server.<\/p>\n<p>This entry will cover the basic steps of setting up your development environment and cover the lifecycle of the engine.<\/p>\n<h3>Set up the development environment<\/h3>\n<p>The easiest way to get &#8220;up&#39;n&#39;running&#8221; is to install my development branch of the engine interface. Just execute the following commands:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">$ git clone git:\/\/github.com\/trondn\/memcached.git<br \/>\n$ cd memcached<br \/>\n$ git -b engine origin\/engine<br \/>\n$ .\/config\/autorun.sh<br \/>\n$ .\/configure &#8211;prefix=\/opt\/memcached<br \/>\n$ make all install<br \/>\n\u00a0 \u00a0 \u00a0<\/div>\n<\/div>\n<p>Lets verify that the server works by executing the following commands:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">$ \/opt\/memcached\/bin\/memcached -E default_engine.so &#038;<br \/>\n$ echo version | nc localhost 11211<br \/>\nVERSION 1.3.3_433_g82fb476 \u00a0 \u00a0 &lg;&#8211; you may get another output string&#8230;.<br \/>\n$ fg<br \/>\n$ ctrl-C<\/div>\n<\/div>\n<h3>Creating the filesystem engine<\/h3>\n<p>You might want to use autoconf to build your engine, but setting up autoconf is way beyond the scope of this tutorial. Let&#39;s just use the following <code><font color=\"#999999\">Makefile<\/font><\/code> instead.<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">ROOT=\/opt\/memcached<br \/>\nINCLUDE=-I${ROOT}\/include<\/p>\n<p>#CC = gcc<br \/>\n#CFLAGS=-std=gnu99 -g -DNDEBUG -fno-strict-aliasing -Wall <br \/>\n# -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations <br \/>\n# -Wredundant-decls <br \/>\n# ${INCLUDE} -DHAVE_CONFIG_H<br \/>\n#LDFLAGS=-shared<\/p>\n<p>CC=cc<br \/>\nCFLAGS=-I${ROOT}\/include -m64 -xldscope=hidden -mt -g <br \/>\n\u00a0 \u00a0 \u00a0 -errfmt=error -errwarn -errshort=tags \u00a0-KPIC<br \/>\nLDFLAGS=-G -z defs -m64 -mt<\/p>\n<p>all: .libs\/fs_engine.so<\/p>\n<p>install: all<br \/>\n\u00a0${CP} .libs\/fs_engine.so ${ROOT}\/lib<\/p>\n<p>SRC = fs_engine.c<br \/>\nOBJS = ${SRC:%.c=.libs\/%.o}<\/p>\n<p>.libs\/fs_engine.so: .libs $(OBJS)<br \/>\n\u00a0${LINK.c} -o $@ ${OBJS}<\/p>\n<p>.libs:; -@mkdir $@<\/p>\n<p>.libs\/%.o: %.c<br \/>\n\u00a0${COMPILE.c} $< -o $@ \u00a0 clean: \u00a0$(RM) .libs\/fs_engine.so $(OBJS) \u00a0 \u00a0 \u00a0<\/div>\n<\/div>\n<p>I am doing most of my development on Solaris using the Sun Studio compilers, but I have added a section with settings for gcc there if you&#39;re using gcc. Just comment out lines for <code><font color=\"#999999\">CC<\/font><\/code>, <code><font color=\"#999999\">CFLAGS<\/font><\/code> and <code><font color=\"#999999\">LDFLAGS<\/font><\/code> and remove the <code><font color=\"#999999\">#<\/font><\/code> for the gcc alternatives.<\/p>\n<p>In order for memcached to utilize your storage engine it needs to first load your module, and then create an instance the engine. You use the <code><font color=\"#999999\">-E<\/font><\/code> option to memcached to specify the name of the module memcached should load. With the module loaded memcached will look for a symbol named <code><font color=\"#999999\">create_instance<\/font><\/code> in the module to create an handle memcached can use to communicate with the engine. This is the first function we need to create, and it should have the following signature:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">MEMCACHED_PUBLIC_API<br \/>\nENGINE_ERROR_CODE create_instance(uint64_t interface, GET_SERVER_API get_server_api, ENGINE_HANDLE **handle);<br \/>\n\u00a0 \u00a0 \u00a0<\/div>\n<\/div>\n<p>The purpose of this function is to provide the server a handle to our module, but we should <b>not<\/b> perform any kind of initialization of our engine yet. The reason for that is because the memcached server may not support the version of the API we provide. The intention is that the server should notify the engine with the &#8220;highest&#8221; interface version it supports through <code><font color=\"#999999\">interface<\/font><\/code>, and the engine <b>must<\/b> return a descriptor to one of those interfaces through the <code><font color=\"#999999\">handle<\/font><\/code>. If the engine <b>don&#39;t<\/b> support any of those interfaces it should return <code><font color=\"#999999\">ENGINE_ENOTSUP<\/font><\/code>.<\/p>\n<p>So let&#39;s go ahead and define a engine descriptor for our example engine and create an implementation for <code><font color=\"#999999\">create_instance<\/font><\/code>:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">struct fs_engine {<br \/>\n\u00a0 ENGINE_HANDLE_V1 engine;<br \/>\n\u00a0 \/* We&#39;re going to extend this structure later on *\/<br \/>\n};<\/p>\n<p>MEMCACHED_PUBLIC_API<br \/>\nENGINE_ERROR_CODE create_instance(uint64_t interface,<br \/>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0GET_SERVER_API get_server_api,<br \/>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0ENGINE_HANDLE **handle) {<br \/>\n\u00a0 \/*<br \/>\n\u00a0 \u00a0* Verify that the interface from the server is one we support. Right now<br \/>\n\u00a0 \u00a0* there is only one interface, so we would accept all of them (and it would<br \/>\n\u00a0 \u00a0* be up to the server to refuse us&#8230; I&#39;m adding the test here so you<br \/>\n\u00a0 \u00a0* get the picture..<br \/>\n\u00a0 \u00a0*\/<br \/>\n\u00a0 if (interface == 0) {<br \/>\n\u00a0 \u00a0 \u00a0return ENGINE_ENOTSUP;<br \/>\n\u00a0 }<\/p>\n<p>\u00a0 \/*<br \/>\n\u00a0 \u00a0* Allocate memory for the engine descriptor. I&#39;m no big fan of using<br \/>\n\u00a0 \u00a0* global variables, because that might create problems later on if<br \/>\n\u00a0 \u00a0* we later on decide to create multiple instances of the same engine.<br \/>\n\u00a0 \u00a0* Better to be on the safe side from day one&#8230;<br \/>\n\u00a0 \u00a0*\/<br \/>\n\u00a0 struct fs_engine *h = calloc(1, sizeof(*h));<br \/>\n\u00a0 if (h == NULL) {<br \/>\n\u00a0 \u00a0 \u00a0return ENGINE_ENOMEM;<br \/>\n\u00a0 }<\/p>\n<p>\u00a0 \/*<br \/>\n\u00a0 \u00a0* We&#39;re going to implement the first version of the engine API, so<br \/>\n\u00a0 \u00a0* we need to inform the memcached core what kind of structure it should<br \/>\n\u00a0 \u00a0* expect<br \/>\n\u00a0 \u00a0*\/<br \/>\n\u00a0 h->engine.interface.interface = 1;<\/p>\n<p>\u00a0 \/*<br \/>\n\u00a0 \u00a0* Map the API entry points to our functions that implement them.<br \/>\n\u00a0 \u00a0*\/<br \/>\n\u00a0 h->engine.initialize = fs_initialize;<br \/>\n\u00a0 h->engine.destroy = fs_destroy;<\/p>\n<p>\u00a0 \/* Pass the handle back to the core *\/<br \/>\n\u00a0 *handle = (ENGINE_HANDLE*)h;<\/p>\n<p>\u00a0 return ENGINE_SUCCESS;<br \/>\n}<br \/>\n\u00a0 \u00a0 \u00a0<\/div>\n<\/div>\n<p>If the interface we provide in <code><font color=\"#999999\">create_instance<\/font><\/code> is dropped from the supported interfaces in memcached, the core will call <code><font color=\"#999999\">destroy()<\/font><\/code> immediately. The memcached core guarantees that it will never use <b>any<\/b> pointers returned from the engine when <code><font color=\"#999999\">destroy()<\/font><\/code> is called.<\/p>\n<p>So let&#39;s go ahead and implement our <code><font color=\"#999999\">destroy()<\/font><\/code> function. If you look at our implementation of <code><font color=\"#999999\">create_instance<\/font><\/code> you will see that we mapped <code><font color=\"#999999\">destroy()<\/font><\/code> to a function named <code><font color=\"#999999\">fs_destroy()<\/font><\/code>:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">static void fs_destroy(ENGINE_HANDLE* handle) {<br \/>\n\u00a0 \/* Release the memory allocated for the engine descriptor *\/<br \/>\n\u00a0 free(handle);<br \/>\n}<br \/>\n\u00a0 \u00a0 \u00a0<\/div>\n<\/div>\n<p>If the core implements the interface we specify, the core will call a the <code><font color=\"#999999\">initialize()<\/font><\/code> method. This is the time where you should do all sort of initialization in your engine (like connecting to a database, initializing mutexes etc). The <code><font color=\"#999999\">initialize<\/font><\/code> function is called only once per instance returned from <code><font color=\"#999999\">create_instance<\/font><\/code> (even if the memcached core use multiple threads). The core will <b>not<\/b> call any other functions in the api before the initialization method returns.<\/p>\n<p>We don&#39;t need any kind of initialization at this moment, so we can use the following initialization code:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">static ENGINE_ERROR_CODE fs_initialize(ENGINE_HANDLE* handle,<br \/>\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const char* config_str) {<br \/>\n\u00a0 return ENGINE_SUCCESS;<br \/>\n}<br \/>\n\u00a0 \u00a0 \u00a0<\/div>\n<\/div>\n<p>If the engine returns anything else than <code><font color=\"#999999\">ENGINE_SUCCESS<\/font><\/code>, the memcached core will refuse to use the engine and call <code><font color=\"#999999\">destroy()<\/font><\/code><\/p>\n<p>In the next blog entry we will start adding functionality so that we can load our engine and handle commands from the client.<\/p>\n<div style=\"clear: both\">\u00a0<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>I am working full time on membase, which utilize the &#8220;engine interface&#8221; we&#39;re adding to Memcached. Being the one who designed the API and wrote the documentation, I can say that we do need more (and better) documentation without insulting [&hellip;]<\/p>\n","protected":false},"author":14,"featured_media":13873,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"ppma_author":[8981],"class_list":["post-1842","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v25.9 (Yoast SEO v25.9) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Writing Your Own Storage Engine for Memcached - The Couchbase Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Writing Your Own Storage Engine for Memcached\" \/>\n<meta property=\"og:description\" content=\"I am working full time on membase, which utilize the &#8220;engine interface&#8221; we&#039;re adding to Memcached. Being the one who designed the API and wrote the documentation, I can say that we do need more (and better) documentation without insulting [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2014-12-16T17:36:13+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/11\/couchbase-nosql-dbaas.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1800\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Trond Norbye, Senior Developer, Couchbase\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Trond Norbye, Senior Developer, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/\"},\"author\":{\"name\":\"Trond Norbye, Senior Developer, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ef0f9ff42d878c2fc0ab3a685e96f36d\"},\"headline\":\"Writing Your Own Storage Engine for Memcached\",\"datePublished\":\"2014-12-16T17:36:13+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/\"},\"wordCount\":1030,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/\",\"name\":\"Writing Your Own Storage Engine for Memcached - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2014-12-16T17:36:13+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#primaryimage\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"width\":1800,\"height\":630},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/www.couchbase.com\/blog\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Writing Your Own Storage Engine for Memcached\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"name\":\"The Couchbase Blog\",\"description\":\"Couchbase, the NoSQL Database\",\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\/\/www.couchbase.com\/blog\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"contentUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png\",\"width\":218,\"height\":34,\"caption\":\"The Couchbase Blog\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ef0f9ff42d878c2fc0ab3a685e96f36d\",\"name\":\"Trond Norbye, Senior Developer, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/03d13b4ab5eaa14c91cab7658f04df07\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/bf3c00ca228efa25f7bfc168f566d6389279b44d4bbba4683c260a8bf33da03d?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/bf3c00ca228efa25f7bfc168f566d6389279b44d4bbba4683c260a8bf33da03d?s=96&d=mm&r=g\",\"caption\":\"Trond Norbye, Senior Developer, Couchbase\"},\"description\":\"Trond Norbye is a Software Architect at Couchbase. Core contributor to Couchbase &amp; Memcached projects. Created the C\/C++ &amp; node.js Couchbase client libraries.\",\"url\":\"https:\/\/www.couchbase.com\/blog\/author\/trond-norbye\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Writing Your Own Storage Engine for Memcached - The Couchbase Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/","og_locale":"en_US","og_type":"article","og_title":"Writing Your Own Storage Engine for Memcached","og_description":"I am working full time on membase, which utilize the &#8220;engine interface&#8221; we&#39;re adding to Memcached. Being the one who designed the API and wrote the documentation, I can say that we do need more (and better) documentation without insulting [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/","og_site_name":"The Couchbase Blog","article_published_time":"2014-12-16T17:36:13+00:00","og_image":[{"width":1800,"height":630,"url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2022\/11\/couchbase-nosql-dbaas.png","type":"image\/png"}],"author":"Trond Norbye, Senior Developer, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Trond Norbye, Senior Developer, Couchbase","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/"},"author":{"name":"Trond Norbye, Senior Developer, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ef0f9ff42d878c2fc0ab3a685e96f36d"},"headline":"Writing Your Own Storage Engine for Memcached","datePublished":"2014-12-16T17:36:13+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/"},"wordCount":1030,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/","url":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/","name":"Writing Your Own Storage Engine for Memcached - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2014-12-16T17:36:13+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#primaryimage","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","width":1800,"height":630},{"@type":"BreadcrumbList","@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Writing Your Own Storage Engine for Memcached"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"The Couchbase Blog","description":"Couchbase, the NoSQL Database","publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.couchbase.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"The Couchbase Blog","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/","url":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","contentUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/2023\/04\/admin-logo.png","width":218,"height":34,"caption":"The Couchbase Blog"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ef0f9ff42d878c2fc0ab3a685e96f36d","name":"Trond Norbye, Senior Developer, Couchbase","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/image\/03d13b4ab5eaa14c91cab7658f04df07","url":"https:\/\/secure.gravatar.com\/avatar\/bf3c00ca228efa25f7bfc168f566d6389279b44d4bbba4683c260a8bf33da03d?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bf3c00ca228efa25f7bfc168f566d6389279b44d4bbba4683c260a8bf33da03d?s=96&d=mm&r=g","caption":"Trond Norbye, Senior Developer, Couchbase"},"description":"Trond Norbye is a Software Architect at Couchbase. Core contributor to Couchbase &amp; Memcached projects. Created the C\/C++ &amp; node.js Couchbase client libraries.","url":"https:\/\/www.couchbase.com\/blog\/author\/trond-norbye\/"}]}},"authors":[{"term_id":8981,"user_id":14,"is_guest":0,"slug":"trond-norbye","display_name":"Trond Norbye, Senior Developer, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/bf3c00ca228efa25f7bfc168f566d6389279b44d4bbba4683c260a8bf33da03d?s=96&d=mm&r=g","author_category":"","last_name":"Norbye","first_name":"Trond","job_title":"","user_url":"","description":"Trond Norbye is a Software Architect at Couchbase. Core contributor to Couchbase &amp; Memcached projects. Created the C\/C++ &amp; node.js Couchbase client libraries."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1842","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/users\/14"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/comments?post=1842"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/posts\/1842\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/media?parent=1842"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/categories?post=1842"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/tags?post=1842"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/wp-json\/wp\/v2\/ppma_author?post=1842"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}