libcouchbase 2.4.0 ya está aquí. Ofrece grandes mejoras arquitectónicas y varias novedades, mejorando respecto a versiones anteriores.
Este blog fue escrito originalmente para la versión 2.4.0 DP1, se ha modificado para reflejar las diferencias entre la vista previa para desarrolladores y la versión actual GA (2.4.0)
Enlaces de descarga directa: http://packages.couchbase.com/clients/c/index.html
Documentación de la API: http://docs.couchbase.com/sdk-api/couchbase-c-client-2.4.0/
Mejoras internas
Estructuras de paquetes
Nombre en clave packet-ngEsta versión de libcouchbase comenzó como un intento de refactorizar el manejo de paquetes de tal manera que los paquetes fueran considerados objetos de primera clase. El paquete de petición es la divisa central de la librería ya que une la cookie solicitada por el usuario junto con la respuesta del servidor.
En 2.4, los paquetes de solicitud se encapsulan en el paquete mc_PACKET que contiene información sobre la cookie, los buffers para el paquete en sí, y el estado del paquete (es decir, recibido, vaciado, reintentado, error, pendiente). La estructura del paquete viene junto con el mcreq que proporciona una API unificada para asignar, liberar, analizar y reprogramar paquetes a servidores individuales.
Colas de paquetes y búferes
Los paquetes se insertan ahora en una cola (o en un mc_PIPELINE) que contiene la ordenación de los paquetes como una lista enlazada. Los paquetes se añaden a la cola en el orden en que están programados.
Dado que la eficiencia de E/S es mejor con búferes contiguos, el mc_PACKET no contiene el búfer dentro de su propio objeto, sino un puntero especial a una región dentro de un búfer contiguo gestionado por un asignador contiguo especial en orden. Esto permite que los paquetes vivan como objetos "independientes" mientras que sus datos de red reales están empaquetados en secuencia. Al igual que los búferes de red, cada objeto paquete se asigna utilizando una instancia separada de este asignador.
El asignador vive en el netbuf que también contiene estructuras y rutinas para manejar eficientemente fragmentos de búfer y prepararlos adecuadamente para ser enviados a la red, a la vez que maneja condiciones tales como envíos parciales.
Mejoras de E/S
El sistema de E/S se ha refactorizado y modularizado dentro del lcbio módulo (src/lcbio). La adición notable es la del lcbio_CTX que contiene rutinas eficientes y unificadas para lecturas, escrituras y gestión de errores de sockets, abstrayendo el modelo de E/S subyacente (por ejemplo, basado en finalización como IOCP o libuv; o basado en eventos como select o libevent) de su API.
Robustez ante cambios de configuración y fallos
Los cambios de configuración y los fallos se gestionan ahora con elegancia. Cuando se recibe una nueva configuración y el objeto servidor relacionado (mc_SERVIDOR) necesita cambiar de posición, su conexión TCP se mantiene intacta, y se recorre en busca de cualquier comando (paquete) que ya no esté asignado a ella. Para cada uno de esos comandos, la estructura mc_PACKET se duplica y se coloca en la cola adecuada, mientras que el posible búfer de envío subyacente se sigue enviando a la red y su respuesta se ignora. Esto nos permite mantener el flujo TCP intacto y simplemente tragarnos la respuesta de error relacionada (y anticipada) procedente del servidor.
Si una conexión TCP se interrumpe repentinamente y no ha llegado ninguna nueva configuración, los paquetes relacionados pueden colocarse dentro de una cola de reintento o fallan inmediatamente. El usuario puede configurar qué comandos se reintentan y cuáles fallan.
También se ha mejorado el comportamiento mientras se opera en un clúster degradado. Ahora las operaciones que se enrutan a nodos que faltan se colocan en la cola y la biblioteca emitirá de forma transparente una solicitud de configuración al clúster, lo que permite a la aplicación volver a intentar el elemento sin realizar pasos adicionales.
Más pruebas
Como esta versión de la librería ha sido refactorizada para modularizar tantos sistemas como sea posible, significa que probar cada uno de los módulos se vuelve más simple ya que tienen un comportamiento más bien definido y menos dependencias. Se han añadido muchas pruebas nuevas dedicadas a la gestión de búferes, el manejo de paquetes y el manejo de E/S sin procesar. Todas estas pruebas no hacen uso del CouchbaseMock servidor o cualquier recurso externo, sino que son totalmente contenidos y deterministas.
Nueva documentación de la API
La documentación de la API se genera ahora a través de Doxygen. Doxygen es un generador de documentación multiplataforma de código abierto que genera documentación de API basada en los comentarios del código fuente. Esto permitirá que nuestra documentación de la API esté más actualizada, de modo que siempre que se añada una nueva API y contenga comentarios, aparecerá en la documentación de la API, y si se elimina una API antigua, desaparecerá de ella.
Además, hemos añadido formalmente atributos de la interfaz a todas nuestras API para ayudarle a determinar la estabilidad y la hoja de ruta de una determinada llamada a la API. Esto nos permite saber claramente si una interfaz concreta es experimental (o volátil), o si puede utilizarse en código de producción con la confianza de que no se modificará o eliminará en versiones posteriores.
Novedades
Soporte SSL para Couchbase Enterprise 3.0
La versión 2.4 contiene soporte (a través de OpenSSL) para comunicarse con el servidor utilizando el protocolo SSL. El soporte SSL se implementa completamente en una de las capas dentro de lcbio y por lo tanto reside debajo de lcbio_CTX. Como tal, el soporte SSL es virtualmente transparente para la mayoría de los sistemas de la biblioteca. Por defecto, la biblioteca se conectará en modo no encriptado (aunque su contraseña SASL seguirá encriptada si es posible).
Soporte de cadenas de conexión
También es nuevo el soporte para una nueva forma de especificar cómo conectarse al clúster. Como cada vez se añaden más opciones de conexión a la biblioteca, era necesario proporcionar un formato uniforme para que los usuarios declaren cómo y qué quieren utilizar al conectarse al clúster. Brett Lawson propuso un nuevo URI-como que permite especificar las opciones de conexión en un formato claro, conciso y sin ambigüedades. El uso de un formato URI permite cosas como poder especificar estas opciones dentro de un archivo de configuración (para no tener que analizar manualmente múltiples opciones y luego hacerlas coincidir con los campos struct apropiados).
Dado que libcouchbase se utiliza principalmente como capa central de bibliotecas de nivel superior (como Python, Node.JS y Ruby), exponer una opción de conexión de cadena facilita que todos estos lenguajes compartan una interfaz y una base de código comunes a la hora de especificar cómo conectarse al clúster.
Como demostración, una cadena de conexión como couchbase://foo.com,bar.com,baz.com/mybucket?operation_timeout=5000000&detailed_errcodes=true utilizará foo.com, bar.comy baz.com como nodos para conectarse al cubo mybucketLa biblioteca también ofrece la posibilidad de introducir códigos de error detallados (otra novedad de la biblioteca).
Nueva API de operaciones comunes
En esta versión se ha añadido un nuevo conjunto de API de peticiones (volátiles) que constituirán la base de las API de la próxima versión principal de la biblioteca. Estas API operan con un único comando cada vez y siguen un patrón de entrada/salida, en el que un usuario "entra" en un contexto de programación, programa un grupo de comandos y luego "sale". A diferencia de las API de la versión 2.x, en las que cada orden programaba implícitamente una descarga en la red, estas nuevas API sólo programan una descarga cuando "abandonan" su contexto actual. Esto permite la construcción eficiente de múltiples operaciones por lotes sin tener que asignar una matriz de estructuras de comandos para hacerlo; así por ejemplo.
Además, las nuevas API de solicitud y respuesta permiten la reutilización de código en operaciones comunes al hacer una ABI común para las estructuras de solicitud y respuesta. En esta nueva API, todas las estructuras de solicitud son compatibles con la estructura lcb_CMDBASE y todas las estructuras de respuesta son compatibles con el diseño del lcb_RESPBASE estructura. Asimismo, el nuevo mecanismo de retrollamada permite que una sola retrollamada gestione más de un tipo de operación, en la que a la retrollamada se le pasa una constante entera que indica el tipo de operación, y una variable lcb_RESPBASE que, en caso necesario, puede convertirse en la estructura de respuesta específica de la operación.
1TP5Incluido
1TP5Incluido
#includestatic void
op_callback(lcb_t instance, int cbtype, const lcb_RESPBASE *resp)
{
fprintf(stderr, "Obtenido resultado para la clave %.*s con código 0x%xn",
(int)resp->nkey, resp->key, resp->rc);
if (resp->rc != LCB_SUCCESS) {
volver;
}
if (cbtype == LCB_CALLBACK_GET) {
const lcb_RESPGET *gresp = (const lcb_RESPGET *)resp;
fprintf(stderr, "ITEMn RETORNADO");
fprintf(stderr, "VALOR: %.*snFLAGS: 0x%xnCAS=0x%lxn",
(int)gresp->nvalue, gresp->value, gresp->itmflags, gresp->cas);
} else if (cbtype == LCB_CALLBACK_STORE) {
fprintf(stderr, "ALMACENADO ITEMn");
fprintf(stderr, "CAS: 0x%lxn", resp->cas);
}
}
int main(void)
{
lcb_t instancia;
sin firmar 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(instancia);
lcb_wait(instancia);
lcb_install_callback3(instancia, LCB_CALLBACK_GET, op_callback);
lcb_install_callback3(instancia, LCB_CALLBACK_STORE, op_callback);
for (ii = 0; ii < 10; ii++) {
lcb_CMDSTORE almacenar_cmd = { 0 };
lcb_CMDGET get_cmd = { 0 };
char buf[1024];
size_t nbuf;
sprintf(buf, "Clave_%d", ii);
nbuf = strlen(buf);
LCB_CMD_SET_KEY(&store_cmd, buf, nbuf);
LCB_CMD_SET_VALUE(&store_cmd, "Valor", strlen("Valor"));
store_cmd.operation = LCB_SET;
err = lcb_store3(instancia, NULL, &store_cmd);
if (err != LCB_SUCCESS){
romper;
}
LCB_CMD_SET_KEY(&get_cmd, buf, nbuf);
err = lcb_get3(instancia, NULL, &get_cmd);
if (err != LCB_SUCCESS) {
romper;
}
}
if (err == LCB_SUCCESS) {
lcb_sched_leave(instancia);
lcb_wait(instancia);
} else {
lcb_sched_fail(instancia);
}
lcb_destroy(instancia);
Devuelve 0;
}
Manipulación eficiente de la carga útil
Se han introducido varias características en el cliente 2.4 para permitir un manejo más eficiente de la carga útil entre la aplicación y la biblioteca. Por defecto, la biblioteca copiará el valor de un archivo configure con el fin de no requerir que el búfer de valores pasados permanezca en memoria válida durante toda la operación. Del mismo modo, para consiga la aplicación debe copiar el búfer de valores si desea que los datos persistan fuera de la llamada de retorno.
Se ha añadido un soporte experimental que permite indicar a la biblioteca no para copiar el búfer de valores (para configure) mediante la función lcb_VALBUF estructura (proporcionado como un campo dentro del lcb_CMDSTORE) estructura:.
Asimismo, existe un campo adicional dentro del lcb_RESPGET estructura denominada bufh. Este campo contiene un puntero opaco a un asa de tope. Este manejador de búfer puede ser configurado para persistir fuera de de la devolución de llamadalo que permite que los datos de respuesta sigan siendo válidos hasta que el propio manejador del búfer se publicado. Internamente esto utiliza un recuento de referencia
Envío de paquetes sin procesar
Ahora puede dar a libcouchbase paquetes memcached sin procesar para enviar a un servidor y recibir un paquete memcached sin procesar como respuesta. Esto permite un acceso de bajo nivel a la funcionalidad de paquetes y le permite construir un servidor proxy. La función está implementada de tal forma que los buffers de respuesta no se copian a la llamada de retorno y pueden mantenerse vivos fuera de la llamada de retorno, de forma que no es necesario copiar las respuestas GET a un buffer temporal para procesarlas. Del mismo modo, el propio paquete de petición también puede no ser copiado, pero tener una llamada de retorno invocada cuando ya no es necesario por la biblioteca.
Nuevas API de configuración de clústeres
Se ha añadido un nuevo callback a la librería que notifica al usuario si el bootstrap inicial ha tenido éxito o ha fallado. Anteriormente, esto se hacía mediante la función devolución de llamada de error (lcb_set_error_callback()) y el llamada de configuración (lcb_set_configuration_callback)El callback de error se invocaría cuando se produjera un error inicial, y el callback de configuración se invocaría cuando el cluster recibiera una nueva configuración. Sin embargo, la llamada de retorno de error también sería invocada cada vez que un nodo específico fallara, haciendo que los clientes fallaran prematuramente si se pasaban múltiples nodos y sólo fallaba el primero de la lista. La nueva callback de arranque se invoca una sola vez, y sólo durante la creación inicial con un código de error definido que indica el éxito o el fracaso del arranque. Para los clientes no asíncronos puede utilizar simplemente lcb_get_bootstrap_status() y no tener que depender de una devolución de llamada:
struct lcb_create_st cropt = {
.versión = 3,
.v.3.dsn = "couchbase://cbnode1,cbnode2/mybucket"
};
lcb_error_t err = lcb_create(&instance, &cropt);
if (err != LCB_SUCCESS) {
// gestionar error;
}
#if I_AM_BLOCKING
err = lcb_connect(instancia);
lcb_wait(instancia);
if ((err = lcb_get_bootstrap_status(instance)) != LCB_SUCCESS)
{
printf("Error al arrancar: %sn", lcb_strerror(instance, err));
}
// hacer comandos
#else /* SOY ASYNC */
static void bootstrap_callback(lcb_t instance, lcb_error_t err) {
if (err != LCB_SUCCESS) {
printf("No se pudo arrancar");
} else {
lcb_GETCMD gcmd = { 0 };
LCB_KREQ_SIMPLE(&req.key, "foo", 3);
lcb_sched_enter(instancia);
lcb_get3(instancia, NULL, &gcmd);
lcb_sched_leave(instancia);
}
}
lcb_set_bootstrap_callback(instancia, bootstrap_callback);
lcb_connect(instance); // Volver al bucle de eventos, o llamar a lcb_wait()
#endif
Además, un lcb_refresh_config() para forzar al cliente a solicitar una nueva configuración del clúster. Esto es útil para "forzar" una reconfiguración en los casos en que se encuentran muchos tiempos de espera, o para hacer cumplir una política de actualización personalizada dentro de la aplicación.
Por último, el vbucket que permite inspeccionar la configuración actual utilizada por la biblioteca. La nueva API se encuentra en libcouchbase/vbucket.h (dentro del directorio headers).
lcbvb_CONFIG *config;
lcb_error_t err;
err = lcb_cntl(instancia, LCB_CNTL_GET, LCB_CNTL_VBCONFIG, &config);
// Comprobar error
printf("La revisión de la configuración actual es %dn", lcbvb_get_revision(config));
printf("El cluster tiene %u serversn", lcbvb_get_nservers(config));
También puede utilizar la función revisión para determinar si el cliente ha recibido una nueva configuración.
Tiene buena pinta. Quiero intentar reescribir maxi/mc-loader con él. No estoy seguro de si voy a encontrar tiempo sin embargo.
Sin duda recomendaría intentar rehacer moxi con las nuevas características. De hecho he escrito un pequeño clon de moxi en C++ llamado "epoxy": https://github.com/mnunberg/ep…
[...] Si nos has estado siguiendo, el mes pasado se publicó una versión preliminar para desarrolladores de la biblioteca. Contenía un montón de mejoras que puedes leer aquí. [...]