sisoputnfrba / foro

Foro de consultas para el trabajo práctico
147 stars 6 forks source link

Problema con fwrite() a la hora de establecer un limite en el archivo. #841

Closed CDNievas closed 7 years ago

CDNievas commented 7 years ago

Buenas, estoy armando las funciones getBloque y setBloque del proceso DataNode y me encontré con un problema.

La función getBloque funciona perfectamente, va y busca los datos de un bloque en el archivo con un fread() y en caso de ser un bloque que no exista, ya que el archivo no tiene el tamaño suficiente, tira error.

A la hora de implementar la función setBloque, esta funciona pero a diferencia con la anterior, si escribo/grabo en un bloque que no existe en el archivo, me lo escribe igualmente agregando espacio. Y si hago un getBloque sobre este me trae los datos escritos correctamente.

De esto me di cuenta al entrar en las propiedades del archivo .bin y encontrarme con esto

image

Los datos de testeo fueron:

Cosas a tener en cuenta:

El algoritmo para resolverlo fue:

Agradezco cualquier ayuda que me pudieran dar

tferraro commented 7 years ago

No entiendo exactamente cual es la pregunta en particular, pero a tené en cuenta como creás el archivo, como lo hiciste? Lo más común que termina pasando cuando uno crea un archivo, es que el especio no esté asignado posta, sino que se haga a demanda.

Deeeee todas formas, investigate mmap() como dice el enunciado, antes de seguir pegándote la cabeza contra la pared, porque va a cambiar muuucho lo que estás haciendo. Justamente por estos casos, traten de ir siguiendo los hitos del TP.

Saludos!

Tom

nicozar95 commented 7 years ago

Buenas Creo, no estoy 100% seguro, que fwrite() siempre va a tratar de escribir un archivo hasta el tamaño maximo del mismo dependiendo de la arquitectura que tengas (creo que en arquitecturas de 32 bits es hasta 2GB en un solofwrite()).

Por lo tanto tenes 2 opciones que se me ocurren:

  1. Hacer vos mismo el calculo de los bloques que queres escribir, osea, antes de escribir un bloque fijarte que el mismo existe y si no existe largar el error.

  2. Podes usar algo de la familia de mmap() para manejar el archivo como si fuera un char* y asi ya lo limitas, porque creo que dispara una señal SIGBUS si tratas de escribir en un espacio de memoria mayor del archivo mapeado.

Cuando vos abris un archivo, con fopen() por ejemplo, el FD que te devuelve sirve como puntero a tu archivo con los permisos que le asignaste, al pasarle ese FD a tu fwrite() el mismo no entiende de limites de archivos que vos establezcas el va a escribir hasta lo que le permita la arquitectura, o en otras palabras, a el no le importa si ya creaste un archivo y vos queres que el tamaño de ese archivo sea fijo, el esta para escribir en el archivo y no tiene problemas en agrandarlo.

Saludos

CDNievas commented 7 years ago

No entiendo exactamente cual es la pregunta en particular,

Si era posible que fwrite() tirara error como lo hace el fread() al posicionarse excendiendose del tamaño del archivo ya que en la man para ambas funciones dice "If an error occurs, or the end of the file is reached, the return value is a short item count (or zero)"

pero a tené en cuenta como creás el archivo, como lo hiciste?

Cree una función que se llama generarDatabin() que si no encuentra el archivo data.bin creado con el path que se pasa por el archivo de configuración lo crea de X tamaño (lo recibe como argumento), usando las funciones fopen() con "wb", ftruncate() con fileno() ,y, el fclose().

Deeeee todas formas, investigate mmap() como dice el enunciado, antes de seguir pegándote la cabeza contra la pared, porque va a cambiar muuucho lo que estás haciendo. Justamente por estos casos, traten de ir siguiendo los hitos del TP

Ahí me voy a fijar lo leí por arriba y entendí que se referían a la función "nmap()" con lo cual automáticamente pensé "debe ser para las conexiones con sockets". Ahora que vi que es mmap() tiene mas sentido :joy:

nicozar95 commented 7 years ago

Ojo los errores de fwrite() van por otro lado, los mismos hacen referencias a los mensajes de error que te largafputc() y ninguno es un error de que queres escribir mas del tamaño del archivo (EFBIG es que el archivo no sea mayor a lo que te permita el sistema operativo no el usuario)

tferraro commented 7 years ago

Ahí me voy a fijar lo leí por arriba y entendí que se referían a la función "nmap()" con lo cual automáticamente pensé "debe ser para las conexiones con sockets". Ahora que vi que es mmap() tiene mas sentido 😂

Plz dale amor a mmap, te vas a evitar este problema con fwrite 😄

CDNievas commented 7 years ago

Hacer vos mismo el calculo de los bloques que queres escribir, osea, antes de escribir un bloque fijarte que el mismo existe y si no existe largar el error.

Supongamos que voy por esta opción para aprovechar lo que hice anteriormente. Existe alguna otra función del TP que me restrinja al uso si o si del mmap() posteriormente? O alguna otra función la cual el mmap() me salve?

Cuando vos abris un archivo, con fopen() por ejemplo, el FD que te devuelve sirve como puntero a tu archivo con los permisos que le asignaste, al pasarle ese FD a tu fwrite() el mismo no entiende de limites de archivos que vos establezcas el va a escribir hasta lo que le permita la arquitectura, o en otras palabras, a el no le importa si ya creaste un archivo y vos queres que el tamaño de ese archivo sea fijo, el esta para escribir en el archivo y no tiene problemas en agrandarlo.

Gracias por explicarlo, creí que había alguna forma mediante un permiso/función o parámetro de limitarlo a que solo reemplace datos :+1:

CDNievas commented 7 years ago

Plz dale amor a mmap, te vas a evitar este problema con fwrite :smile:

Voy a investigarlo pero depende que tan retorcido sea el usarlo o no

nicozar95 commented 7 years ago

Supongamos que voy por esta opción para aprovechar lo que hice anteriormente. Existe alguna otra función del TP que me restrinja al uso si o si del mmap() posteriormente? O alguna otra función la cual el mmap() me salve?

mmap() lo que te va a permitir hacer es manejar tu archivo como si fuese un char*, entonces te ahorras el tema de hacer fopen(),fseek(),etc y directamente haces un memcpy() de lo que queres escribir en tu archivo y despues lo sincronizas con msync() Como cualquier char*, si queres escribir en una pocision de memoria que no alocaste te va a largar error.

Al hacerlo confseek(), lo que deberias hacer es controlar cuantos bloques tiene tu data.bin a priori para asi saber que si te mandan a escribir un bloque que no existe decirle que no.

CDNievas commented 7 years ago

mmap() lo que te va a permitir hacer es manejar tu archivo como si fuese un char, entonces te ahorras el tema de hacer fopen(),fseek(),etc y directamente haces un memcpy() de lo que queres escribir en tu archivo y despues lo sincronizas con msync() Como cualquier char, si queres escribir en una pocision de memoria que no alocaste te va a largar error. Al hacerlo confseek(), lo que deberias hacer es controlar cuantos bloques tiene tu data.bin a priori para asi saber que si te mandan a escribir un bloque que no existe decirle que no.

Gracias a los 2 por explicarlo tan claro :smile: cierro el issue entonces.