libcouchbase 2.4.0 está aqui. Ele oferece grandes aprimoramentos arquitetônicos e vários novos recursos, melhorando as versões anteriores.

Este blog foi originalmente escrito para a versão 2.4.0 DP1, mas foi modificado para refletir as diferenças entre a visualização do desenvolvedor e a versão atual do GA (2.4.0)

Links diretos para downloadhttp://packages.couchbase.com/clients/c/index.html

Documentação da API: http://docs.couchbase.com/sdk-api/couchbase-c-client-2.4.0/

Melhorias internas

Estruturas de pacotes

Codinome pacote-ngNa verdade, essa versão da libcouchbase começou como uma tentativa de refatorar o tratamento de pacotes de modo que eles fossem considerados objetos de primeira classe. O pacote de solicitação é a moeda principal da biblioteca, pois vincula o cookie solicitado pelo usuário à resposta do servidor.

Na versão 2.4, os pacotes de solicitação são encapsulados no mc_PACKET que contém informações sobre o cookie, os buffers do próprio pacote e o estado do pacote (ou seja, recebido, liberado, tentado novamente, com erro, pendente). A estrutura do pacote vem junto com a estrutura mcreq que fornece uma API unificada para alocar, liberar, analisar e reprogramar pacotes para servidores individuais.

Filas e buffers de pacotes

Os pacotes agora são inseridos em uma fila (ou em um mc_PIPELINE) que contém a ordenação dos pacotes como uma lista vinculada. Os pacotes são adicionados à fila na ordem em que são agendados.

Como a eficiência de E/S é melhor com buffers contíguos, o mc_PACKET não contém o buffer em seu próprio objeto, mas sim um ponteiro especial para uma região em um buffer contíguo gerenciado por um alocador contíguo especial em ordem. Isso permite que os pacotes vivam como objetos "independentes" e, ao mesmo tempo, que seus dados de rede reais sejam compactados em sequência. Assim como os próprios buffers de rede, cada objeto de pacote também é alocado usando uma instância separada desse alocador.

O alocador reside no netbuf que também contém estruturas e rotinas para lidar com fragmentos de buffer de forma eficiente e prepará-los adequadamente para serem enviados à rede, enquanto lida com condições como envios parciais.

Aprimoramentos de E/S

O sistema de E/S foi refatorado e modularizado dentro do lcbio módulo (src/lcbio). A adição notável é a do lcbio_CTX que contém rotinas eficientes e unificadas para leituras, gravações e tratamento de erros de soquetes, abstraindo o modelo de E/S subjacente (por exemplo, baseado em conclusão, como IOCP ou libuv, ou baseado em eventos, como select ou libevent) de sua API.

Robustez durante alterações de configuração e falhas

As alterações de configuração e as falhas agora são tratadas com elegância. Quando uma nova configuração é recebida e o objeto de servidor relacionado (mc_SERVER) precisa mudar de posição, sua conexão TCP é mantida intacta e é percorrida por todos os comandos (pacotes) que não são mais mapeados para ela. Para cada um desses comandos, a estrutura mc_PACKET é duplicada e colocada na fila adequada, enquanto o buffer de envio possivelmente subjacente ainda é enviado para a rede e sua resposta é ignorada. Isso nos permite manter o fluxo TCP intacto e simplesmente engolir a resposta de erro relacionada (e prevista) proveniente do servidor.

Se uma conexão TCP for interrompida repentinamente e nenhuma nova configuração for recebida, os pacotes relacionados poderão ser colocados em uma fila de repetição ou falharam imediatamente. Os comandos que são repetidos e os que falham podem ser configurados pelo usuário.

O comportamento durante a operação em um cluster degradado também foi aprimorado. Agora, as operações que são roteadas para nós ausentes são colocadas na fila e a biblioteca emitirá de forma transparente uma solicitação de configuração para o cluster, permitindo que o aplicativo tente novamente o item sem executar etapas adicionais.

Mais testes

Como essa versão da biblioteca foi refatorada para modularizar o maior número possível de sistemas, isso significa que o teste de cada um dos módulos se torna mais simples, pois eles têm um comportamento mais bem definido e menos dependências. Foram adicionados muitos testes novos dedicados ao gerenciamento de buffer, ao tratamento de pacotes e ao tratamento de E/S bruta. Todos esses testes não fazem uso da função CouchbaseMock servidor ou quaisquer recursos externos, mas são totalmente contidos e determinísticos.

Nova documentação da API

A documentação da API agora é gerada via Doxygen. O Doxygen é um gerador de documentação de código aberto para várias plataformas que gera documentação de API com base nos comentários do código-fonte. Isso permitirá que a documentação da nossa API seja mais atualizada, de modo que, desde que uma nova API seja adicionada e contenha comentários, ela aparecerá na documentação da API e, se uma API mais antiga for removida, ela desaparecerá da documentação.

Além disso, adicionamos formalmente atributos da interface para todas as nossas APIs para ajudá-lo a determinar a estabilidade e o roteiro de uma determinada chamada de API. Isso nos permite identificar claramente se uma interface específica é experimental (ou volátil), ou se pode ser usado no código de produção com a certeza de que não será modificado ou removido em versões posteriores.

Novos recursos

Suporte a SSL para o Couchbase Enterprise 3.0

A versão 2.4 contém suporte (via OpenSSL) para se comunicar com o servidor usando o protocolo SSL. O suporte a SSL é implementado inteiramente em uma das camadas dentro de lcbio e, portanto, reside embaixo lcbio_CTX. Dessa forma, o suporte a SSL é praticamente transparente para a maioria dos sistemas da biblioteca. Por padrão, a biblioteca ainda se conectará em um modo não criptografado (no entanto, sua senha SASL ainda será criptografada, se possível)

Suporte à cadeia de conexão

Também é novidade o suporte a uma nova maneira de especificar como se conectar ao cluster. À medida que mais e mais opções de conexão são adicionadas à biblioteca, foi necessário fornecer um formato uniforme para que os usuários declarassem como e o que desejam usar ao se conectar ao cluster. Brett Lawson propôs um novo URI-like que permite especificar as opções de conexão em um formato claro, conciso e não ambíguo. O uso de um formato URI permite coisas como a possibilidade de especificar essas configurações em um arquivo de configuração (para que você não precise analisar manualmente várias configurações e depois combiná-las com os campos de estrutura apropriados).

Como a libcouchbase é usada principalmente como uma camada central de bibliotecas de nível superior (como Python, Node.JS e Ruby), a exposição de uma opção de conexão de string facilita que todas essas linguagens compartilhem uma interface comum e uma base de código comum ao especificar como se conectar ao cluster.

Como demonstração, uma string de conexão como couchbase://foo.com,bar.com,baz.com/mybucket?operation_timeout=5000000&detailed_errcodes=true  usará foo.combar.combaz.com como nós para se conectar ao bucket meu cesto, aplicando um tempo limite de operação de 5 segundos e ativando códigos de erro detalhados (outro novo recurso da biblioteca).

Nova API de operação comum

Um novo conjunto de APIs de solicitação (voláteis) foi adicionado nesta versão para formar a base das APIs da próxima versão principal da biblioteca. Essas APIs operam em um único comando por vez e seguem um padrão de entrada/saída, em que um usuário "entra" em um contexto de agendamento, agenda vários comandos e depois "sai". Em contraste com as APIs 2.x, em que cada comando agendava implicitamente uma descarga para a rede, essas novas APIs só agendam uma descarga quando "saem" do contexto atual. Isso permite a construção eficiente de várias operações em lote sem a necessidade de alocar uma matriz de estruturas de comando para isso; por exemplo.

Além disso, as novas APIs de solicitação e resposta permitem a reutilização de código em operações comuns, criando uma ABI comum para as estruturas de solicitação e resposta. Nessa nova API, todas as estruturas de solicitação são compatíveis com o layout da lcb_CMDBASE  e todas as estruturas de resposta são compatíveis com o layout do lcb_RESPBASE estrutura. Da mesma forma, o novo mecanismo de retorno de chamada permite que um único retorno de chamada manipule mais de um tipo de operação, em que o retorno de chamada recebe uma constante inteira indicando o tipo de operação e um lcb_RESPBASE que pode ser convertida para a estrutura de resposta específica da operação apropriada, se necessário.

#include
#inclui
#inclui
#includestatic void
op_callback(lcb_t instance, int cbtype, const lcb_RESPBASE *resp)
{
fprintf(stderr, "Obteve o resultado para a chave %.*s com o código 0x%xn",
(int)resp->nkey, resp->key, resp->rc);
se (resp->rc != LCB_SUCCESS) {
retorno;
}

Se (cbtype == LCB_CALLBACK_GET) {
const lcb_RESPGET *gresp = (const lcb_RESPGET *)resp;
fprintf(stderr, "RETRIEVED ITEMn");
fprintf(stderr, "VALUE: %.*snFLAGS: 0x%xnCAS=0x%lxn",
(int)gresp->nvalue, gresp->value, gresp->itmflags, gresp->cas);
} else if (cbtype == LCB_CALLBACK_STORE) {
fprintf(stderr, "STORED ITEMn");
fprintf(stderr, "CAS: 0x%lxn", resp->cas);
}
}

int main(void)
{
instância lcb_t;
não assinado ii;
struct lcb_create_st cropts = { 0 };
lcb_error_t err;

cropts.v.v3.connstr = "couchbase://10.0.0.99/default";
lcb_create(&instance, &cropts);
lcb_connect(instance);
lcb_wait(instance);
lcb_install_callback3(instance, LCB_CALLBACK_GET, op_callback);
lcb_install_callback3(instance, LCB_CALLBACK_STORE, op_callback);

for (ii = 0; ii < 10; ii++) {

lcb_CMDSTORE store_cmd = { 0 };
lcb_CMDGET get_cmd = { 0 };
char buf[1024];
size_t nbuf;

sprintf(buf, "Key_%d", ii);
nbuf = strlen(buf);

LCB_CMD_SET_KEY(&store_cmd, buf, nbuf);
LCB_CMD_SET_VALUE(&store_cmd, "Value", strlen("Value"));
store_cmd.operation = LCB_SET;
err = lcb_store3(instance, NULL, &store_cmd);
Se (err != LCB_SUCCESS){
pausa;
}
LCB_CMD_SET_KEY(&get_cmd, buf, nbuf);
err = lcb_get3(instance, NULL, &get_cmd);
se (err != LCB_SUCCESS) {
pausa;
}
}
Se (err == LCB_SUCCESS) {
lcb_sched_leave(instance);
lcb_wait(instance);
} else {
lcb_sched_fail(instance);
}
lcb_destroy(instance);
retornar 0;
}

Manuseio eficiente da carga útil

Vários recursos foram introduzidos no cliente 2.4 para permitir o manuseio mais eficiente da carga útil entre o aplicativo e a biblioteca. Por padrão, a biblioteca copiará o valor de um definir de modo a não exigir que o buffer de valor passado permaneça na memória válida durante toda a operação. Da mesma forma para obter o aplicativo deve copiar o buffer de valores se quiser que os dados persistam fora do retorno de chamada.

Foi adicionado um suporte experimental que permite que você indique a biblioteca não para copiar o buffer de valores (para definir) por meio das operações lcb_VALBUF estrutura (fornecido como um campo dentro do lcb_CMDSTORE) estrutura:.

Da mesma forma, existe um campo adicional no lcb_RESPGET estrutura chamada bufh. Esse campo contém um ponteiro opaco para um alça do buffer. Esse identificador de buffer pode ser definido para persistir externo do retorno de chamadapermitindo que os dados da resposta permaneçam válidos até que o próprio identificador do buffer seja liberado. Internamente, isso usa uma contagem de referência

Despacho de pacotes brutos

Agora você pode fornecer pacotes memcached brutos à libcouchbase para enviar a um servidor e receber um pacote memcached bruto como resposta. Isso permite acesso de nível inferior à funcionalidade do pacote e permite que você crie um servidor proxy. O recurso é implementado de forma que os buffers de resposta não sejam copiados para a chamada de retorno e possam ser mantidos ativos fora da chamada de retorno, de modo que não seja necessário copiar as respostas GET em um buffer temporário para processamento. Da mesma forma, o próprio pacote de solicitação também pode, opcionalmente, não ser copiado, mas ter uma chamada de retorno invocada quando não for mais necessário para a biblioteca.

Novas APIs de configuração de cluster

Uma nova chamada de retorno foi adicionada à biblioteca, notificando o usuário se o bootstrap inicial foi bem-sucedido ou falhou. Isso era feito anteriormente usando a função retorno de chamada de erro (lcb_set_error_callback()) e o retorno de chamada de configuração (lcb_set_configuration_callback)A chamada de retorno de erro seria invocada em um erro inicial e a chamada de retorno de configuração seria invocada quando o cluster recebesse uma nova configuração. No entanto, a chamada de retorno de erro também seria chamada toda vez que um nó específico falhasse, fazendo com que os clientes falhassem prematuramente se vários nós fossem passados e apenas o primeiro da lista falhasse. O novo retorno de chamada do bootstrap é chamado apenas uma vez e somente durante a criação inicial com um código de erro definido que indica o sucesso ou a falha do bootstrap. Para clientes não assíncronos, você pode simplesmente usar lcb_get_bootstrap_status() e não precisar depender de um retorno de chamada:

instância lcb_t;
struct lcb_create_st cropt = {
.versão = 3,
.v.3.dsn = "couchbase://cbnode1,cbnode2/mybucket"
};
lcb_error_t err = lcb_create(&instance, &cropt);
se (err != LCB_SUCCESS) {
// tratar o erro;
}
#if I_AM_BLOCKING
err = lcb_connect(instance);
lcb_wait(instance);
Se ((err = lcb_get_bootstrap_status(instance)) != LCB_SUCCESS)
{
printf("Failed to bootstrap: %sn", lcb_strerror(instance, err));
}
// fazer comandos
#else /* SOU ASYNC */
static void bootstrap_callback(lcb_t instance, lcb_error_t err) {
se (err != LCB_SUCCESS) {
printf("Não foi possível fazer o bootstrap");
} else {
lcb_GETCMD gcmd = { 0 };
LCB_KREQ_SIMPLE(&req.key, "foo", 3);
lcb_sched_enter(instance);
lcb_get3(instance, NULL, &gcmd);
lcb_sched_leave(instance);
}
}
lcb_set_bootstrap_callback(instance, bootstrap_callback);
lcb_connect(instance); // Retornar ao loop de eventos ou chamar lcb_wait()
#endif

Além disso, um lcb_refresh_config() foi adicionada para forçar o cliente a solicitar uma nova configuração do cluster. Isso é útil para "forçar" uma reconfiguração nos casos em que muitos tempos limite estão sendo encontrados ou para impor uma política de atualização personalizada no aplicativo.

Por fim, o vbucket A API foi exposta, permitindo a inspeção da configuração atual que está sendo usada pela biblioteca. A nova API está localizada em libcouchbase/vbucket.h (dentro do diretório de cabeçalhos). 

#include
lcbvb_CONFIG *config;
lcb_error_t err;
err = lcb_cntl(instance, LCB_CNTL_GET, LCB_CNTL_VBCONFIG, &config);
// Verificar erro
printf("A revisão da configuração atual é %dn", lcbvb_get_revision(config));
printf("Cluster has %u serversn", lcbvb_get_nservers(config));

Você também pode usar o revisão para determinar se o cliente recebeu uma nova configuração.

Autor

Postado por Mark Nunberg, engenheiro de software, Couchbase

Mark Nunberg é um engenheiro de software que trabalha na Couchbase. Ele mantém a biblioteca do cliente em C (libcouchbase), bem como o cliente em Python. Ele também desenvolveu o cliente Perl (para uso em sua empresa anterior), o que o levou inicialmente a trabalhar no Couchbase. Antes de ingressar no Couchbase, ele trabalhou em sistemas de roteamento distribuídos e de alto desempenho em uma empresa de análise de comércio eletrônico. Mark estudou Linguística na Universidade Hebraica de Jerusalém.

3 Comentários

  1. Aliaksey Kandratsenka junho 20, 2014 em 3:05 am

    Parece bom. Quero tentar reescrever o maxi/mc-loader com ele. No entanto, não tenho certeza se terei tempo.

    1. Eu certamente recomendaria tentar refazer o moxi com os novos recursos. Na verdade, escrevi um pequeno clone do moxi em C++ chamado \"epoxy\": https://github.com/mnunberg/ep

  2. [...] Se você estiver acompanhando, uma versão prévia da biblioteca para desenvolvedores foi lançada no mês passado. Ela continha uma série de melhorias sobre as quais você pode ler aqui. [...]

Deixar uma resposta