{"id":1843,"date":"2014-12-16T17:36:08","date_gmt":"2014-12-16T17:36:08","guid":{"rendered":"https:\/\/www.couchbase.com\/blog\/?p=1843"},"modified":"2014-12-16T17:36:08","modified_gmt":"2014-12-16T17:36:08","slug":"writing-your-own-storage-engine-memcached-part-2","status":"publish","type":"post","link":"https:\/\/www.couchbase.com\/blog\/pt\/writing-your-own-storage-engine-memcached-part-2\/","title":{"rendered":"Criando seu pr\u00f3prio mecanismo de armazenamento para o Memcached, parte 2"},"content":{"rendered":"<p>Na postagem anterior do blog, descrevi a inicializa\u00e7\u00e3o e a destrui\u00e7\u00e3o do mecanismo. Esta postagem do blog abordar\u00e1 o modelo de aloca\u00e7\u00e3o de mem\u00f3ria na interface do mecanismo.<\/p>\n<p>O n\u00facleo do memcached \u00e9 respons\u00e1vel por alocar toda a mem\u00f3ria necess\u00e1ria para suas conex\u00f5es (buffers de envio\/recebimento etc.), e o mecanismo \u00e9 respons\u00e1vel por alocar (e liberar) toda a mem\u00f3ria necess\u00e1ria para manter o controle dos itens. Os mecanismos n\u00e3o devem se preocupar com a mem\u00f3ria que o n\u00facleo aloca (e usa), mas o n\u00facleo acessar\u00e1 a mem\u00f3ria gerenciada pelo mecanismo.<\/p>\n<p>Quando o n\u00facleo do memcached est\u00e1 prestes a armazenar um novo item, ele precisa obter um buffer (at\u00e9 o momento, cont\u00ednuo) para armazenar os dados do item. O n\u00facleo tentar\u00e1 alocar esse buffer chamando a fun\u00e7\u00e3o\u00a0<code><font color=\"#999999\">alocar<\/font><\/code> na API. Portanto, vamos come\u00e7ar a estender nosso c\u00f3digo de exemplo adicionando nossa pr\u00f3pria implementa\u00e7\u00e3o da fun\u00e7\u00e3o <code><font color=\"#999999\">alocar<\/font><\/code> fun\u00e7\u00e3o. A primeira coisa que precisamos fazer \u00e9 adicion\u00e1-la ao nosso descritor de mecanismo que retornamos de\u00a0<code><font color=\"#999999\">create_instance<\/font><\/code>. Vamos adicionar v\u00e1rias fun\u00e7\u00f5es na entrada de hoje, portanto, vamos mapear todas elas enquanto fazemos isso:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">MEMCACHED_PUBLIC_API<br \/>ENGINE_ERROR_CODE create_instance(uint64_t interface,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 GET_SERVER_API get_server_api,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ENGINE_HANDLE **handle)<br \/>{<br \/>\u00a0 \u00a0[ ... cortar ... ]<br \/>\u00a0 \/*<br \/>\u00a0 \u00a0* Mapear os pontos de entrada da API para nossas fun\u00e7\u00f5es que os implementam.<br \/>\u00a0 \u00a0*\/<br \/>\u00a0 \u00a0h-&gt;engine.initialize = fs_initialize;<br \/>\u00a0 \u00a0h-&gt;engine.destroy = fs_destroy;<br \/>\u00a0 \u00a0<b>h-&gt;engine.get_info = fs_get_info;<br \/>\u00a0 \u00a0h-&gt;engine.allocate = fs_allocate;<br \/>\u00a0 \u00a0h-&gt;engine.remove = fs_item_delete;<br \/>\u00a0 \u00a0h-&gt;engine.release = fs_item_release;<br \/>\u00a0 \u00a0h-&gt;engine.get = fs_get;<br \/>\u00a0 \u00a0h-&gt;engine.get_stats = fs_get_stats;<br \/>\u00a0 \u00a0h-&gt;engine.reset_stats = fs_reset_stats;<br \/>\u00a0 \u00a0h-&gt;engine.store = fs_store;<br \/>\u00a0 \u00a0h-&gt;engine.flush = fs_flush;<br \/>\u00a0 \u00a0h-&gt;engine.unknown_command = fs_unknown_command;<br \/>\u00a0 \u00a0h-&gt;engine.item_set_cas = fs_item_set_cas;<br \/>\u00a0 \u00a0h-&gt;engine.get_item_info = fs_get_item_info;<\/b><br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>A pr\u00f3xima coisa que precisamos fazer \u00e9 criar uma estrutura de dados para manter as informa\u00e7\u00f5es de que precisamos. O objetivo deste tutorial n\u00e3o \u00e9 criar uma implementa\u00e7\u00e3o eficiente em termos de mem\u00f3ria, mas exercitar a API. Portanto, vamos criar a seguinte estrutura:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">struct fs_item {<br \/>\u00a0 \u00a0void *key;<br \/>\u00a0 \u00a0size_t nkey;<br \/>\u00a0 \u00a0void *data;<br \/>\u00a0 \u00a0size_t ndata;<br \/>\u00a0 \u00a0int flags;<br \/>\u00a0 \u00a0rel_time_t exptime;<br \/>};<br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>Nossa implementa\u00e7\u00e3o de <code><font color=\"#999999\">alocar<\/font><\/code> teria a seguinte apar\u00eancia:<\/p>\n<p>\u00a0<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">static ENGINE_ERROR_CODE fs_allocate(ENGINE_HANDLE* handle,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0const void* cookie,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0item **item,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0const void* key,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0const size_t nkey,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0const size_t nbytes,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0const int flags,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0const rel_time_t exptime)<br \/>{<br \/>\u00a0 \u00a0struct fs_item *it = malloc(sizeof(struct fs_item));<br \/>\u00a0 \u00a0Se (it == NULL) {<br \/>\u00a0 \u00a0 \u00a0 return ENGINE_ENOMEM;<br \/>\u00a0 \u00a0}<br \/>\u00a0 \u00a0it-&gt;flags = flags;<br \/>\u00a0 \u00a0it-&gt;exptime = exptime;<br \/>\u00a0 \u00a0it-&gt;nkey = nkey;<br \/>\u00a0 \u00a0it-&gt;ndata = nbytes;<br \/>\u00a0 \u00a0it-&gt;key = malloc(nkey);<br \/>\u00a0 \u00a0it-&gt;data = malloc(nbytes);<br \/>\u00a0 \u00a0Se (it-&gt;key == NULL || it-&gt;data == NULL) {<br \/>\u00a0 \u00a0 \u00a0 free(it-&gt;key);<br \/>\u00a0 \u00a0 \u00a0 free(it-&gt;data);<br \/>\u00a0 \u00a0 \u00a0 free(it);<br \/>\u00a0 \u00a0 \u00a0 return ENGINE_ENOMEM;<br \/>\u00a0 \u00a0}<br \/>\u00a0 \u00a0memcpy(it-&gt;key, key, nkey);<br \/>\u00a0 \u00a0*item = it;<br \/>\u00a0 \u00a0retornar ENGINE_SUCCESS;<br \/>}<br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>Se voc\u00ea observar a implementa\u00e7\u00e3o acima, ver\u00e1 que n\u00e3o retornamos o ponteiro para a mem\u00f3ria real do armazenamento de dados para o n\u00facleo do memcached. Para obter esse endere\u00e7o, o memcached chamar\u00e1\u00a0<code><font color=\"#999999\">get_item_info<\/font><\/code> na API. Ent\u00e3o, vamos implementar isso:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">static bool fs_get_item_info(ENGINE_HANDLE *handle, const void *cookie,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0const item* item, item_info *item_info)<br \/>{<br \/>\u00a0 \u00a0struct fs_item* it = (struct fs_item*)item;<br \/>\u00a0 \u00a0if (item_info-&gt;nvalue < 1) {<br \/>\u00a0 \u00a0 \u00a0 retornar falso;<br \/>\u00a0 \u00a0}<\/p>\n<p>\u00a0 \u00a0item_info-&gt;cas = 0; \/* N\u00e3o suportado *\/<br \/>\u00a0 \u00a0item_info-&gt;clsid = 0; \/* N\u00e3o suportado *\/<br \/>\u00a0 \u00a0item_info-&gt;exptime = it-&gt;exptime;<br \/>\u00a0 \u00a0item_info-&gt;flags = it-&gt;flags;<br \/>\u00a0 \u00a0item_info-&gt;key = it-&gt;key;<br \/>\u00a0 \u00a0item_info-&gt;nkey = it-&gt;nkey;<br \/>\u00a0 \u00a0item_info-&gt;nbytes = it-&gt;ndata; \/* Comprimento total dos dados do item *\/<br \/>\u00a0 \u00a0item_info-&gt;nvalue = 1; \/* N\u00famero de fragmentos usados *\/<br \/>\u00a0 \u00a0item_info-&gt;value[0].iov_base = it-&gt;data; \/* ponteiro para o fragmento 1 *\/<br \/>\u00a0 \u00a0item_info-&gt;value[0].iov_len = it-&gt;ndata; \/* Comprimento do fragmento 1 *\/<\/p>\n<p>\u00a0 \u00a0retornar verdadeiro;<br \/>}<br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>O <code><font color=\"#999999\">get_item_info<\/font><\/code> \u00e9 importante e merece mais informa\u00e7\u00f5es. Se voc\u00ea observar a API do mecanismo, o \"item\" \u00e9 definido como um ponteiro vazio, e n\u00f3s definimos nossa pr\u00f3pria estrutura de item para manter o controle das informa\u00e7\u00f5es de que precisamos por item. No entanto, o n\u00facleo do memcached precisar\u00e1 saber<br \/>onde ler\/gravar a mem\u00f3ria para a chave e os dados que v\u00e3o\/vem de um clinet. Para isso, invocaremos\u00a0<code><font color=\"#999999\">get_item_info<\/font><\/code>. Se voc\u00ea observar atentamente nossa implementa\u00e7\u00e3o do <code><font color=\"#999999\">fs_get_item_info<\/font><\/code> Voc\u00ea ver\u00e1 que a primeira coisa que estou fazendo \u00e9 verificar se\u00a0<code><font color=\"#999999\">item_info-&gt;nvalue<\/font><\/code> cont\u00e9m pelo menos 1<br \/>elemento. No momento, ele ir\u00e1 <b>sempre<\/b> mas a inten\u00e7\u00e3o \u00e9 que apoiemos a IO dispersa.<\/p>\n<p>Quando o n\u00facleo terminar de mover os dados que recebeu pelo cabo para o item, ele tentar\u00e1 armazenar o item em nosso mecanismo chamando <code><font color=\"#999999\">store<\/font><\/code>. Portanto, vamos criar uma implementa\u00e7\u00e3o simples (vamos ampli\u00e1-la mais adiante no tutorial):<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">static ENGINE_ERROR_CODE fs_store(ENGINE_HANDLE* handle,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const void *cookie,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 item* item,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 uint64_t *cas,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Opera\u00e7\u00e3o ENGINE_STORE_OPERATION,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 uint16_t vbucket)<br \/>{<br \/>\u00a0 \u00a0struct fs_item* it = item;<br \/>\u00a0 \u00a0char fname[it-&gt;nkey + 1];<br \/>\u00a0 \u00a0memcpy(fname, it-&gt;key, it-&gt;nkey);<br \/>\u00a0 \u00a0fname[it-&gt;nkey] = '<br \/>\u00a0 \u00a0FILE *fp = fopen(fname, \"w\");<br \/>\u00a0 \u00a0Se (fp == NULL) {<br \/>\u00a0 \u00a0 \u00a0 return ENGINE_NOT_STORED;<br \/>\u00a0 \u00a0}<br \/>\u00a0 \u00a0size_t nw = fwrite(it-&gt;data, 1, it-&gt;ndata, fp);<br \/>\u00a0 \u00a0fclose(fp);<br \/>\u00a0 \u00a0se (nw != it-&gt;ndata) {<br \/>\u00a0 \u00a0 \u00a0 remove(fname);<br \/>\u00a0 \u00a0 \u00a0 return ENGINE_NOT_STORED;<br \/>\u00a0 \u00a0}<\/p>\n<p>\u00a0 \u00a0*cas = 0;<br \/>\u00a0 \u00a0retornar ENGINE_SUCCESS;<br \/>}<br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>Se voc\u00ea observar a implementa\u00e7\u00e3o acima, ver\u00e1 que ela n\u00e3o implementa a sem\u00e2ntica correta para <em>adicionar<\/em>\/<em>substituir<\/em>\/<em>definir<\/em> etc., e isso bloquear\u00e1 o memcached enquanto estivermos fazendo o IO do arquivo. N\u00e3o se preocupe com isso agora, pois voltaremos a esse assunto.<\/p>\n<p>Quando o n\u00facleo terminar de usar o item alocado, ele liberar\u00e1 o item chamando a fun\u00e7\u00e3o <code><font color=\"#999999\">libera\u00e7\u00e3o<\/font><\/code> na API. O mecanismo pode reutilizar o armazenamento de itens para outra coisa nesse momento. Ent\u00e3o, vamos conectar nosso <code><font color=\"#999999\">libera\u00e7\u00e3o<\/font><\/code> implementa\u00e7\u00e3o:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">static void fs_item_release(ENGINE_HANDLE* handle,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const void *cookie,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 item* item)<br \/>{<br \/>\u00a0 \u00a0struct fs_item *it = item;<br \/>\u00a0 \u00a0free(it-&gt;key);<br \/>\u00a0 \u00a0free(it-&gt;data);<br \/>\u00a0 \u00a0free(it);<br \/>}<br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>Agora criamos todo o c\u00f3digo para armazenar itens com sucesso em nosso mecanismo, mas n\u00e3o podemos ler nenhum deles de volta. Ent\u00e3o, vamos implementar <font color=\"#999999\"><code>obter<\/code><\/font><\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">static ENGINE_ERROR_CODE fs_get(ENGINE_HANDLE* handle,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const void* cookie,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 item** item,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const void* key,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const int nkey,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 uint16_t vbucket)<br \/>{<\/p>\n<p>\u00a0 \u00a0char fname[nkey + 1];<br \/>\u00a0 \u00a0memcpy(fname, key, nkey);<br \/>\u00a0 \u00a0fname[nkey] = '<\/p>\n<p>\u00a0 \u00a0struct stat st;<br \/>\u00a0 \u00a0se (stat(fname, &amp;st) == -1) {<br \/>\u00a0 \u00a0 \u00a0 return ENGINE_NOT_STORED;<br \/>\u00a0 \u00a0}<\/p>\n<p>\u00a0 \u00a0struct fs_item* it = NULL;<br \/>\u00a0 \u00a0ENGINE_ERROR_CODE ret = fs_allocate(handle, cookie, (void**)&amp;it, key, nkey,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0st.st_size, 0, 0);<br \/>\u00a0 \u00a0Se (ret != ENGINE_SUCCESS) {<br \/>\u00a0 \u00a0 \u00a0 return ENGINE_ENOMEM;<br \/>\u00a0 \u00a0}<\/p>\n<p>\u00a0 \u00a0FILE *fp = fopen(fname, \"r\");<br \/>\u00a0 \u00a0Se (fp == NULL) {<br \/>\u00a0 \u00a0 \u00a0 fs_release(handle, cookie, it);<br \/>\u00a0 \u00a0 \u00a0 retornar ENGINE_FAILED;<br \/>\u00a0 \u00a0}<\/p>\n<p>\u00a0 \u00a0size_t nr = fread(it-&gt;data, 1, it-&gt;ndata, fp);<br \/>\u00a0 \u00a0fclose(fp);<br \/>\u00a0 \u00a0se (nr != it-&gt;ndata) {<br \/>\u00a0 \u00a0 \u00a0 fs_release(handle, cookie, it);<br \/>\u00a0 \u00a0 \u00a0 retornar ENGINE_FAILED;<br \/>\u00a0 \u00a0}<\/p>\n<p>\u00a0 \u00a0*item = it;<br \/>\u00a0 \u00a0retornar ENGINE_SUCCESS;<br \/>}<br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>Vamos adicionar uma implementa\u00e7\u00e3o fict\u00edcia para o restante da API e tentar carregar e testar o mecanismo:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">static const engine_info* fs_get_info(ENGINE_HANDLE* handle)<br \/>{<br \/>\u00a0 \u00a0static engine_info info = {<br \/>\u00a0 \u00a0 \u00a0 .description = \"Mecanismo do sistema de arquivos v0.1\",<br \/>\u00a0 \u00a0 \u00a0 .num_features = 0<br \/>\u00a0 \u00a0};<\/p>\n<p>\u00a0 \u00a0return &amp;info;<br \/>}<\/p>\n<p>static ENGINE_ERROR_CODE fs_item_delete(ENGINE_HANDLE* handle,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const void* cookie,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const void* key,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const size_t nkey,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 uint64_t cas,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 uint16_t vbucket)<br \/>{<br \/>\u00a0 \u00a0return ENGINE_KEY_ENOENT;<br \/>}<\/p>\n<p>static ENGINE_ERROR_CODE fs_get_stats(ENGINE_HANDLE* handle,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const void* cookie,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const char* stat_key,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 int nkey,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 ADD_STAT add_stat)<br \/>{<br \/>\u00a0 \u00a0retornar ENGINE_SUCCESS;<br \/>}<\/p>\n<p>static ENGINE_ERROR_CODE fs_flush(ENGINE_HANDLE* handle,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const void* cookie, time_t when)<br \/>{<\/p>\n<p>\u00a0 \u00a0retornar ENGINE_SUCCESS;<br \/>}<\/p>\n<p>static void fs_reset_stats(ENGINE_HANDLE* handle, const void *cookie)<br \/>{<\/p>\n<p>}<\/p>\n<p>static ENGINE_ERROR_CODE fs_unknown_command(ENGINE_HANDLE* handle,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 const void* cookie,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 protocol_binary_request_header *request,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 Resposta ADD_RESPONSE)<br \/>{<br \/>\u00a0 \u00a0retornar ENGINE_ENOTSUP;<br \/>}<\/p>\n<p>static void fs_item_set_cas(ENGINE_HANDLE *handle, const void *cookie,<br \/>\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 item* item, uint64_t val)<br \/>{<br \/>}<\/p>\n<p>\u00a0 \u00a0 \u00a0 <\/p><\/div>\n<\/div>\n<p>Ent\u00e3o, vamos testar nosso mecanismo:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">trond@opensolaris&gt; \/opt\/memcached\/bin\/memcached -E .libs\/fs_engine.so<br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>De outro terminal em que estou digitando:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">trond@opensolaris&gt; telnet localhost 11211<br \/>Tentando ::1...<br \/>Conectado ao opensolaris.<br \/>O caractere de escape \u00e9 '^]'.<br \/>adicionar teste 0 0 4<br \/>teste<br \/>ARMAZENADO<br \/>obter teste<br \/>VALUE test 0 4<br \/>teste<br \/>FIM<br \/>sair<br \/>Conex\u00e3o com a tempestade fechada pelo host externo.<br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>Encerre o memcached pressionando <code><font color=\"#999999\">ctrl-c<\/font><\/code>e procurar no diret\u00f3rio atual:<\/p>\n<div class=\"geshifilter\">\n<div class=\"text geshifilter-text\" style=\"font-family:monospace;\">trond@opensolaris&gt; ls -l test<br \/>-rw-r-r- 1 trond users 6 Oct 8 12:56 test<br \/>trond@opensolaris&gt; cat test<br \/>teste<br \/>\u00a0 \u00a0 \u00a0 <\/div>\n<\/div>\n<p>Isso \u00e9 tudo por enquanto.<\/p>","protected":false},"excerpt":{"rendered":"<p>In the previous blog post I described the engine initialization and\u00a0destruction. This blog post will cover the memory allocation model\u00a0in the engine interface. The memcached core is responsible for allocating all of the\u00a0memory it needs for its connections (send \/ [&hellip;]<\/p>","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-1843","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 v26.1 (Yoast SEO v26.1.1) - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>Writing your own storage engine for Memcached, part 2 - 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\/writing-your-own-storage-engine-memcached-part-2\/\" \/>\n<meta property=\"og:locale\" content=\"pt_BR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Writing your own storage engine for Memcached, part 2\" \/>\n<meta property=\"og:description\" content=\"In the previous blog post I described the engine initialization and\u00a0destruction. This blog post will cover the memory allocation model\u00a0in the engine interface. The memcached core is responsible for allocating all of the\u00a0memory it needs for its connections (send \/ [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.couchbase.com\/blog\/pt\/writing-your-own-storage-engine-memcached-part-2\/\" \/>\n<meta property=\"og:site_name\" content=\"The Couchbase Blog\" \/>\n<meta property=\"article:published_time\" content=\"2014-12-16T17:36:08+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=\"7 minutos\" \/>\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-part-2\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/\"},\"author\":{\"name\":\"Trond Norbye, Senior Developer, Couchbase\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ef0f9ff42d878c2fc0ab3a685e96f36d\"},\"headline\":\"Writing your own storage engine for Memcached, part 2\",\"datePublished\":\"2014-12-16T17:36:08+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/\"},\"wordCount\":1384,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#organization\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#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\/writing-your-own-storage-engine-memcached-part-2\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/\",\"url\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/\",\"name\":\"Writing your own storage engine for Memcached, part 2 - The Couchbase Blog\",\"isPartOf\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png\",\"datePublished\":\"2014-12-16T17:36:08+00:00\",\"breadcrumb\":{\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#breadcrumb\"},\"inLanguage\":\"pt-BR\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@id\":\"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#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-part-2\/#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, part 2\"}]},{\"@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\/ef0f9ff42d878c2fc0ab3a685e96f36d\",\"name\":\"Trond Norbye, Senior Developer, Couchbase\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"pt-BR\",\"@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\/pt\/author\/trond-norbye\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Writing your own storage engine for Memcached, part 2 - 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\/writing-your-own-storage-engine-memcached-part-2\/","og_locale":"pt_BR","og_type":"article","og_title":"Writing your own storage engine for Memcached, part 2","og_description":"In the previous blog post I described the engine initialization and\u00a0destruction. This blog post will cover the memory allocation model\u00a0in the engine interface. The memcached core is responsible for allocating all of the\u00a0memory it needs for its connections (send \/ [&hellip;]","og_url":"https:\/\/www.couchbase.com\/blog\/pt\/writing-your-own-storage-engine-memcached-part-2\/","og_site_name":"The Couchbase Blog","article_published_time":"2014-12-16T17:36:08+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":"7 minutos"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#article","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/"},"author":{"name":"Trond Norbye, Senior Developer, Couchbase","@id":"https:\/\/www.couchbase.com\/blog\/#\/schema\/person\/ef0f9ff42d878c2fc0ab3a685e96f36d"},"headline":"Writing your own storage engine for Memcached, part 2","datePublished":"2014-12-16T17:36:08+00:00","mainEntityOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/"},"wordCount":1384,"commentCount":0,"publisher":{"@id":"https:\/\/www.couchbase.com\/blog\/#organization"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#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\/writing-your-own-storage-engine-memcached-part-2\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/","url":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/","name":"Writing your own storage engine for Memcached, part 2 - The Couchbase Blog","isPartOf":{"@id":"https:\/\/www.couchbase.com\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#primaryimage"},"image":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#primaryimage"},"thumbnailUrl":"https:\/\/www.couchbase.com\/blog\/wp-content\/uploads\/sites\/1\/2022\/11\/couchbase-nosql-dbaas.png","datePublished":"2014-12-16T17:36:08+00:00","breadcrumb":{"@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#breadcrumb"},"inLanguage":"pt-BR","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/"]}]},{"@type":"ImageObject","inLanguage":"pt-BR","@id":"https:\/\/www.couchbase.com\/blog\/writing-your-own-storage-engine-memcached-part-2\/#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-part-2\/#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, part 2"}]},{"@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\/ef0f9ff42d878c2fc0ab3a685e96f36d","name":"Trond Norbye, desenvolvedor s\u00eanior, Couchbase","image":{"@type":"ImageObject","inLanguage":"pt-BR","@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 \u00e9 arquiteto de software na Couchbase. Principal colaborador dos projetos Couchbase e Memcached. Criou as bibliotecas de clientes C\/C++ e node.js do Couchbase.","url":"https:\/\/www.couchbase.com\/blog\/pt\/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 \u00e9 arquiteto de software na Couchbase. Principal colaborador dos projetos Couchbase e Memcached. Criou as bibliotecas de clientes C\/C++ e node.js do Couchbase."}],"_links":{"self":[{"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1843","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\/14"}],"replies":[{"embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/comments?post=1843"}],"version-history":[{"count":0,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/posts\/1843\/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=1843"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/categories?post=1843"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/tags?post=1843"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/www.couchbase.com\/blog\/pt\/wp-json\/wp\/v2\/ppma_author?post=1843"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}