{"id":931,"date":"2007-05-04T17:52:14","date_gmt":"2007-05-04T20:52:14","guid":{"rendered":"http:\/\/www.maurom.com\/blog\/?p=931"},"modified":"2014-05-27T17:47:26","modified_gmt":"2014-05-27T20:47:26","slug":"come-mis-datos-por-que-todos-malinterpretamos-la-es-de-archivos","status":"publish","type":"post","link":"https:\/\/maurom.com\/blog\/2007\/05\/04\/come-mis-datos-por-que-todos-malinterpretamos-la-es-de-archivos\/","title":{"rendered":"Come mis datos: por qu\u00e9 todos malinterpretamos la E\/S de archivos"},"content":{"rendered":"<p>En <a href=\"http:\/\/www.besttechvideos.com\/\">besttechvideos<\/a> publicaron un video de la \u00faltima <a href=\"http:\/\/lca2007.linux.org.au\/\">LinuxConf<\/a> en Australia donde Stewart Smith, un ingeniero de software de MySQL AB, comenta acerca de c\u00f3mo debemos proceder para mantener la integridad de los datos en disco al desarrollar una aplicaci\u00f3n.<\/p>\n<p>El video est\u00e1 disponible <a href=\"http:\/\/lca2007.linux.org.au\/talk\/278\">aqu\u00ed (en flash)<\/a> o <a href=\"http:\/\/mirror.linux.org.au\/pub\/linux.conf.au\/2007\/video\/talks\/278.ogg\">aqu\u00ed (en ogg)<\/a>.<br \/>\nComo la disertaci\u00f3n es en ingl\u00e9s, les dejo una s\u00edntesis de lo que Smith comenta:<\/p>\n<p><span style=\"font-weight: bold;\">Una breve introducci\u00f3n<\/span><\/p>\n<p>Al comienzo de los tiempos, toda la entrada y salida de archivos era sincr\u00f3nica; es decir, una llamada a grabar implicaba que los datos llegaban al dispositivo f\u00edsico en el momento, y el procesamiento se deten\u00eda hasta finalizar la operaci\u00f3n. Por razones obvias la performance de este m\u00e9todo es muy baja, de ah\u00ed que surgi\u00f3 la llamada<a href=\"http:\/\/en.wikipedia.org\/wiki\/Asynchronous_I\/O\"> entrada\/salida as\u00edncrona<\/a>, que permite continuar la ejecuci\u00f3n del c\u00f3digo mientras los datos son le\u00eddos o escritos a disco.<\/p>\n<p>Lamentablemente, no existe un mundo sin fallas: las computadoras se cuelgan, se corta la luz, se termina la bater\u00eda, alguien se tropez\u00f3 con el cable, etc&#8230;<\/p>\n<p><span style=\"font-weight: bold;\">Bien, \u00bfcuando ocurre un corte de energia, qu\u00e9 es lo que se pierde?<\/span><\/p>\n<ul>\n<li>Lo que est\u00e1 en buffers de la aplicaci\u00f3n<\/li>\n<li>Lo que est\u00e1 en buffers de las librer\u00edas<\/li>\n<li>Lo que est\u00e1 en buffers del S.O. (page\/buffer cache)<\/li>\n<\/ul>\n<p><span style=\"font-weight: bold;\">\u00bfD\u00f3nde radican los errores que llevan a la p\u00e9rdida de datos?<\/span><\/p>\n<ul>\n<li>En el c\u00f3digo de la aplicaci\u00f3n<\/li>\n<li>En el c\u00f3digo de la librer\u00eda utilizada<\/li>\n<li>En el c\u00f3digo del kernel del sistema operativo<\/li>\n<\/ul>\n<p><span style=\"font-weight: bold;\">\u00bfCu\u00e1l es el flujo de los datos desde una aplicaci\u00f3n hacia el disco, al grabar?<\/span><\/p>\n<p>En un resumen burdo: con las funciones <span style=\"font-style: italic;\">fwrite<\/span>, <span style=\"font-style: italic;\">fprint<\/span> y otras, la aplicaci\u00f3n pasa los datos a la librer\u00eda (p. ej., glibc); la librer\u00eda a su vez dirige los datos con <span style=\"font-style: italic;\">write<\/span> y similares al sistema operativo; y este \u00faltimo hacia el disco mediante <span style=\"font-style: italic;\">page out<\/span> y <span style=\"font-style: italic;\">flushing <\/span>peri\u00f3dico realizado entre 5 y 30 segundos (o m\u00e1s si se trata de una laptop). En cualquiera de estos momentos nuestros datos son vulnerables ante una falla de energ\u00eda.<span style=\"font-size: 85%;\"><span style=\"font-family: courier new;\"><br \/>\n<\/span><\/span><span style=\"font-weight: bold;\"><br \/>\n\u00bfEs <\/span><span style=\"font-style: italic; font-weight: bold;\">write<\/span><span style=\"font-weight: bold;\"> at\u00f3mico? \u00bfQu\u00e9 pasa si se corta la energ\u00eda en la mitad de una operaci\u00f3n <\/span><span style=\"font-style: italic; font-weight: bold;\">write<\/span><span style=\"font-weight: bold;\">?<\/span><\/p>\n<p>Pues no, y si se corta la energ\u00eda en la mitad de la operaci\u00f3n lo m\u00e1s probable es que la informaci\u00f3n en el archivo sea un conglomerado entre los datos de la versi\u00f3n anterior y los de la que se <span style=\"font-style: italic;\">estaba<\/span> guardando.<\/p>\n<p><span style=\"font-weight: bold;\">\u00bfC\u00f3mo puede evitarse esto?<\/span><\/p>\n<p>El truco m\u00e1s viejo consiste en escribir sobre un archivo temporal y luego renombrar al finalizar la operaci\u00f3n de escritura. De esa forma, los datos originales <span style=\"font-style: italic;\">estar\u00edan<\/span> seguros a\u00fan si se corta la energ\u00eda durante la etapa de escritura del archivo temporal. Y nunca tenemos que olvidarnos de las excepciones (permiso denegado, espacio en disco agotado).<\/p>\n<p><span style=\"font-weight: bold;\">\u00bfHummm&#8230; por qu\u00e9 dice <span style=\"font-style: italic;\">estar\u00edan<\/span> en la afirmaci\u00f3n anterior?<\/span><\/p>\n<p>Aqu\u00ed tenemos una interesante cuesti\u00f3n. Stewart indica en que <span style=\"font-style: italic;\">close<\/span> y <span style=\"font-style: italic;\">rename<\/span> no implican <span style=\"font-style: italic;\">sync<\/span>. Redondeando, <span style=\"font-weight: bold;\">nadie <\/span><span style=\"font-weight: bold;\">asegura que la operaci\u00f3n de cambio de nombre <\/span><span style=\"font-style: italic; font-weight: bold;\">rename<\/span><span style=\"font-weight: bold;\"> se realice despu\u00e9s del <\/span><span style=\"font-style: italic; font-weight: bold;\">write<\/span><span style=\"font-weight: bold;\"> y consecuente <\/span><span style=\"font-style: italic; font-weight: bold;\">close<\/span><span style=\"font-weight: bold;\">, a\u00fan estando en el orden correcto<\/span>. Las operaciones sobre los datos de un archivo (tales como la grabaci\u00f3n) se almacenan en buffers diferentes a las operaciones sobre los metadatos (tales como el renombrado), por lo que puede ocurrir (y generalmente ocurre) que estas \u00faltimas se realicen primero. En el triste caso de un fallo de energ\u00eda, habremos perdido la informaci\u00f3n original por haberse efectuado el cambio de nombre primero, y <span style=\"font-style: italic;\">adem\u00e1s<\/span> tendr\u00edamos un archivo corrupto, dado que los datos habr\u00edan quedado a medio grabar.<\/p>\n<p>Por suerte para nosotros, el modo <span style=\"font-style: italic;\">ordered<\/span> del sistema de archivos <span style=\"font-style: italic;\">ext3<\/span>, nos asegura que el orden de prioridad es: <span style=\"font-weight: bold;\">primero <\/span><span style=\"font-style: italic; font-weight: bold;\">write<\/span><span style=\"font-weight: bold;\">, luego <\/span><span style=\"font-style: italic; font-weight: bold;\">close<\/span><span style=\"font-weight: bold;\"> y luego <\/span><span style=\"font-style: italic; font-weight: bold;\">rename<\/span>. En otras palabras: primero grabar los datos al disco, luego actualizar el inodo y finalmente actualizar la entrada en el directorio.<\/p>\n<p>Bien, ahora sabemos que haciendo <span style=\"font-style: italic;\">fsync<\/span> mas la t\u00e9cnica del archivo temporal, sobre un sistema de archivos ext3 y efectuando los controles de errores correspondientes, si ocurre un fallo durante una operaci\u00f3n de escritura, los datos originales se mantienen seguros&#8230;<\/p>\n<p><span style=\"font-weight: bold;\">\u00bfQu\u00e9 tal en otras plataformas?<\/span><\/p>\n<p>El Sr. Smith nos da una advertencia interesante cuando observa que <span style=\"font-weight: bold;\">el est\u00e1ndar POSIX define como v\u00e1lida una implementaci\u00f3n de <\/span><span style=\"font-style: italic; font-weight: bold;\">fsync<\/span><span style=\"font-weight: bold;\"> nula<\/span>. En otras palabras, no podemos quedarnos tranquilos al utilizar <span style=\"font-style: italic;\">fsync<\/span> en nuestras aplicaciones, pues puede que el sistema operativo subyacente implemente dicha funci\u00f3n s\u00f3lo haciendo nada. O sea, que una <span style=\"font-style: italic;\">fsync<\/span> implementada como sigue es v\u00e1lida en el est\u00e1ndar POSIX:<\/p>\n<p><span style=\"font-family: courier new;\">int fsync (int fd) { return 0; }<\/span><\/p>\n<p><span style=\"font-weight: bold;\">\u00bfY c\u00f3mo se dio cuenta?<\/span><\/p>\n<p>Cuando se cans\u00f3 de tener p\u00e1ginas corruptas con MySQL, pues el <span style=\"font-style: italic;\">fsync<\/span> de MacOS X <span style=\"font-weight: bold;\">no descarga a disco el contenido del buffer de escritura<\/span>, sino que se requiere un <span style=\"font-style: italic;\">fcntl<\/span> adicional. As\u00ed que hay que hacer algunas definiciones diferentes dependiendo del sistema operativo para el cual se compile la aplicaci\u00f3n&#8230;<\/p>\n<p>En el video, Stewart tambi\u00e9n discurre con bastante detalle sobre el tratamiento de archivos de gran tama\u00f1o y las t\u00e9cnicas utilizadas para la recuperaci\u00f3n de datos (undo\/redo logs) y prealocaci\u00f3n de espacio.<\/p>\n<p>En fin, un poco de charla para espabilar las neuronas y refrescarse con en ingl\u00e9s. Espero que lo disfruten&#8230;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>En besttechvideos publicaron un video de la \u00faltima LinuxConf en Australia donde Stewart Smith, un ingeniero de software de MySQL AB, comenta acerca de c\u00f3mo debemos proceder para mantener la integridad de los datos en disco al desarrollar una aplicaci\u00f3n. El video est\u00e1 disponible aqu\u00ed (en flash) o aqu\u00ed (en ogg). Como la disertaci\u00f3n es [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[3],"_links":{"self":[{"href":"https:\/\/maurom.com\/blog\/wp-json\/wp\/v2\/posts\/931"}],"collection":[{"href":"https:\/\/maurom.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/maurom.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/maurom.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/maurom.com\/blog\/wp-json\/wp\/v2\/comments?post=931"}],"version-history":[{"count":0,"href":"https:\/\/maurom.com\/blog\/wp-json\/wp\/v2\/posts\/931\/revisions"}],"wp:attachment":[{"href":"https:\/\/maurom.com\/blog\/wp-json\/wp\/v2\/media?parent=931"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/maurom.com\/blog\/wp-json\/wp\/v2\/categories?post=931"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/maurom.com\/blog\/wp-json\/wp\/v2\/tags?post=931"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}