{"id":1678,"date":"2014-12-16T19:38:48","date_gmt":"2014-12-16T19:38:47","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1678"},"modified":"2017-05-03T10:04:44","modified_gmt":"2017-05-03T17:04:44","slug":"maintaining-set-memcached","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/pt\/maintaining-set-memcached\/","title":{"rendered":"Manuten\u00e7\u00e3o de um conjunto no Memcached"},"content":{"rendered":"<div id=\"post\">\n<p><span style=\"color: #c0c0c0;\"><em>[This post also appears on <\/em><\/span><em><a href=\"https:\/\/dustin.github.com\/2011\/02\/17\/memcached-set.html\"><span style=\"color: #c0c0c0;\">Dustin&#8217;s github blog<\/span><\/a><\/em><span style=\"color: #c0c0c0;\"><em>].<\/em><\/span><\/p>\n<p>This is something that comes up every once in a <img decoding=\"async\" class=\"floatright\" title=\"I found this in some old military archives.\" src=\"https:\/\/dustin.github.com\/images\/simple.png\" alt=\"simple\" align=\"right\" hspace=\"15\" \/><br \/>\nwhile. I usually describe a means of doing it that I think makes sense, but I don\u2019t think I\u2019ve ever described it <em>quite<\/em> well enough. People tend to think it\u2019s complicated or slow or things like that. I\u2019m going to try to try to solve that problem here.<\/p>\n<h3>Constraints<\/h3>\n<p>In order to be useful for enough applications, we\u2019re going to work under the following assumptions:<\/p>\n<ul>\n<li>must minimize round trips to the servers<\/li>\n<li>O(1) add (for both current size and new items coming in)<\/li>\n<li>O(1) remove (for both current size and items being removed)<\/li>\n<li>O(1) fetch<\/li>\n<li>lock and wait free<\/li>\n<li>easy to use<\/li>\n<li>easy to understand<\/li>\n<li>no required explicit maintenance<\/li>\n<\/ul>\n<p>And, of course, it has to be web scale!<\/p>\n<h3>Ingredients<\/h3>\n<p>The concept is simple and makes use of three memcached operations with atomicity guarantees.<\/p>\n<p>An index is created with <code>add<\/code>. This should be pretty obvious.<\/p>\n<p>Whenever we need to add or remove items, we use <code>append<\/code>. For this to work, we need to encode the items in such a way as to have them represent either positive or negative items. I created a simple sample encoding of <code>+key<\/code> to represent the addition of <code>key<\/code> to the set and <code>-key<\/code> to represent the removal of <code>key<\/code> from the set. I then use spaces to separate multiple items.<\/p>\n<p>Example: <code>+a +b +c -b<\/code> represents <code>{a, c}<\/code>. The sequence is, of course important.<\/p>\n<p>A set that has members coming and going frequently enough may need to be compacted. For that, we reencode the set and use <code>cas<\/code> to ensure we can add it back without stepping on another client.<\/p>\n<h3>Walk Me Through It<\/h3>\n<p>I\u2019m using python for this example. Ideally this gets implemented in your client and everything\u2019s good to go.<\/p>\n<p>First, we need encoders and decoders. This is actually the hard part and it\u2019s really trivial when it comes down to it.<\/p>\n<h3>The Encoder<\/h3>\n<p>We start with the most basic representation of data within our sets.<\/p>\n<div class=\"geshifilter\">\n<div class=\"python geshifilter-python\" style=\"font-family: monospace;\">\n<p><span style=\"color: #ff7700; font-weight: bold;\">def<\/span> encodeSet<span style=\"color: black;\">(<\/span>keys<span style=\"color: #66cc66;\">,<\/span> op<span style=\"color: #66cc66;\">=<\/span><span style=\"color: #483d8b;\">&#8216;+&#8217;<\/span><span style=\"color: black;\">)<\/span>:<br \/>\n<span style=\"color: #483d8b;\">&#8220;&#8221;&#8221;Encode a set of keys to modify the set.<\/span><\/p>\n<p>&gt;&gt;&gt; encodeSet([&#8216;a&#8217;, &#8216;b&#8217;, &#8216;c&#8217;])<br \/>\n&#8216;+a +b +c &#8216;<br \/>\n&#8220;&#8221;&#8221;<br \/>\n<span style=\"color: #ff7700; font-weight: bold;\">return<\/span> <span style=\"color: #483d8b;\">&#8221;<\/span>.<span style=\"color: black;\">join<\/span><span style=\"color: black;\">(<\/span>op + k + <span style=\"color: #483d8b;\">&#8216; &#8216;<\/span> <span style=\"color: #ff7700; font-weight: bold;\">for<\/span> k <span style=\"color: #ff7700; font-weight: bold;\">in<\/span> keys<span style=\"color: black;\">)<\/span><\/p>\n<\/div>\n<\/div>\n<p>This is more documentation than code, but it\u2019s pretty clear. If you want a set of JPEGs instead, you could create a simple binary encoding with a length and a body instead of having it be whitespace separated.<\/p>\n<h3>Modifying a Set<\/h3>\n<p>Modification is append-only with the only difference between adding and removing being an encoding op. This is useful because we can write the same code for both cases.<\/p>\n<div class=\"geshifilter\">\n<div class=\"python geshifilter-python\" style=\"font-family: monospace;\">\n<p><span style=\"color: #ff7700; font-weight: bold;\">def<\/span> modify<span style=\"color: black;\">(<\/span>mc<span style=\"color: #66cc66;\">,<\/span> indexName<span style=\"color: #66cc66;\">,<\/span> op<span style=\"color: #66cc66;\">,<\/span> keys<span style=\"color: black;\">)<\/span>:<br \/>\nencoded <span style=\"color: #66cc66;\">=<\/span> encodeSet<span style=\"color: black;\">(<\/span>keys<span style=\"color: #66cc66;\">,<\/span> op<span style=\"color: black;\">)<\/span><br \/>\n<span style=\"color: #ff7700; font-weight: bold;\">try<\/span>:<br \/>\nmc.<span style=\"color: black;\">append<\/span><span style=\"color: black;\">(<\/span>indexName<span style=\"color: #66cc66;\">,<\/span> encoded<span style=\"color: black;\">)<\/span><br \/>\n<span style=\"color: #ff7700; font-weight: bold;\">except<\/span> <span style=\"color: #008000;\">KeyError<\/span>:<br \/>\n<span style=\"color: #808080; font-style: italic;\"># If we can&#8217;t append, and we&#8217;re adding to the set,<\/span><br \/>\n<span style=\"color: #808080; font-style: italic;\"># we are trying to create the index, so do that.<\/span><br \/>\n<span style=\"color: #ff7700; font-weight: bold;\">if<\/span> op <span style=\"color: #66cc66;\">==<\/span> <span style=\"color: #483d8b;\">&#8216;+&#8217;<\/span>:<br \/>\nmc.<span style=\"color: black;\">add<\/span><span style=\"color: black;\">(<\/span>indexName<span style=\"color: #66cc66;\">,<\/span> encoded<span style=\"color: black;\">)<\/span><\/p>\n<p><span style=\"color: #ff7700; font-weight: bold;\">def<\/span> add<span style=\"color: black;\">(<\/span>mc<span style=\"color: #66cc66;\">,<\/span> indexName<span style=\"color: #66cc66;\">,<\/span> *keys<span style=\"color: black;\">)<\/span>:<br \/>\n<span style=\"color: #483d8b;\">&#8220;&#8221;&#8221;Add the given keys to the given set.&#8221;&#8221;&#8221;<\/span><br \/>\nmodify<span style=\"color: black;\">(<\/span>mc<span style=\"color: #66cc66;\">,<\/span> indexName<span style=\"color: #66cc66;\">,<\/span> <span style=\"color: #483d8b;\">&#8216;+&#8217;<\/span><span style=\"color: #66cc66;\">,<\/span> keys<span style=\"color: black;\">)<\/span><\/p>\n<p><span style=\"color: #ff7700; font-weight: bold;\">def<\/span> remove<span style=\"color: black;\">(<\/span>mc<span style=\"color: #66cc66;\">,<\/span> indexName<span style=\"color: #66cc66;\">,<\/span> *keys<span style=\"color: black;\">)<\/span>:<br \/>\n<span style=\"color: #483d8b;\">&#8220;&#8221;&#8221;Remove the given keys from the given set.&#8221;&#8221;&#8221;<\/span><br \/>\nmodify<span style=\"color: black;\">(<\/span>mc<span style=\"color: #66cc66;\">,<\/span> indexName<span style=\"color: #66cc66;\">,<\/span> <span style=\"color: #483d8b;\">&#8216;-&#8216;<\/span><span style=\"color: #66cc66;\">,<\/span> keys<span style=\"color: black;\">)<\/span><\/p>\n<\/div>\n<\/div>\n<p>I allow a side-effect of <code>add<\/code> to create the index if it doesn\u2019t exist.<\/p>\n<p>In an actual application, there\u2019s a non-zero chance that the <code>append<\/code> would fail because the item is missing and the immediately subsequent <code>add<\/code> would fail due to a race condition. I didn\u2019t write the code to cover that here, but it\u2019s pretty simple. If it matters to you, just loop the entire modify method as long as both fail. You\u2019d have to be trying to get it to fail more than once.<\/p>\n<h3>The Decoder<\/h3>\n<p>In order to use the data, we\u2019re going to need to decode it, so let\u2019s put together a quick decoder that can reverse what the above encoder does (including the appends for add and remove).<\/p>\n<div class=\"geshifilter\">\n<div class=\"python geshifilter-python\" style=\"font-family: monospace;\">\n<p><span style=\"color: #ff7700; font-weight: bold;\">def<\/span> decodeSet<span style=\"color: black;\">(<\/span>data<span style=\"color: black;\">)<\/span>:<br \/>\n<span style=\"color: #483d8b;\">&#8220;&#8221;&#8221;Decode an item from the cache into a set impl.<\/span><\/p>\n<p>Returns a dirtiness indicator (compaction hint) and the set<\/p>\n<p>&gt;&gt;&gt; decodeSet(&#8216;+a +b +c -b -x&#8217;)<br \/>\n(2, set([&#8216;a&#8217;, &#8216;c&#8217;]))<br \/>\n&#8220;&#8221;&#8221;<\/p>\n<p>keys <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #008000;\">set<\/span><span style=\"color: black;\">(<\/span><span style=\"color: black;\">)<\/span><br \/>\ndirtiness <span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #ff4500;\">0<\/span><br \/>\n<span style=\"color: #ff7700; font-weight: bold;\">for<\/span> k <span style=\"color: #ff7700; font-weight: bold;\">in<\/span> data.<span style=\"color: black;\">split<\/span><span style=\"color: black;\">(<\/span><span style=\"color: black;\">)<\/span>:<br \/>\nop<span style=\"color: #66cc66;\">,<\/span> key <span style=\"color: #66cc66;\">=<\/span> k<span style=\"color: black;\">[<\/span><span style=\"color: #ff4500;\">0<\/span><span style=\"color: black;\">]<\/span><span style=\"color: #66cc66;\">,<\/span> k<span style=\"color: black;\">[<\/span><span style=\"color: #ff4500;\">1<\/span>:<span style=\"color: black;\">]<\/span><br \/>\n<span style=\"color: #ff7700; font-weight: bold;\">if<\/span> op <span style=\"color: #66cc66;\">==<\/span> <span style=\"color: #483d8b;\">&#8216;+&#8217;<\/span>:<br \/>\nkeys.<span style=\"color: black;\">add<\/span><span style=\"color: black;\">(<\/span>key<span style=\"color: black;\">)<\/span><br \/>\n<span style=\"color: #ff7700; font-weight: bold;\">elif<\/span> op <span style=\"color: #66cc66;\">==<\/span> <span style=\"color: #483d8b;\">&#8216;-&#8216;<\/span>:<br \/>\nkeys.<span style=\"color: black;\">discard<\/span><span style=\"color: black;\">(<\/span>key<span style=\"color: black;\">)<\/span><br \/>\ndirtiness +<span style=\"color: #66cc66;\">=<\/span> <span style=\"color: #ff4500;\">1<\/span><\/p>\n<p><span style=\"color: #ff7700; font-weight: bold;\">return<\/span> dirtiness<span style=\"color: #66cc66;\">,<\/span> keys<\/p>\n<\/div>\n<\/div>\n<p>This is the most complicated part.<\/p>\n<h3>Retrieving the Items<\/h3>\n<p>Now that we can encode, set, and modify our data, retrieval should be quite trivial. A basic pass would look like this:<\/p>\n<div class=\"geshifilter\">\n<div class=\"python geshifilter-python\" style=\"font-family: monospace;\">\n<p><span style=\"color: #ff7700; font-weight: bold;\">def<\/span> items<span style=\"color: black;\">(<\/span>mc<span style=\"color: #66cc66;\">,<\/span> indexName<span style=\"color: black;\">)<\/span>:<br \/>\n<span style=\"color: #483d8b;\">&#8220;&#8221;&#8221;Retrieve the current values from the set.&#8221;&#8221;&#8221;<\/span><\/p>\n<p>flags<span style=\"color: #66cc66;\">,<\/span> cas<span style=\"color: #66cc66;\">,<\/span> data <span style=\"color: #66cc66;\">=<\/span> mc.<span style=\"color: black;\">get<\/span><span style=\"color: black;\">(<\/span>indexName<span style=\"color: black;\">)<\/span><br \/>\ndirtiness<span style=\"color: #66cc66;\">,<\/span> keys <span style=\"color: #66cc66;\">=<\/span> decodeSet<span style=\"color: black;\">(<\/span>data<span style=\"color: black;\">)<\/span><br \/>\n<span style=\"color: #ff7700; font-weight: bold;\">return<\/span> keys<\/p>\n<\/div>\n<\/div>\n<p>That\u2019s pretty much it. However, this is a pretty good time to do compaction. <code>dirtiness<\/code> above measures how many removal tokens are in the set. If there are too many, we want to kill them.<\/p>\n<p>Imagine a <code>DIRTINESS_THRESHOLD<\/code> number set that decides where we want to do autocompaction. If we have more dirtiness than this, we compact upon retrieval (making a single get into a single get and a single <code>CAS<\/code>.<\/p>\n<p>For this use case, we don\u2019t actually care whether the <code>CAS<\/code> succeeds most of the time, so we just fire and forget. It\u2019s safe (i.e. won\u2019t destroy any data), but not guaranteed to work.<\/p>\n<p>So here\u2019s a modified <code>items<\/code> function conditionally compacting:<\/p>\n<div class=\"geshifilter\">\n<div class=\"python geshifilter-python\" style=\"font-family: monospace;\">\n<p><span style=\"color: #ff7700; font-weight: bold;\">def<\/span> items<span style=\"color: black;\">(<\/span>mc<span style=\"color: #66cc66;\">,<\/span> indexName<span style=\"color: #66cc66;\">,<\/span> forceCompaction<span style=\"color: #66cc66;\">=<\/span><span style=\"color: #008000;\">False<\/span><span style=\"color: black;\">)<\/span>:<br \/>\n<span style=\"color: #483d8b;\">&#8220;&#8221;&#8221;Retrieve the current values from the set.<\/span><\/p>\n<p>This may trigger a compaction if you ask it to or the encoding is<br \/>\ntoo dirty.&#8221;&#8221;&#8221;<\/p>\n<p>flags<span style=\"color: #66cc66;\">,<\/span> casid<span style=\"color: #66cc66;\">,<\/span> data <span style=\"color: #66cc66;\">=<\/span> mc.<span style=\"color: black;\">get<\/span><span style=\"color: black;\">(<\/span>indexName<span style=\"color: black;\">)<\/span><br \/>\ndirtiness<span style=\"color: #66cc66;\">,<\/span> keys <span style=\"color: #66cc66;\">=<\/span> decodeSet<span style=\"color: black;\">(<\/span>data<span style=\"color: black;\">)<\/span><\/p>\n<p><span style=\"color: #ff7700; font-weight: bold;\">if<\/span> forceCompaction <span style=\"color: #ff7700; font-weight: bold;\">or<\/span> dirtiness <span style=\"color: #66cc66;\">&gt;<\/span> DIRTINESS_THRESHOLD:<br \/>\ncompacted <span style=\"color: #66cc66;\">=<\/span> encodeSet<span style=\"color: black;\">(<\/span>keys<span style=\"color: black;\">)<\/span><br \/>\nmc.<span style=\"color: black;\">cas<\/span><span style=\"color: black;\">(<\/span>indexName<span style=\"color: #66cc66;\">,<\/span> casid<span style=\"color: #66cc66;\">,<\/span> compacted<span style=\"color: black;\">)<\/span><br \/>\n<span style=\"color: #ff7700; font-weight: bold;\">return<\/span> keys<\/p>\n<\/div>\n<\/div>\n<p>And we\u2019re done.<\/p>\n<h3>In Summary<\/h3>\n<p><strong>Worst case add to set<\/strong>: 2 round trips (when the set doesn\u2019t exist and needs to be created, but we don\u2019t have to know that).<\/p>\n<p><strong>Normal add to set<\/strong>: 1 round trip regardless of the number of members being added. (You don\u2019t even need to retrieve the current value to correctly add or remove items in bulk, much less transfer it all back).<\/p>\n<p><strong>Worst case retrieval<\/strong>: 2 round trips (when compaction is a side-effect).<\/p>\n<p><strong>Normal retrieval<\/strong>: 1 round trip (just fetch the one key).<\/p>\n<h3>Caveats<\/h3>\n<p>While the number of sets is roughly unlimited, there\u2019s a practical size of a single set with this implementation. It\u2019d be trivial to \u201cshard\u201d the set across multiple keys (thus across multiple servers) if one needed very large sets (more than, say 4,000 250 byte items).<\/p>\n<p>Since compaction is done on read in this implementation, a case where you\u2019re modifying very heavily but reading rarely might not be a perfect for this code. In that case, I\u2019d start compacting on random writes (making worst case add\/remove take about three hops where it would\u2019ve otherwise been one).<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>[This post also appears on Dustin&#8217;s github blog]. This is something that comes up every once in a while. I usually describe a means of doing it that I think makes sense, but I don\u2019t think I\u2019ve ever described it [&hellip;]<\/p>\n","protected":false},"author":34,"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":[8992],"class_list":["post-1678","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.3 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Maintaining a Set in 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\/pt\/maintaining-set-memcached\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Maintaining a Set in Memcached\" \/>\n<meta property=\"og:description\" content=\"[This post also appears on Dustin&#8217;s github blog]. This is something that comes up every once in a while. I usually describe a means of doing it that I think makes sense, but I don\u2019t think I\u2019ve ever described it [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/pt\/maintaining-set-memcached\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2014-12-16T19:38:47+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2017-05-03T17:04:44+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=\"Dustin Sallings, Chief Architect, 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=\"Dustin Sallings, Chief Architect, Couchbase\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"6 minutos\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/\"},\"author\":{\"name\":\"Dustin Sallings, Chief Architect, Couchbase\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#\\\/schema\\\/person\\\/e68b6f4489072ef4a84f60bc437c07d0\"},\"headline\":\"Maintaining a Set in Memcached\",\"datePublished\":\"2014-12-16T19:38:47+00:00\",\"dateModified\":\"2017-05-03T17:04:44+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/\"},\"wordCount\":1125,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"articleSection\":[\"Uncategorized\"],\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/\",\"name\":\"Maintaining a Set in Memcached - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/wp-content\\\/uploads\\\/sites\\\/1\\\/2022\\\/11\\\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2014-12-16T19:38:47+00:00\",\"dateModified\":\"2017-05-03T17:04:44+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-memcached\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/maintaining-set-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\\\/maintaining-set-memcached\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Maintaining a Set in 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\":\"pt-BR\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/#organization\",\"name\":\"The Couchbase Blog\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\\\/e68b6f4489072ef4a84f60bc437c07d0\",\"name\":\"Dustin Sallings, Chief Architect, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=gc5bddc8d7dab8b5c9121282556b0dbff\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=g\",\"caption\":\"Dustin Sallings, Chief Architect, Couchbase\"},\"description\":\"Dustin Sallings is a Chief Architect at Couchbase. Dustin is an Author of spymemcached and core contributor to Couchbase and Memcached projects.\",\"url\":\"https:\\\/\\\/www.couchbase.com\\\/blog\\\/pt\\\/author\\\/dustin-sallings\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Maintaining a Set in 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\/pt\/maintaining-set-memcached\/","og_locale":"pt_BR","og_type":"article","og_title":"Maintaining a Set in Memcached","og_description":"[This post also appears on Dustin&#8217;s github blog]. This is something that comes up every once in a while. I usually describe a means of doing it that I think makes sense, but I don\u2019t think I\u2019ve ever described it [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/pt\/maintaining-set-memcached\/","og_site_name":"The Couchbase Blog","article_published_time":"2014-12-16T19:38:47+00:00","article_modified_time":"2017-05-03T17:04:44+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":"Dustin Sallings, Chief Architect, Couchbase","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Dustin Sallings, Chief Architect, Couchbase","Est. reading time":"6 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/"},"author":{"name":"Dustin Sallings, Chief Architect, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/e68b6f4489072ef4a84f60bc437c07d0"},"headline":"Maintaining a Set in Memcached","datePublished":"2014-12-16T19:38:47+00:00","dateModified":"2017-05-03T17:04:44+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/"},"wordCount":1125,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","articleSection":["Uncategorized"],"inLanguage":"pt-BR","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/","url":"https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/","name":"Maintaining a Set in Memcached - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2014-12-16T19:38:47+00:00","dateModified":"2017-05-03T17:04:44+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/maintaining-set-memcached\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/maintaining-set-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\/maintaining-set-memcached\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.couchbase.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Maintaining a Set in Memcached"}]},{"@type":"WebSite","@id":"https:\/\/www.couchbase.com\/blog\/#website","url":"https:\/\/www.couchbase.com\/blog\/","name":"Blog do Couchbase","description":"Couchbase, o banco de dados NoSQL","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":"pt-BR"},{"@type":"Organization","@id":"https:\/\/www.couchbase.com\/blog\/#organization","name":"Blog do Couchbase","url":"https:\/\/www.couchbase.com\/blog\/","logo":{"@type":"ImageObject","inLanguage":"pt-BR","@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\/e68b6f4489072ef4a84f60bc437c07d0","name":"Dustin Sallings, arquiteto-chefe da Couchbase","image":{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/secure.gravatar.com\/avatar\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=gc5bddc8d7dab8b5c9121282556b0dbff","url":"https:\/\/secure.gravatar.com\/avatar\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=g","caption":"Dustin Sallings, Chief Architect, Couchbase"},"description":"Dustin Sallings is a Chief Architect at Couchbase. Dustin is an Author of spymemcached and core contributor to Couchbase and Memcached projects.","url":"https:\/\/www.couchbase.com\/blog\/pt\/author\/dustin-sallings\/"}]}},"acf":[],"authors":[{"term_id":8992,"user_id":34,"is_guest":0,"slug":"dustin-sallings","display_name":"Dustin Sallings, Chief Architect, Couchbase","avatar_url":"https:\/\/secure.gravatar.com\/avatar\/61704e29c6b19851f45c023b2f456b2a0c80ba03ae65e957e39080a0d15065e5?s=96&d=mm&r=g","0":null,"1":"","2":"","3":"","4":"","5":"","6":"","7":"","8":""}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1678","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/users\/34"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=1678"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1678\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media\/13873"}],"wp:attachment":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/media?parent=1678"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=1678"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=1678"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=1678"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}