libcouchbase com C++ e threads (1/2)

Decidi brincar um pouco na semana passada, tentando criar um conjunto mais padrão de ligações C++ para a libcouchbase.

Embora a libcouchbase seja C e, portanto, totalmente utilizável em C++, eu tinha uma coceira comum e frequente para coçar quando usava a libcouchbase em programas C++ - ou seja, não há hierarquia de classes para objetos de comando ou resposta e a interface da libcouchbase dificilmente parece "amigável". Por isso, iniciei um projeto para criar uma interface padrão e genérica (no sentido coloquial do termo) para o libcouchbase em C++. Esse é um trabalho em andamento e pode ser encontrado em https://github.com/couchbaselabs/lcb-cxx.

Como a compatibilidade máxima com o C++ era desejada, evitei usar bibliotecas externas grandes, como impulso ou C++11. Essas ligações extras sempre podem ser colocadas em camadas sobre as ligações "genéricas" do C++, mas reverter o processo pode ser mais difícil.

O resultado foi um conjunto de associações que expôs a seguinte semântica:

Objetos de comando

Todos os comandos são herdados de um objeto Command; por exemplo

class Command { };

Todos os comandos de chave (ou seja, set, get, delete) são herdados de um KeyCommand que deriva do objeto Comando. O KeyCommand tem acessores para key e hashkey, por exemplo

 
classe KeyCommand : público Comando {
    virtual vazio setKey(const padrão::string&) = 0;
    virtual vazio setHashKey(const padrão::string&) = 0;
}

Três classes de modelo foram criadas para ajudar na construção dos objetos de comando. Elas são instanciadas com seu T sendo a estrutura libcouchbase do C, que elas envolvem como seu único membro de dados, garantindo assim que o desempenho e o perfil de memória da classe de comando do C++ sejam mais ou menos os mesmos da estrutura do C (embora haja uma vtable). Esses modelos fornecem definidores comuns para comandos que aceitam CAS e/ou um tempo de expiração, por exemplo

 
modelo <typename T> KeyCommand_v0 {
público:
       vazio setKey(const padrão::string &s) {
           cmd.v.v0.chave = s.c_str();
           cmd.v.v0.nkey = s.tamanho();
      }
      // …
privado:
    T cmd;
};
Objetos de resposta

Assim como os objetos de comando, os objetos de resposta também são fornecidos em uma hierarquia; eles contêm o C lcb_resp_t * como seu único membro de dados. Sua hierarquia é a seguinte:

  1. O resumo ResponseBase classe. Ela apresenta acessores para chaves
  2. O resumo CasResponseBase que herda a classe ResponseBase e fornece acessores para o CAS
  3. O Resposta classe que implementa o ResponseBase, recuperando as informações de chave do T::v.v0.key
  4. O CasResponse que herda de Resposta e implementa o CasResponseBase, fornecendo cas via T::v.v0.cas
  5. Classes específicas de resposta que fornecem informações adicionais; por exemplo GetResponse é implementado como CasResponse com acessores adicionais para o valor e os sinalizadores.

No cabeçalho, isso se parece com o seguinte:

 
classe ResponseBase {
público:
    virtual const vazio *getKey(lcb_size_t *n) const = 0;
    padrão::string getKey() const;
};
modelo <typename T, classe I>
classe Resposta : público I {
público:
    typedef T LcbInternalResponse;
    virtual const vazio * getKey(lcb_size_t *n) const {
        *n = resp>v.v0.nkey;
        retorno resp>v.v0.chave;
    }
protegida:
    const T * resp;
};
modelo <typename T>
classe CasResponse : público Resposta<T, CasResponseBase>
{
público:
    virtual lcb_cas_t getCas() const {
        retorno Resposta<T,CasResponseBase>::getRawResponse()>v.v0.cas;
    }
};
 
classe ArithmeticResponse : público CasResponse<C_ArithResp> {
público:
    lcb_uint64_t getValue() const { retorno getRawResponse()>v.v0.valor; }
};
 
 

Como as classes de resposta são derivadas dos modelos e de suas bases abstratas puras, elas podem ter seus membros comuns tratados por métodos e classes auxiliares, de modo que, por exemplo, para uma determinada função chamada logKey, que registra a chave da resposta, ela pode ser implementada assim:

 
vazio logKey(ResponseBase *resp) {
   padrão::cout << resp>getKey() << padrão::endl;
}

E, em seguida, logKey pode ser chamado com qualquer objeto de resposta.

Chamadas de retorno

Por fim, também implementei uma interface de retorno de chamada. Como a libcouchbase é uma biblioteca em C e usa retornos de chamada em C, o seguinte boilerplate para código C++ era bastante comum

externo "C" {
estático vazio manipulador de aritmética(lcb_t, const vazio *cookie, lcb_error_t err, const lcb_arithmetic_response_t *resp) {
    MyCppObject *o = reinterpretar_cast<MyCppObject>(const_cast<vazio*>(biscoito));
    o>doSomething(resp);
}
} // extern "C"

em seguida, para definir o retorno de chamada

lcb_set_arithmetic_callback(instância, manipulador de aritmética);

Nas novas associações, os retornos de chamada são expostos em um objeto unificado, de modo que você não precisa definir explicitamente os manipuladores, mas simplesmente subclasse a classe ResponseHandler e implementar o onArithmetic(OperationContext *, const ArithmeticResponse *, lcb_error_t) método.

Se não quiser implementar manipuladores dedicados para comandos genéricos, você pode simplesmente implementar o onDefault(OperationContext *, const ResponseBase *, lcb_error_t) e manipular todos os comandos a partir daí.

Compartilhe este artigo
Receba atualizações do blog do Couchbase em sua caixa de entrada
Esse campo é obrigatório.

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.

Um comentário

  1. [...] Postagem de blog da semana #2: libcouchbase com C++ e threads (1/2)Pergunta da semana: Pergunta sobre o custo de tempo do rebalanceamento de swap [...]

Deixe um comentário

Pronto para começar a usar o Couchbase Capella?

Iniciar a construção

Confira nosso portal do desenvolvedor para explorar o NoSQL, procurar recursos e começar a usar os tutoriais.

Use o Capella gratuitamente

Comece a trabalhar com o Couchbase em apenas alguns cliques. O Capella DBaaS é a maneira mais fácil e rápida de começar.

Entre em contato

Deseja saber mais sobre as ofertas do Couchbase? Deixe-nos ajudar.