Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

node-db: La excusa perfecta para hablar de C++ y Node.js

3,220 views

Published on

Un ejemplo de amistad entre C++ y Node.jsEsta charla introduce a node-db, una libreria para Node.js que busca ofrecer un soporte unificado a multiples bases de datos relacionales (MySQL y Oracle entre ellas), como una excusa para entrar al tema de fondo: el desarrollo de plugins para Node. js utilizando C++ y el motor V8

Published in: Technology
  • Be the first to comment

node-db: La excusa perfecta para hablar de C++ y Node.js

  1. 1. node­db La excusa perfecta para hablar de C++ y  Node.js    @mgiglesias
  2. 2. Se dice de mi Que soy nerd Que me gusta Apple Sí, ¡ni te imaginás cuánto! Que soy de opinar @mgiglesias es una mescolanza preocupante Que todos los lenguajes me quedan bien Duh! ¿De qué era esta charla? Que está en algún que otro proyecto FOSS   
  3. 3. Se dice de mi Le sobraba el tiempo, y arrancó WORKANA Che, es http://workana.com Le gusta Seinfeld Y los zombies :­/ Se mandó a mudar a Miramar Se encerró en un baño de un avión   
  4. 4. Cortá el chamullo ¿De qué voy a hablar? Node­db Node.js + C++   
  5. 5. Había una vez un Alemán @felixge   
  6. 6. Propuesta node­db API C++ unificada Separar lo intrínseco de los protocolos Librerías DB blocking y non blocking API en JS land sencillo Performance Solo relacionales MySQL Oracle   
  7. 7. A laburar$ npm install db­mysqlvar dbmysql = require(db­mysql);new dbmysql.Database({ hostname: localhost, user: root, password: password, database: node}).connect(function(error, server) { if (error) { throw new Error(ERROR:  + error); } console.log(server);});{ version: 5.5.24,  hostname: localhost,  user: root,      database: node }
  8. 8. Pooleando conexionesvar mysql = require(db­mysql),    generic_pool = require(generic­pool);var pool = generic_pool.Pool({    name: mysql,    max: 10,    create: function(callback) {        new mysql.Database({ … }).connect(function(err, server) {  callback(err, this);  });    },    destroy: function(db) {        db.disconnect();    }});pool.acquire(function(err, db) { pool.release(db);});    
  9. 9. A consultar se ha dichodb.query()        .select(["id", "user", "email"])        .from("users")        .where("role IN ?", [ ["administrator", "user"] ])        .and("created > ?", [ new Date(2011, 1, 1) ])        .execute(function(error, rows, columns){            if (error) {                console.log(ERROR:  + error);                return;            }            // Hacer algo mas interesante        }); http://nodejsdb.org   
  10. 10. ¿Qué hay detrás del telón? db­mysql.js exports.Database exports.Query lib/node­db binding.cc, query.cc, events.cc connection.cc, result.cc, exception.cc src/ mysql.cc, query.cc  connection.cc, result.cc  
  11. 11. En el fondo...  Javascript  C++ V8: un amigo   
  12. 12. ¿¿¿¿¿¿C++??????   
  13. 13. C++ en Node.js Performance Ojo, ¡no siempre! Librerias C/C++ Código proprietario Integración con otros lenguajes Python en Node.js via boost:python?   
  14. 14. C++ en Node.js Ya que estamos, le damos una mano   
  15. 15. C++ en Node.js V8 libuv libeio Y lo que gustes... ¡es C++ después  de todo! waf / gyp   
  16. 16. ¿¿¿¿¿¿WINDOWS??????  Birra para el que adivina de qué película es esta foto  
  17. 17. Muerte a los hola mundosvar binding = require(./build/Release/binding);cerveza = new binding.Cerveza();console.log(cerveza.estado());cerveza.tomar(1);console.log(cerveza.estado());cerveza.tomar(2);console.log(cerveza.estado());cerveza.tomar(5);console.log(cerveza.estado());$ node test.js Arranca a tomar de una vez!Segui tomando tranquiloMas vale que no manejesMe parece que te falto el agua para las macetas   
  18. 18. Qué ganas de una cerveza...#ifndef CERVEZA_H_#define CERVEZA_H_#include <node.h>#include <node_object_wrap.h>class Cerveza : public node::ObjectWrap { public: static void Init(v8::Handle<v8::Object> target); protected: long liters; Cerveza(); static v8::Handle<v8::Value> New(const v8::Arguments& args); static v8::Handle<v8::Value> Tomar(const v8::Arguments& args); static v8::Handle<v8::Value> Estado(const v8::Arguments& args);};#endif   
  19. 19. Qué ganas de una cerveza...void Cerveza::Init(v8::Handle<v8::Object> target) { v8::HandleScope scope; v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(New); v8::Persistent<v8::FunctionTemplate> constructorTemplate; constructorTemplate = v8::Persistent<v8::FunctionTemplate>::New(t); constructorTemplate­>InstanceTemplate()­>SetInternalFieldCount(1); NODE_ADD_PROTOTYPE_METHOD(constructorTemplate, "tomar", Tomar); NODE_ADD_PROTOTYPE_METHOD(constructorTemplate, "estado", Estado); target­>Set(v8::String::NewSymbol("Cerveza"), constructorTemplate­>GetFunction());}v8::Handle<v8::Value> Cerveza::New(const v8::Arguments& args) { v8::HandleScope scope; Cerveza* cerveza = new Cerveza(); if (cerveza == NULL) { THROW_EXCEPTION("Ops! Tamos en el horno!") } cerveza­>Wrap(args.This());  return scope.Close(args.This());  }
  20. 20. Qué ganas de una cerveza...   
  21. 21. Los métodos expuestosv8::Handle<v8::Value> Cerveza::Tomar(const v8::Arguments& args) { v8::HandleScope scope; if (args.Length() != 1) { THROW_EXCEPTION("Si no me decis cuantos litros que queres que haga?"); } else if (!args[0]­>IsInt32()) { THROW_EXCEPTION("Que te tomaste?"); } else if (args[0]­>ToInt32()­>Value() < 0) { THROW_EXCEPTION("Limpia ese enchastre!") }    Cerveza* cerveza = node::ObjectWrap::Unwrap<Cerveza>(args.This());    assert(cerveza);    cerveza­>liters += (args[0]­>ToInt32()­>Value());    return scope.Close(v8::Undefined());}   
  22. 22. Los métodos expuestosv8::Handle<v8::Value> Cerveza::Estado(const v8::Arguments& args) { v8::HandleScope scope; Cerveza* cerveza = node::ObjectWrap::Unwrap<Cerveza>(args.This()); assert(cerveza); const char* estado; if (cerveza­>liters > 4) { estado = "Me parece que te falto el agua para las macetas"; } else if (cerveza­>liters > 2) { estado = "Mas vale que no manejes"; } else if (cerveza­>liters > 0) { estado = "Segui tomando tranquilo"; } else { estado = "Arranca a tomar de una vez!"; }    return scope.Close(v8::String::New(estado));}   
  23. 23. Y le decimos a Nodeextern “C” void init(v8::Handle<v8::Object> target) { Cerveza::Init(target);}NODE_MODULE(binding, init);{  "targets": [    {      "target_name": "binding",      "sources": [ "cerveza.cc" ]    }  ]}$ node­gyp configure buildinfo it worked if it ends with okmake: Leaving directory `/home/mariano/Documents/Talks/JSConf/src/buildinfo done ok     
  24. 24. libuv“El mundo no es perfecto.  A veces no podemos  hacer non­blocking.......  sin threads”   
  25. 25. libuvcerveza.comprar(function() { cerveza.comprar(function(compradas) { console.log(Ya compre  + compradas +  cervezas); });});$ node test.js Ya compre 2 cervezas   
  26. 26. libuvuv_work_t* request = new uv_work_t();request­>data = // ….uv_queue_work(uv_default_loop(), request, uvComprar, uvComprado);uv_ref(uv_default_loop()); void uvComprar(uv_work_t* uvRequest) void uvComprado(uv_work_t* uvRequest) uv_unref(uv_default_loop());   
  27. 27. A comprar cervezaclass Cerveza : public node::ObjectWrap { protected: long compradas; pthread_mutex_t compradasLock; struct compra_t { Cerveza* cerveza;          v8::Persistent<v8::Function>* callback; v8::Persistent<v8::Object> context; }; static v8::Handle<v8::Value> Comprar(const v8::Arguments& args);         static void uvComprar(uv_work_t* uvRequest);         static void uvComprado(uv_work_t* uvRequest);};Cerveza::Cerveza():litros(0), compradas(0) { pthread_mutex_init(&(this­>compradasLock), NULL);}Cerveza::~Cerveza() {  pthread_mutex_destroy(&(this­>compradasLock));  }
  28. 28. v8::Handle<v8::Value> Cerveza::Comprar(const v8::Arguments& args) { v8::HandleScope scope; Cerveza* cerveza = node::ObjectWrap::Unwrap<Cerveza>(args.This()); assert(cerveza); compra_t* compra = new compra_t(); if (compra == NULL) { THROW_EXCEPTION("Sin espacio!") } cerveza­>Ref(); compra­>context = v8::Persistent<v8::Object>::New(args.This()); compra­>cerveza = cerveza; compra­>callback = NULL; if (args.Length() > 0) { compra­>callback = node::cb_persist(args[0]); } uv_work_t* req = new uv_work_t(); req­>data = compra; uv_queue_work(uv_default_loop(), req, uvComprar, uvComprado); uv_ref(uv_default_loop()); return scope.Close(v8::Undefined());   }
  29. 29. void Cerveza::uvComprar(uv_work_t* uvRequest) { compra_t* compra = static_cast<compra_t*>(uvRequest­>data); assert(compra); pthread_mutex_lock(&(compra­>cerveza­>compradasLock)); compra­>cerveza­>compradas++; pthread_mutex_unlock(&(compra­>cerveza­>compradasLock));}   
  30. 30. void Cerveza::uvComprado(uv_work_t* uvRequest) { v8::HandleScope scope; compra_t* compra = static_cast<compra_t*>(uvRequest­>data); assert(compra); uv_unref(uv_default_loop()); compra­>cerveza­>Unref(); if (compra­>callback != NULL) { v8::Local<v8::Value> argv[1] = { v8::Number::New(compra­>cerveza­>compradas) }; v8::TryCatch tryCatch; (*(compra­>callback))­>Call(compra­>context, 1, argv); if (tryCatch.HasCaught()) { node::FatalException(tryCatch); } } compra­>context.Dispose(); if (compra­>callback != NULL) { compra­>callback­>Dispose(); }  delete compra;  }
  31. 31. libeio “libeio es como si me  teletransportara del laburo  al bar. Cada 5 segundos”   
  32. 32. libeiocerveza.consultar(function(r) { console.log(r);});$ node test.js John Doe   
  33. 33. libeioev_io* ioRequest = new ev_io();ev_init(ioRequest, eioConsultado);ev_io_set(ioRequest, fd, EV_READ);ev_io_start(EV_DEFAULT_UC_ ioRequest); void eioConsultado(EV_P_ ev_io* ioRequest, int revents) ev_io_stop(EV_A_ ioRequest);   
  34. 34. v8::Handle<v8::Value> Cerveza::Comprar(const v8::Arguments& args) { consulta­>connection = mysql_init(NULL); mysql_real_connect(consulta­>connection, "localhost", "root", "password",  "node", 3306, NULL, 0); mysql_send_query(consulta­>connection, "SELECT * FROM users", 20); consulta­>context = v8::Persistent<v8::Object>::New(args.This()); consulta­>cerveza = cerveza; consulta­>callback = NULL; if (args.Length() > 0) { consulta­>callback = node::cb_persist(args[0]); } consulta­>cerveza­>Ref(); ev_io* ioRequest = new ev_io(); ioRequest­>data = consulta; ev_init(ioRequest, eioConsultado); ev_io_set(ioRequest, consulta­>connection­>net.fd, EV_READ); ev_io_start(EV_DEFAULT_UC_ ioRequest);}   
  35. 35. void Cerveza::eioConsultado(EV_P_ ev_io* ioRequest, int revents) { v8::HandleScope scope; consulta_t* consulta = static_cast<consulta_t*>(ioRequest­>data); assert(consulta); ev_io_stop(EV_A_ ioRequest); consulta­>cerveza­>Unref(); mysql_read_query_result(consulta­>connection); MYSQL_RES* result = mysql_store_result(consulta­>connection); assert(result); char** row = mysql_fetch_row(result); // … mysql_free_result(result); mysql_close(consulta­>connection);}   
  36. 36. Conclusión C++ sigue sirviendo para algo libuv y libeio te simplifican la vida ¡No solo para Node.js eh! Ojeá el fuente de Node. Hay cosas interesantes  ahí ;) No minimices el poder de V8. Por algo se llama  V8   
  37. 37. ¿Preguntas? :­)  www.workana.com   @mgiglesias

×