lunes, 28 de diciembre de 2009

Implementación de malloc en glibc

malloc es una función de C que sirve para reservar n bytes consecutivos en memoria y devuelve un puntero a ese array.

¿Qué pasa cuando se agota la memoria? En teoría la función malloc debería devolver un puntero nulo y establecer la variable errno a ENOMEM.

¿Qué ocurre en realidad? En la librería de C de Linux (glibc) se usa un algoritmo de reserva de memoria optimista, no contempla el caso de haber agotado la memoria y siempre se devuelve un puntero válido. Según la manpage "uno o varios procesos pueden morir en estas situaciones llegándoles el mensaje 'out of memory'".

Hay una forma de solucionar esto, cambiar el comportamiento del algoritmo estableciendo a 2 la variable overcommit_memory con el comando:

echo 2 > /proc/sys/vm/overcommit_memory

Fuentes:
manpagez.com
linux.die.net

domingo, 1 de noviembre de 2009

Ejecución asíncrona de javascript con web workers

Tal y como anunciaba Google en la Google IO de este año han estado trabajando junto a la fundación Mozilla en la definición e implementación de los llamados web workers.

Los web workers permiten carga y ejecución asíncrona de javascript, tienen algunas limitaciones ya que no se puede acceder al DOM entre otras funciones, usa threads a nivel de sistema operativo y usa como método de sincronización paso de mensajes.

Un ejemplo de sincronización sencillo.

long_work.js

var j=1;
for(var i=0; i<999999999; i++){j=j*7+2;j=1}
this.postMessage('Done');

index.html

<script type="text/javascript">
var worker = new Worker("/javascripts/long_work.js");
worker.onmessage = function(event){
alert(event.data);
};
</script>

Ejemplo de uso en la web de la fundación Mozilla.

sábado, 15 de agosto de 2009

Como hacer copias de seguridad de tu agenda en symbian

Ya que tenemos acceso al API de symbian desde python (gracias al proyecto pys60) podemos aprovecharnos para hacer algunas cosas útiles con unos scripts simples en python.

Por ejemplo, para hacer una copia de seguridad de la agenda serviría el siguiente script.

from contacts import ContactsDb

contacts = ContactsDb().values()

filename = 'e:\\agenda.txt'
f = open(filename, "w")

for c in contacts:
f.write(c.as_vcard())

f.close()


Este programa exporta a un fichero toda la agenda en formato VCard para posteriormente transferirlo a otro dispositivo.

sábado, 18 de julio de 2009

Conectar una aplicación rails a varias bases de datos simultáneamente

Se puede conectar una aplicación rails a varias bases de datos a la vez, eso sí, hay que tener un especial cuidado con el rendimiento de la aplicación, aunque ActiveRecord nos provee una interfaz transparente a la hora de acceder a los modelos.

Suponiendo como ejemplo que tenemos dos modelos (Post y Comment) y este último está localizado en una base de datos externa, se puede configurar rails de la siguiente forma:

1) Primero, creamos un fichero de configuración para la conexión a la nueva base de datos (config/external_database.yml).

development:
adapter: mysql
database: test
username: root
password:

production:
adapter: mysql
database: test
username: root
password:

2) Después, creamos un módulo para encapsular la lectura del fichero y la nueva conexión.

module ExternalDatabase
def self.included(base)
config = YAML.load(File.open('config/external_database.yml'))

if config and ENV['RAILS_ENV']
base.establish_connection(config[ENV['RAILS_ENV']])
else
raise 'External Database not configured'
end
end
end

3) Por último, incluimos en los modelos que van a la base de datos externa el módulo que hemos creado.

class Comment < ActiveRecord::Base
include ExternalDatabase

belongs_to :post
end

Con esto ya podemos utilizar los modelos aunque cada uno esté en una base de datos diferente.

Comment.find(:all, :include => :post)

sábado, 11 de julio de 2009

Diferencias de rendimiento entre eval y send

La metaprogramación en ruby permite mucha expresividad y flexibilidad, aún así hace caer bastante el rendimiento.

A pesar de eso, lo más importante es evitar en la medida de lo posible eval ya que es bastante más lento.

Al hacer una llamada a send la máquina virtual de ruby tiene que buscar el nombre del método que se le pasa como parámetro y ejecutarlo.

En cambio, al hacer un eval además de lo anterior la máquina virtual necesita parsear la cadena y después ejecutar el código.


Benchmark.bm{|x| x.report{100000.times{eval('Post.scopes')}}}
user system total real
0.410000 0.000000 0.410000 ( 0.410306)

Benchmark.bm{|x| x.report{100000.times{Post.send('scopes')}}}
user system total real
0.140000 0.000000 0.140000 ( 0.144820)

viernes, 26 de junio de 2009

Optimización de consultas en rails

Cuando en rails se hace una consulta a la base de datos sobre una tabla que contiene mucha información, no todo el tiempo se pierde en la consulta. Una parte importante del tiempo se pierde en la creación de cada objeto ActiveRecord.

Usando directamente el método select_all de la conexión ActiveRecord devolverá un array de hash, ahorrando el tiempo de construcción de objetos.

Benchmark.bm{|x| x.report{100.times{BigTable.find(:all)}}}
user system total real
10.090000 2.090000 12.180000 ( 19.199150)

Benchmark.bmbm{|x| x.report{100.times{BigTable.connection.select_all('select * from big_table')}}}
user system total real
7.350000 2.080000 9.430000 ( 16.646406)

En general, no es buena idea guardar todos los elementos de una tabla grande en un array, pero aún seleccionando tan solo el índice se obtiene una mejora sustancial.

Benchmark.bm{|x| x.report{100.times{BigTable.find(:all, :select => :id)}}}
user system total real
0.610000 0.010000 0.620000 ( 0.707702)

Benchmark.bmbm{|x| x.report{100.times{BigTable.connection.select_all('select id from big_table')}}}
user system total real
0.080000 0.000000 0.080000 ( 0.161878)

sábado, 20 de junio de 2009

Crear extensiones de ruby en c

Crear extensiones en C del lenguaje ruby es bastante sencillo.

En primer lugar hay que crear un fichero para extconf, este nos generará el fichero makefile de forma automática.

En el fichero extconf.rb debería haber algo como:

#!/usr/bin/env ruby

require 'mkmf'
create_makefile("ruby1")

Donde ruby1 es el nombre de la extensión.

En segundo lugar hay que crear la extensión en código C, simplemente hay que incluir la cabecera ruby.h.

La función Init_ruby1 es la que se ejecutará al importar la extensión desde código ruby.

#include "ruby.h"

static VALUE c_printf(VALUE self, VALUE anObject){
printf("%s\n", STR2CSTR(anObject));
return Qnil;
}

static VALUE c_init(VALUE self){
return self;
}


VALUE FromC;

void Init_ruby1() {
rb_define_global_function("printfc", c_printf, 1);
FromC = rb_define_class("FromC", rb_cObject);
rb_define_method(FromC, "initialize", c_init, 0);
rb_define_method(FromC, "printfc", c_printf, 1);
}

En este ejemplo se define una función global printfc, se define la clase FromC, el método de instancia printfc de esa clase.

Para compilar e instalar este código hay que ejecutar ruby extconf.rb, make y make install.

Ya deberíamos tener disponible la librería ruby1, al ejecutar require 'ruby1' podremos ejecutar las funciones de nuestro código en C.

Hay una gran cantidad de funciones disponibles para crear extensiones en la siguiente dirección: http://www.rubycentral.com/book/ext_ruby.html

miércoles, 3 de junio de 2009

Definición de named_scopes dependientes del tiempo actual

Si tenemos una clase ActiveRecord como la siguiente:

class Post < ActiveRecord::Base
named_scope :test, :conditions => ['updated_at < ?', Time.now]
end

En modo development funciona sin problemas, sin embargo en modo production la consulta que se genera no es la esperada.

Al arrancar rails en modo production se cachean las clases, al cargar este modelo en concreto se evalúa Time.now haciendo que para todas las consultas se coja como fecha la hora en la que se ha cargado el modelo.

El descrito anteriormente no es el comportamiento que esperaríamos al definir el named_scope, sino que debería obtener la fecha y hora actual para cada consulta, no en la definición.

Revisando la definición de los named_scopes nos encontramos lo siguiente:

def named_scope(name, options = {}, &block)
name = name.to_sym
scopes[name] = lambda do |parent_scope, *args|
Scope.new(parent_scope, case options
when Hash
options
when Proc
options.call(*args)
end, &block)
end
(class << self; self end).instance_eval do
define_method name do |*args|
scopes[name].call(self, *args)
end
end
end


En nuestro caso pasamos un hash como opciones, por lo que efectivamente se evaluará el Time.now solo en la definición de dicho hash.

Si en lugar de eso definimos un objeto de tipo Proc se evaluará cada vez.

Por lo tanto para arreglar el comportamiento del primer ejemplo deberíamos escribirlo como:

class Post < ActiveRecord::Base
named_scope :test, lambda{{:conditions => ['updated_at < ?', Time.now]}}
end

domingo, 10 de mayo de 2009

Aplicación de consola para twitter

Acabo de lanzar un proyecto en github para interaccionar con twitter desde consola.

Por ahora incluye la funcionalidad básica: cambio de estado, consulta de estado de amigos, login y mensajería.

La interfaz de comandos es muy similar al clásico IRC.

La url del proyecto es la siguiente: twit

viernes, 1 de mayo de 2009

Añadiendo estado a los elementos del DOM

En aplicaciones complejas con javascript para guardar el estado de cada elemento se suele modificar alguna propiedad del elemento que queramos manipular.

Sin embargo esta práctica es poco adecuada y no demasiado flexible, ya que no podemos guardar tipos de datos complejos.

jQuery ya prevee que podemos necesitar esta funcionalidad y nos proporciona la función data para guardar información de cada elemento.

Por ejemplo:

$('a').data('activated_links', false);
....
var footer_links = $('.footer_links');
if(!footer_links.data('activated_links')){
footer_links.data('activated_links', true);
...
}
...

sábado, 28 de marzo de 2009

Combinación de named_scopes en rails

Cuando hay que realizar un filtrado de resultados en una web con muchas posibles combinaciones podemos acabar con muchas líneas de código para obtener una funcionalidad no demasiado compleja.

En rails, la mayoría de los filtrados se hacen con named_scopes, queda parcialmente resuelto el problema, aún así quedan resolver como aplicar cada combinación de named_scopes según el filtrado que necesite el usuario.

Suponiendo que tenemos un modelo Post como el siguiente:

class Post < ActiveRecord::Base
named_scope :all
named_scope :published, :conditions => {:published => true}
named_scope :from_user, :conditions => {:kind => 'user'}
named_scope :from_admin, :conditions => {:kind => 'admin'}
end


Podemos resolver el problema de aplicar filtros combinados de la siguiente forma usando inject:

class PostsController < ApplicationController
def index
filter = (params[:filter] or String.new)
filter = filter.split(',').map(&:to_sym).select{|f| Post.scopes.include?(f)}
filter << :all

@posts = filter.inject(Post){|model, nscope| model.send(nscope)}
end
end

En primer lugar obtenemos la lista de named_scopes a aplicar y filtramos los no válidos, en segundo con inject se los aplicamos al modelo.

Con ese código tan simple podemos usar rutas del tipo:

http://server/posts
http://server/posts?filter=published
http://server/posts?filter=published,from_user

domingo, 1 de marzo de 2009

Optimización del tiempo de carga de webs

Dentro del tiempo total desde que se hace una petición a una página web hasta que se termina de dibujar en el navegador, gran parte corresponde a los distintos recursos externos que hay que recuperar: javascript, css e imágenes.

Los ficheros javascript y css tienen una propiedad interesante, si se concatenan varios y se envían en un solo fichero no debe influir en el resultado final.
Sin embargo, si se concatenan, se pueden cargar con una sola petición, con el consiguiente aumento de rendimiento.

El método que rails proporciona para hacer esto de forma automática es el siguiente (solo en modo producción):

<%= javascript_include_tag 'first.js', 'second.js', :cache => '1_2' %>

Sin embargo esto tiene un problema, normalmente en una aplicación según la página se carga unos ficheros u otros, no es muy práctico ir dándole claves a todas las combinaciones.

Se pueden programar dos helpers para dar las claves de forma automática:

<%= cached_javascript_include_tag 'first.js', 'second.js' %>
<%= cached_stylesheet_link_tag 'first.css', 'second.css' %>

Es importante que las versiones cacheadas tanto de css como de javascript no estén en el svn, a la hora de hacer un despliegue se regenerarán usando la nueva versión de los ficheros.

Aún así, si se quiere que se genere de nuevo la versión cacheada para una página sin desplegar la aplicación ni borrar los ficheros antiguos, se puede usar un sistema de versiones.

<%= cached_javascript_include_tag 'first.js?v=1', 'second.js?v=3' %>

El código de los helpers es el siguiente:

module ApplicationHelper
def cached_javascript_include_tag(*args)
cached_args!(*args)
javascript_include_tag(*args)
end

def cached_stylesheet_link_tag(*args)
cached_args!(*args)
stylesheet_link_tag(*args)
end

def cached_args!(*args)
options = args.extract_options!.stringify_keys

cache_entry = args.map(&:to_s).sort.join('_').gsub!('?', '_')
options[:cache] = cache_entry

args << options
end
end

domingo, 11 de enero de 2009

Observadores personalizables en rails

En rails hay unas clases llamadas observadores que sirven para redefinir los métodos que necesitemos en el ciclo de vida de los objetos (after_update, before_create, etc...).

El problema es que en ocasiones con los métodos del ciclo de vida no es suficiente, una situación muy común es redefinir el método after_save, y cada vez que se guarde un objeto comprobar una condición y actuar si es necesario.

Afortunadamente existe un método en ActiveRecord para notificar a los observadores exactamente cuando queramos y de lo que queramos, de la siguiente forma.

En el modelo:

class Post < ActiveRecord::Base
def just_created
notify :manage_task
end
end

En el observador:

class GlobalObserver < ActiveRecord::Observer
observe Post

def manage_task(object)
#do something
end
end

viernes, 2 de enero de 2009

Carga de css dinámica

Es habitual en webs en las que cada usuario tiene una página personal permitirle cambiar la apariencia mediante temas (skins).

Para cargar un css nuevo de forma dinámica se puede usar la siguiente función javascript o algún variante.

function loadCSS(cssFile){
var cssLink=document.createElement("link");
cssLink.setAttribute("rel", "stylesheet");
cssLink.setAttribute("type", "text/css");
cssLink.setAttribute("href", cssFile);
document.getElementsByTagName("head")[0].appendChild(cssLink);
}

Lo que hace esta función es crear un elemento link que apunta a un css y lo inserta en el head de la página.