sábado, 19 de septiembre de 2009

Star Wars (John Williams Is The Man) A Cappella Tribute

Os dejo este magnífico vídeo homenaje a John Williams hecho por Corey Vidal, un canadiense que ha triunfado en YouTube con sus grabaciones. Es de hecho uno de los usuarios más vistos y con más suscripciones.

Por otro lado, para el que no conozca a John Williams, decir que se trata de un compositor y director de orquesta de los más famosos. Estoy 100% seguro de que has escuchado alguna de sus más famosas obras, como son las bandas sonoras de Tiburón, La Guerra de las Galaxias, E. T.: El extraterrestre, Superman, la saga de películas de Indiana Jones, Parque Jurásico, La lista de Schindler, Memorias de una geisha o Harry Potter entre otras.

Además de este magnífico vídeo de Corey Vidal por cuatriplicado, os dejo la letra para que podáis seguirlo mejor.


[Close Encounters of the Droid Kind]
You must use the force (repeat ad nauseum)

[Raiders of the Lost Wookiee]
Long time ago, far far away (repeat)

Kiss a wookie, kick a droid
Fly the falcon through an asteroid
Till the princess is annoyed
This is spaceships, it's monsters, it's Star Wars, we love it!

Come and help me, Obi-Wan
X-wing fighter and a blaster gun
Dance with Ewoks, oh what fun!
This is spaceships, it's monsters, it's Star Wars, we love it!

[Super Han]
Get in there you big, furry oaf
I couldn't care less what you smell
I take orders from only me
Maybe you'd like it back in your cell
Your Highness, your worshipfulness, your highness, your worshipfulness

No one cares if you upset a droid
(nobody cares if you upset a droid)
That's because droids don't tear your arms out of socket.
(nobody cares)
I suggest a new strategy: let the Wookie win
That's because nobody cares if you upset a droid.

[ET the DiscoTerrestrial]
Now we listen to Luke whining:
One more season... One more season... One more season... One more season...

I was gonna go to Tosche Station for power converters
Now I guess I'm going nowhere.
It just isn't fair.

[Jaws: the Wookiee]
Woooooookiee (repeat)

Someone move this walking carpet (repeat)

Kiss your brother, Kiss your brother (repeat)

Princess Leia
Well I guess you don't know anything about women.

Who's your daddy? (repeat)

[Jurassic Darth]
Luke, I'm your father
(That's not true!)
It is useless to resist
(My hand!)
Come with me my son, We will rule
(I'll never join you!)
Search your feelings it is true

So you have a twin sister
Who Obi-Wan was wise to hide
(Is that Leia?)
If you will not turn
Then perhaps she will
Give in to your hate
You are mine

Long Long Long Time ago... Far Far Far Far Away

Long Long Long Time Ago, Far Far Far Away (repeat)

Kiss a wookie
Kick a droid
Fly the falcon
Through an asteroid
Till the princess is annoyed
(She's annoyed!)
This is spaceships, it's monsters, it's Star Wars, we love it, it's true

Episode 3
Coming to you
In 2005

So Let's go
(go go go to the movies)
Stand in line
(buy buy buy me some popcorn)
Cause it's al-
(please I'd like extra butter)
most the time
(Join the dark side...)
May the Force be with you all

John Williams is the man

lunes, 14 de septiembre de 2009

Pink Panther Theme

Continuamos con un poco de guitarra. Esta vez os dejo todo un clasico, La Pantera Rosa. Os dejo también una versión más rockera del mismo que me ha llamado mucho la atención. ¡¡¡Que los disfrutéis!!!



miércoles, 9 de septiembre de 2009

Optimización de un servidor MySQL

Las bases de datos MySQL son bastante utilizadas debido a que ofrecen una calidad bastante aceptable a coste 0. Por supuesto, no basta con instalar y listo. Hay que configurar y ajustar los parámetros adecuados al uso que se le vaya a dar. En cualquier caso, en entornos de producción los parámetros que trae por defecto no son suficientes.

En este post, explico una serie de pautas a tener en cuenta en la configuración que pueden servir de punto de partida para el ajuste fino de un servidor MySQL y el motor InnoDB, que es el que he utilizado mayormente ya que permite relación entre tablas.

-innodb_buffer_pool_size: se debe configurar al 70-80% de la memoria del servidor. Por ejemplo, si tienes un servidor de 4GB de RAM, 3G sería un valor adecuado.

-innodb_log_file_size: 256M parece un valor adecuado.

-innodb_log_buffer_size: 4M es un valor adecuado en la mayoría de los casos, a menos que uses grandes blobs. En ese caso, auméntalo un poco.

-innodb_flush_log_at_trx_commit=2 si no te interesan el ACID y puedes asumir que se pierdan transacciones en los dos últimos segundos en caso de fallo en el sistema operativo. Si usas replicación este valor debe estar a 1, tal y como comenté en el post sobre Replicación de bases de datos MySQL.

-innodb_thread_concurrency=8 Incluso con las correcciones sobre escalabilidad del motor InnoDB, tener limitada la concurrencia siempre ayuda. Puede ser mayor o menor dependiendo de tu aplicación, pero 8 es un buen comienzo.

-innodb_flush_method=O_DIRECT. Evita el doble buffer y reduce el uso de swap. En la mayoría de los casos mejora el rendimiento.

-innodb_file_per_table: divide el fichero de información InnoDB en varios, concretamente uno por tabla. Evita que toda la información vaya a un único fichero, aumentando el rendimiento.

Estos puntos anteriores los he sacado del MySQL Performance Blog. Te recomiendo que le eches un vistazo, ya que es posible que aspectos que he omitido porque no se adaptan a mi caso, sí que te interesen a ti. 

Ejemplo de configuración  

A continuación dejo un ejemplo de configuración en un servidor de 4 núcleos con 4MB de RAM y contiene el servidor dedicado únicamente a la base de datos MySQL.

El siguiente fichero ha de colocarse en /etc/mysql/conf.d .Yo lo he llamado innodb.cnf, por ejemplo.
#
# Configuración para optimización de la base de datos
#
[mysqld]
# ficheros de log
log_slow_queries=/var/log/mysql/mysql-slow.log
long_query_time=5 

innodb_buffer_pool_size=3G
innodb_log_file_size=512M
innodb_log_buffer_size=16M
innodb_file_per_table

key_buffer_size=64M
table_cache=1024
thread_cache=16
query_cache_size=256M
max_connections=300
max_user_connections=300
thread_concurrency=8
Puedes observar que se ha aumentado el parámetro innodb_log_buffer_size debido a que usamos gran cantidad de blobs.

Espero que os sirva como punto de partida. Por supuesto, el ajuste fino dependerá mucho del uso y de las aplicaciones.

lunes, 7 de septiembre de 2009

Dueling Banjos

Para continuar con la sección de guitarra, os dejo otro vídeo de mis favoritos. Se trata de una escena musical de la película Deliverance (1972) en la que hay un duelo de banjos entre el personaje de Ronny Cox, tocando la guitarra, y un extraño chico mentalmente discapacitado, pero muy habilidoso con el banjo.

sábado, 5 de septiembre de 2009

31 noches, de Nacho Escolar

El pasado 31 de agosto terminó 31 noches, la novela corta por entregas que Nacho Escolar ha estado escribiendo durante el mes de agosto para Público.

A mi me enganchó a mediados de agosto y no he podido parar de leerla hasta su fin. Se trata de una novela policíaca donde un periodista se ve envuelto entre la corrupción, las drogas y las mafias y nos cuenta como se desarrolla la historia que le conduce a su propia muerte (que conste que no he desvelado nada, esto aparece en el primer capítulo). Muy grata sorpresa la que me llevé con esta novela que encontré por casualidad en mis vacaciones. La recomiendo 100%. ;-)

miércoles, 2 de septiembre de 2009

Plugins de Firefox para el Desarrollo Web

Todo desarrollador web que se precie debe haberse hecho la siguiente pregunta en algún momento de su vida: ¿Por qué cada navegador web interpreta el html/css/javascript como le da la gana?¿No podrían hacerlo todos de la misma forma? y seguro que habéis maldecido más de una vez a los creadores de Internet Explorer. ¿No sería más feliz el mundo si no existiera el Explorer? Si nunca te has planteado estas preguntas, es que aún no has trabajado lo suficiente con html/css/javascript :-p

En este post no os voy a dar una solución definitiva a esta problemática, pero al menos sí os comento algunos plugins de Firefox que os pueden resultar útil para el desarrollo web. (Menos es nada ;-) )
  • Firebug: imprescindible para maquetación html y css. Te permite modificar el html y el css interpretado por el navegador. Ideal para hacer ajustes de css. Además, incorpora un depurador para javascript. Yo me pregunto, ¿qué hacíamos cuando no había Firebug?
  • Web developer tool bar: muy útil. Tiene un gran conjunto de funcionalidades, muchos de ellos son atajos a opciones del navegador como desactivar javascript, limpiar caché, ver código fuente. Entre sus funcionalidades destacadas está la posibilidad de ver todas las css, una regla para medir distancias en píxeles, información y edición de formularios html. La verdad es que desde que está Firebug la utilizo poco porque muchas de las cosas que antes hacía con este plugin las hago ahora con Firebug, pero creo que es útil tenerlo a mano para cuando se pueda necesitar.
  • LORI(Lifer-of-request-info): útil para mostrar información de la petición HTTP. Te muestra tiempos de carga de la página, tanto desde que se hizo la petición hasta recibir el primer byte como desde que se hizo la petición hasta la carga completa de la página; tamaño de la página, número de peticiones, ...
  • Live HTTP headers: útil para explorar las cabeceras HTTP, tanto en la petición como en la respuesta.
  • User Agent-switcher: te permite modificar el User-Agent del navegador. Útil si estáis realizando versiones para dispositivos móviles o PDAs.
Estos son los plugins que, por mi trabajo he utilizado, y encuentro más útiles. Supongo que dependiendo de lo que se trate habrá más plugins útiles. Si conocéis alguno más que pueda ser útil para el desarrollo web no dudéis en comentarlo.

lunes, 31 de agosto de 2009

Inauguración de sección sobre Guitarra (Bohemian Rhapsody)

Hace tiempo que soy aficionado al mundo de las guitarras y puesto que lo considero importante en mi vida, no me gustaría dejarlo de lado en este blog. Me gustaría inaugurar la nueva sección sobre guitarra con este vídeo: Bohemian Rhapsody - for solo guitar. Es muy bueno. Espero que lo disfrutéis tanto como yo.

viernes, 28 de agosto de 2009

Configuración de réplicas de MySQL

Es bastante frecuente encontrarse con la necesidad tener, no un único servidor de base datos, sino un conjunto de ellos sincronizados. A menudo esto se hace por razones de rendimiento y escalabilidad.

MySQL nos ofrece dos posibilidades para solucionar este problema: la replicación y el cluster.

En la replicación de nodos MySQL existe un servidor maestro y N servidoes esclavos. Los esclavos se sincronizan a partir del maestro. Esta sincronización es en un único sentido: del maestro al esclavo. Es por ello por lo que los esclavos únicamente deben usarse para leer, lo que implica que todas las consultas de escritura, habrá que hacerlas sobre el maestro.

A grandes rasgos se puede decir que en el cluster MySQL existen N servidores MySQL donde todos se tratan de igual a igual. En todos los servidores se puede leer y escribir, ya que el sistema de cluster se encarga de sincronizar todos los nodos. Realmente es más complejo que lo que dicen estas 3 líneas, por lo que si tienes curiosidad puedes leer la documentación oficial acerca del Cluster MySQL.

Mientras que en primer caso no existiría la alta disponibilidad, al menos en lo que a escritura se refiere, ya que la caída del maestro implica que no se pueden ejecutar las consultas de escritura; en el segundo caso la alta disponibilidad sí que existe, ya que ante la caída de un nodo, el resto podría seguir funcionando perfectamente.

Este post se centra en la configuación de réplicas MySQL. Me gustaría probar el cluster porque tiene buena pinta. Si lo hago pondré un post sobre cómo se configura.

Configuración

A continuación se describen los pasos que hay que seguir para configurar una réplica de un servidor MySQL.

1. Crear usuario de replicación en el servidor maestro para poder replicar

mysql> GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%.mydomain.com' IDENTIFIED BY 'slavepass';

2. Ajustar la configuración del maestro en el my.cnf

[mysqld]
log-bin=mysql-bin
server-id=1

Para mejorar el rendimiento en innodb, ajustar también en el maestro lo siguiente:

innodb_flush_log_at_trx_commit=1
sync_binlog=1

Reiniciar MySQL.

3. Ajustar la configuración del esclavo en el my.cnf

[mysqld]
server-id=2

Reiniciar MySQL

4. Obtener información de replicación del maestro. (Se utilizará en el paso siguiente)

mysql> show master status;

5. Configurar la conexión con el maestro en el esclavo. Los datos MASTER_LOG_FILE y MASTER_LOG_POS hay que cogerlos del resultado del paso anterior.

mysql> CHANGE MASTER TO MASTER_HOST='master_host_name',
MASTER_USER='replication_user_name',
MASTER_PASSWORD='replication_password',
MASTER_LOG_FILE='recorded_log_file_name',
MASTER_LOG_POS=recorded_log_position;

6. Iniciar la sincronización en el esclavo.

mysql> START SLAVE;
Y listo. En caso de que Hubiera más de un esclavo el proceso es análogo.

Espero que sea de utilidad.

sábado, 1 de agosto de 2009

Actualizar firmware Nokia N95 - Fallo de encendido del teléfono

Acabo de actualizar el firmware de mi N95 versión Vodafone. He seguido este tutorial. Por supuesto antes hice copia de seguridad y tras la actualización restauré la copia. Me llevé un susto cuando al encender el teléfono ponía Fallo del encendido del teléfono. Póngase en contacto con el vendedor.

Mi fallo estuvo en restaurar la copia de seguridad. Supongo que tendrá ficheros de la versión anterior que no son compatible con la versión del firmware instalada. La solución es simple: hay que hacer un hard reset. Simplemente apagamos el teléfono y pulsamos a la vez las teclas "3", "*", "llamada (teléfono verde)" y el botón de encendido.

Una vez hecho esto, se restaurará la memoria eliminando la copia de seguridad que hemos restaurado y todo volverá al estado justo después de la actualización del firmware. Tan sólo hay que restaurar contactos, mensajes y agenda.

¡¡¡A seguir disfrutando del teléfono!!!

sábado, 6 de junio de 2009

JavaCup 2009: Clasificación del Grupo 6 de la primera ronda

Este post, realmente va dirigido a un grupo muy reducido de personas. En concreto a 9: los 8 participantes de la JavaCup 2009 que han caído en el grupo 6 y yo, que soy el 9º miembro.

Creo que puede ser interesante ir viendo la evolución de la clasificación del grupo y así poder hacer nuestras cuentas conforme va avanzando la primera fase. Intentare actualizarlo diariamente con los nuevos partidos de cada jornada.


PosEquipoPtsPJPGPEPPGFGCDG
1.igual1A2488001110+111
2.igualAmericanSamoaNationalFootballTeam218701445+39
3.igualLaTascaDeXela168512325+27
4.igualDarkkorTeam1484222016+4
5.arribaelyorch983051130-19
6.abajoSuns98305937-28
7.abajoElEquipoDeJose2009782151322-9
8.igualcucuta68206445-41
9.igualITLA08008185-84


En caso de empate a puntos, se tienen en cuenta la diferencia de goles(DG) y en caso de nuevo empate el resultado del partido individual (incluyendo posesión).

Se clasifican los 4 primeros para la siguiente fase.

Jornada 1
elyorch vs. DarkkorTeam0 - 1Ver partido
LaTascaDeXela vs. cucuta5 - 0Ver partido
ElEquipoDeJose2009 vs. ITLA9 - 0Ver partido
suns vs. AmericanSamoaNationalFootballTeam0 - 6Ver partido
Jornada 2
AmericanSamoaNationalFootballTeam vs. 1A0 - 3Ver partido
LaTascaDeXela vs. elyorch4 - 0Ver partido
ElEquipoDeJose2009 vs. DarkkorTeam1 - 1Ver partido
suns vs. cucuta4 - 0Ver partido
Jornada 3
1A vs. ITLA27 - 0Ver partido
AmericanSamoaNationalFootballTeam vs. cucuta5 - 0Ver partido
suns vs. elyorch0 - 1Ver partido
ElEquipoDeJose2009 vs. LaTascaDeXela1 - 2Ver partido
Jornada 4
cucuta vs. 1A0 - 19Ver partido
ITLA vs. DarkkorTeam0 - 8Ver partido
AmericanSamoaNationalFootballTeam vs. elyorch6 - 0Ver partido
suns vs. ElEquipoDeJose20091 - 0Ver partido
Jornada 5
1A vs. DarkkorTeam14 - 0Ver partido
cucuta vs. elyorch0 - 4Ver partido
ITLA vs. LaTascaDeXela0 - 15Ver partido
AmericanSamoaNationalFootballTeam vs. ElEquipoDeJose20099 - 0Ver partido
Jornada 6
elyorch vs. 1A0 - 17Ver partido
DarkkorTeam vs. LaTascaDeXela0 - 0Ver partido
cucuta vs. ElEquipoDeJose20091 - 0Ver partido
ITLA vs. suns1 - 4Ver partido
Jornada 7
1A vs. LaTascaDeXela1 - 0Ver partido
elyorch vs. ElEquipoDeJose20091 - 2Ver partido
DarkkorTeam vs. suns2 - 0Ver partido
ITLA vs. AmericanSamoaNationalFootballTeam0 - 14Ver partido
Jornada 8
ElEquipoDeJose2009 vs. 1A0 - 7Ver partido
LaTascaDeXela vs. suns4 - 0Ver partido
DarkkorTeam vs. AmericanSamoaNationalFootballTeam0 - 1Ver partido
cucuta vs. ITLA3 - 0Ver partido
Jornada 9
1A vs. suns23 - 0Ver partido
LaTascaDeXela vs. AmericanSamoaNationalFootballTeam2 - 3Ver partido
elyorch vs. ITLA5 - 0Ver partido
DarkkorTeam vs. cucuta8 - 0Ver partido


Fuente: http://javacup.javahispano.org/app/listPartidos.html?fase=6#

martes, 2 de junio de 2009

La Tasca de Xela participa en la JavaCup 2009

En el post anterior ya comenté que tenía intenciones de participar en la JavaCup 2009. Pues bien, mi participación ya está confirmada.

El equipo que he hecho dista mucho de lo que tenía en mente en un principio, pero no por ello no dejo de estar orgulloso del trabajo realizado. Otra cosa distinta es que los otros equipos sean mejores o no, eso ya se verá en la competición. Al ser equipo novato,a priori me conformo con pasar de la liguilla inicial. A partir de ahí lo que venga será bienvenido.

Como se suele decir en el mundo del fútbol, este equipo pretenede asentar las bases del equipo que será en el futuro. Bla,bla,bla ... er furgol es así. :-p O en otras palabras, con la base de este equipo, para el año que viene espero poder desarrollar un equipo que se acerque más a lo que en un principio imaginé. Aún así, espero que en esta edición del torneo, este equipo le ponga la cosa complicada al resto.

Las claves de este equipo son:
  • Una buena defensa (partiendo desde el portero) pero sin olvidar el aspecto ofensivo. De hecho, el equipo es bastante ofensivo ya que juega con un 3-4-1-2.
  • Jugar el balón con sentido. Nada de rifar el balón (salvo cuando se está en peligro, que no hay que complicarse), sino a tocar el balón con pases estudiados (esto aún está por ver :-p) y mantener la posesión.
  • La conducción del balón sorteando a los rivales si no hay opción clara de pase, ya sea por las bandas o el centro.
  • Desmarque de los jugadores. Nada de quedarse estáticos con el contrario al lado y esperar a que nos la pasen, hay que buscar huecos.
  • Por último, una dosis de sorpresa con tiros desde fuera del área de vez en cuando. Por supuesto, a más tiros acertados, más tiros ejecutados y viceversa.
Es la primera vez que participo en un concurso de programación y, pase lo que pase en la competición, tengo que decir que ha sido una gran experiencia para mí. Por supuesto, no es un trabajo fácil pero sí muy motivador, sobre todo si además, en este caso, te gusta el fútbol.

Me gustaría animar a todos aquellos que se han quedado ahí en la duda de si participar o no para que participen en otros concursos o ediciones de éste. Merece la pena el esfuerzo invertido.

PD: Por supuesto, la equipación de la imagen es la que llevará LaTascaDeXela en el torneo. ;-)

martes, 14 de abril de 2009

JavaCup 2009


Desde javaHispano anuncian el comienzo de la JavaCup 2009. Se trata de una competición de futbol donde cada equipo es una clase Java. Para participar tienes que construirte tu propio equipo: jugadores, tácticas, jugadas,... Tu clase se ejecutará sobre un framework y se enfrentará a otros equipos.

El plazo para enviar tu equipo finaliza el 31 de Mayo. Os dejo un enlace a la página oficial y al tutorial sobre cómo crear tu propio equipo.

Friki, ¿verdad? ;-) No os quepa duda de que si tengo el tiempo suficiente, La Tasca de Xela tendrá su propio equipo. Intentaremos dejar el pabellón bien alto a pesar de ser equipo novato. ¡¡Anímate tú también!!

Os dejo el video de promoción de la JavaCup 2009:

viernes, 13 de febrero de 2009

Evitar superar el maxClauseCount en Lucene

Uno de los errores típicos en Lucene es el siguiente:

org.apache.lucene.search.BooleanQuery$TooManyClauses: maxClauseCount is set to 1024

Esto normalmente viene provocado por hacer una consulta con carácteres comodines (* y ?). Cuando hacemos una consulta de este tipo, WildcardQuery, lo que hace internamente Lucene es sustituir nuestra consulta con comodines por una consulta sin ellos. ¿Cómo? Pues mira los campos que cumplan el patrón de la consulta y hace un OR con cada uno de ellos.


Mejor veamos un ejemplo:

Supongamos que tenemos indexado documentos y queremos encontrar todos aquellos cuyo campo título empiece por "cas". Para ello haremos la siguiente consulta:

titulo: cas*

Al tratarse de una WildcardQuery, Lucene miraría en todos los campos "titulo" del índice y tomaría aquellos que empiezan por "cas", por ejemplo supongamos que existen 3: "casa", "casita" y "caserio". Lucene sustituiría la consulta por:

titulo: casa or titulo: casita or titulo: caserio


En este ejemplo, vemos que una simple consulta que para mí tiene únicamente una única clausula, realmente se convierte en una consulta con 3 clausulas. Si en lugar de existir sólo 3 campos "titulo" que empiecen por "cas" existieran más de 1024, nos daría el error que he comentado al principio.

Conclusión: no usar comodines. Por desgracia, esto no es siempre posible, pero si se piensa un poco a la hora de indexar, sí que podemos minimizar los casos de uso de las WildcardQuerys.

Indexar una estructura de carpetas o en árbol

Es muy corriente el uso de Lucene para indexar estructuras en árbol como un sistema de ficheros en un gestor de contenidos. Cuando se tiene una estructura en árbol se usa mucho la consulta por ruta o path. Supongamos que tenemos una carpeta A, que dentro tiene otra, B y ésta a su vez tiene otra, C. A su vez cada carpeta tiene ficheros dentro. La ruta hacia C sería /A/B/C y la de cualquier fichero en C /A/B/C/nombre_fichero.

Es lógico indexar en cada Document de Lucene un campo llamado path que contenga la ruta. De esta forma, podemos buscar un contenido por ruta:

path: /A/B/C/nombre_fichero

o buscar los hijos de C (todos los que su ruta empiece por la de C)

path: /A/B/C/*

Dependiendo de los hijos que tenga C, podremos superar el maxClauseCount. Y lo más seguro es que tarde o temprano lo hagamos.

Para evitar este problema, lo que podemos hacer es:
  1. Seguimos indexando el campo path para hacer consultas por ruta pero sin *.
  2. Indexamos la ruta de la carpeta padre, por ejemplo en el campo parent_path. Esto nos servirá para consultar los hijos de una carpeta.
  3. Indexamos como campo múltiple la ruta de todas las carpetas padres. Por ejemplo, llamemosle ancestor_path. Esto nos sirve para buscar los hijos, nietos, bisnietos,.... de una carpeta.

Dicho esto, para el fichero /A/B/C/nombre_fichero, indexaríamos lo siguiente:
  • path: /A/B/C/nombre_fichero
  • parent_path: /A/B/C
  • ancestor_path: /A
  • ancestor_path: /A/B
  • ancestor_path: /A/B/C
Tened en cuenta que ancestor_path es un campo múltiple.

Si queremos obtener un contenido a partir de su ruta, la consulta seguiría siendo la misma:

path: /A/B/C/nombre_fichero

pero si queremos obtener los hijos de C ya no tenemos que usar comodines:

parent_path: /A/B/C

y si quisieramos obtener todos los hijos de A, incluido nietos tampoco:

ancestor_path: /A

De esta forma, estamos evitando el error del maxClauseCount en este tipo de consultas, que por otro lado suelen ser muy habituales si se trabaja sobre una estructura en árbol.

Si vuestro caso es otro, quizás pensando un poco podáis encontrar una solución alternativa a los comodines. Y si no, no tendréis más remedio que aumentar el maxClauseCount, pero como se suele decir, "eso es pan para hoy, pero hambre para mañana".

Por último, decir que en Lucene no van bien las consultas con "/", por lo que tendréis que transformar el path antes de indexar y antes de consultar, de forma que sustituyáis las "/" por otro/s caráctere/s. Podéis usar las solución que hace Alfresco, que consiste en transformar las "/" por "_x" o algo así. Es una ISO, pero no recuerdo el número. En cuanto lo encuentre lo actualizaré.

Espero que os sea de utilidad.

martes, 10 de febrero de 2009

Configuración del teclado en la consola tty en Linux (Debian)

La configuración del teclado en un entorno X Window, como X.Org, se define en los ficheros de configuración propios del X Window. Pero, ¿qué ocurre cuando no tenemos levantadas las X? Por ejemplo, en la consola tty. ¿Cómo configuramos la distribución del teclado?

Éste ha sido mi problema durante un tiempo. Tenía perfectamente configurado mi sistema en el entorno gráfico: teclado español para todos los usuarios, ... ; pero cuando abría una consola tty, normalmente como root, el teclado tenía la configuración americana. Al principio creía que era cosa de la configuración del usuario root, pero ejecutaba el comando locale y el idioma era el correcto:

LANG=es_ES.UTF-8
LC_CTYPE="es_ES.UTF-8"
LC_NUMERIC="es_ES.UTF-8"
LC_TIME="es_ES.UTF-8"
LC_COLLATE="es_ES.UTF-8"
LC_MONETARY="es_ES.UTF-8"
LC_MESSAGES="es_ES.UTF-8"
LC_PAPER="es_ES.UTF-8"
LC_NAME="es_ES.UTF-8"
LC_ADDRESS="es_ES.UTF-8"
LC_TELEPHONE="es_ES.UTF-8"
LC_MEASUREMENT="es_ES.UTF-8"
LC_IDENTIFICATION="es_ES.UTF-8"
LC_ALL=

El quid de la cuestión estaba en lo que he expuesto en el primer párrafo. En el entorno gráfico la distribución del teclado se configura en los ficheros de las X Windows, X.Org en mi caso:

bash$ dpkg-reconfigure xserver-xorg

pero en la consola tty al no haber X Window, eso no vale. Basta reconfigurar el paquete console-data para solucionar el problema

bash$ dpkg-reconfigure console-data

Si alguien tiene el mismo problema que yo ya sabe cómo solucionarlo.

Que conste que no tengo nada en contra de los teclados americanos, lo que pasa es que cuando tienes un teclado en el que el símbolo de cada tecla no se corresponde con lo que escribe en pantalla te vuelves loco buscando ciertos caracteres tan útiles como "/", "-" o "|". Y no digamos si te pones a editar en vi ¿dónde están los ":"?

En fin, para no discriminar a nadie se puede decir que esto sirve en general para configurar el teclado correctamente en la consola tty. ;-)

domingo, 1 de febrero de 2009

Depurar fugas de memoria en Java (Tomcat)

Hola a todos. Por fin logro sacar algo de tiempo para escribir el primer post de este año. Esta vez está relacionado con la depuración de bugs relacionado con la memoria.

Si tienes problemas de memoria con Tomcat, o en general con aplicaciones Java(OutOfMemoryException), necesitas o simplemente tienes curiosidad de saber la distribución de la memoria de tu aplicación, no sigas buscando, este es tu post.

Las opciones que voy a mostrar son opciones de configuración de la Máquina Virtual Java (JVM), por lo tanto son aplicables tanto a una simple clase con un método main, como a una aplicación sobre Tomcat o cualquier otro servidor de aplicaciones. Sin embargo, en este post voy a tomar como ejemplo Tomcat, ya que es lo que uso en el desarrollo de aplicaciones web.

Más concretamente utilicé estas opciones para investigar un problema que teníamos con Tomcat. Cada cierto intervalo regular de tiempo, el Tomcat se caía debido a un error de OutOfMemory. Por más que aumentamos la memoria, seguía cayéndose aunque a intervalos más grandes, por lo que empezamos a sospechar que había algo en nuestra aplicación que iba consumiendo memoria y no la liberaba. Nuestra aplicación tenía fugas de memoria.

Para resolverlo necesitabamos saber dónde estaba el problema, y al igual que ocurre cuando te rompes un hueso, el mejor diagnóstico se hace si tienes una radiografía de la memoria. Por suerte Java nos permite hacer esto. Para ello sólo hay que usar el comando jmap.

Antes de continuar comentar que todo lo que expongo aquí es para Java 6. Con Java 5 también lo podéis hacer a partir de cierta versión, pero el formato de los comandos cambia un poco. De todas formas, mi recomendación es que paséis a Java 6. El paso es casi inmediato y os ahorraréis muchos quebraderos de cabeza con estos comandos y opciones.

Para hacer un volcado de la memoria del Tomcat, tendréis que ejecutar lo siguiente:

bash$ jmap -dump:file=heap.hprof <pid>

donde <pid> es el id del proceso Tomcat. Podéis sacarlo con el comando ps:

bash$ ps -ef | grep tomcat
usuario 13832 1 79 22:37 pts/0 00:00:14 /usr/lib/jvm/java-6-sun/bin/java -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djava.util.logging.config.file=/opt/tomcat/conf/logging.properties -Djava.endorsed.dirs=/opt/tomcat/common/endorsed -classpath :/opt/tomcat/bin/bootstrap.jar:/opt/tomcat/bin/commons-logging-api.jar -Dcatalina.base=/opt/tomcat -Dcatalina.home=/opt/tomcat -Djava.io.tmpdir=/opt/tomcat/temp org.apache.catalina.startup.Bootstrap start

En mi caso el pid sería 13832 y por tanto la ejecución del comando jmap quedaría así:

bash$ jmap -dump:file=heap.hprof 13832
Dumping heap to /opt/apache-tomcat-5.5.25/heap.hprof ...
Heap dump file created

Esto genera el fichero heap.hprof en el directorio donde ejecutéis el jmap. Este fichero es un volcado de lo que hay en la memoria del Tomcat, y por tanto ocupará tanto como la memoria del Tomcat. Comprobad que tenéis espacio en disco suficiente para generarlo.

Sin embargo, no necesitábamos una radiografía de la memoria en cualquier momento, la necesitábamos justo en el momento en que el hueso se rompía, es decir, cuando el Tomcat lanza la OutOfMemoryException. Por suerte, contamos con las opciones de la JVM. Para que Tomcat -y repito: Tomcat o cualquier aplicación Java- genere un volcado de la memoria al producir una OutOfMemoryException tenéis que poner entre sus JAVA_OPTS las siguientes opciones:

-XX:HeapDumpPath=/ruta/donde/guardar/el/fichero/ -XX:+HeapDumpOnOutOfMemoryError

Observad que es un más(+) lo que hay antes de HeapDumpOn..... Si ponéis un menos(-), no os funcionará. Es un error muy típico ;-)

En el caso del Tomcat, tendremos que editar el fichero catalina.sh y meter las opciones en la variable CATALINA_OPTS. Por ejemplo:

CATALINA_OPTS="-XX:HeapDumpPath=/tmp/ -XX:+HeapDumpOnOutOfMemoryError [...resto de opciones...]"

Un Tomcat funcionando con estas opciones generará un fichero en /tmp llamado heap<pid>.hprof automáticamente cuando se produzca una OutOfMemoryException. Más información sobre esas opciones en Java HotSpot VM Options.

Una vez configurado de esta forma, ya sólo teníamos que esperar a que el Tomcat volviese a fallar. Y de eso estábamos seguros. Una vez con el fichero hprof generado podemos usar dos herramientas para procesarlo.

Una es VisualVM. Es de Sun y viene con el JDK de Java 6. Es el comando jvisualvm que se encuentra en el directorio bin del JDK. Con esta herramienta puedes navegar por los objetos que hay en memoria, ver las clases que más instancias tienen y que más consumen, etc. Te muestra lo que hay en memoria literalmente, pero para mi gusto es demasiada información en bruto y quizás sea complicado ver lo que está pasando.

La otra herramienta es Eclipse Memory Analyzer. Esta herramienta procesa la información y saca gráficas y estadísticas útiles. Incluso te propone posibles errores. Con esta herramienta fue con la que rápidamente descubrimos el error, ya que la gráfica de tarta de la ocupación de la memoria estaba al 75% ocupada por cierta parte de la aplicación. Se trataba de una de nuestras cachés. De ahí, muy hábiles nosotros, dedujimos que el proceso de limpiado de esa caché no estaba funcionando correctamente y por tanto, esta caché era un saco donde se metían cosas, pero nunca salían. :-p

Espero que esto os ayude a resolver este tipo de problemas si es que lo tenéis, y si no tienes problemas de este tipo, ¿nunca te has preguntado cuanto ocupa tu aplicación en memoria y qué objetos ocupan más? Merece la pena probar.