GOOGLE ADS

domingo, 1 de mayo de 2022

La mejor manera de leer una estructura sin procesar de un archivo

Fondo (Omitible)

En Linux, el archivo /var/run/utmpcontiene varias utmpestructuras, cada una en formato binario sin procesar, que se suceden en un archivo. utmpen sí mismo es relativamente grande (384 bytes en mi máquina). Estoy tratando de leer este archivo en sus datos sin procesar, y luego implementan controles después del hecho de que los datos tienen sentido. No soy nuevo en el óxido, pero esta es mi primera experiencia real con el lado inseguro de las cosas.

Planteamiento del problema

Tengo un archivo que contiene varios c sturct utmps ( docs ). En rust, me gustaría leer el archivo completo en una matriz de archivos Vec<libc::utmpx>. Más específicamente, dado un lector abierto a este archivo, ¿cómo podría leer uno struct utmp?

What I have so far

A continuación se muestran tres implementaciones diferentes de read_raw, que acepta un lector y devuelve un RawEntry(mi alias para struct utmp). ¿Qué método es el más correcto? Estoy tratando de escribir un código con el mayor rendimiento posible, y me preocupa que read_raw0pueda ser más lento que los demás si se trata de memcpys. ¿Cuál es la forma mejor/más rápida de lograr este comportamiento?

use std::io::Read;
use libc::utmpx as RawEntry;
const RawEntrySize = std::mem::size_of::<RawEntry>();
type RawEntryBuffer = [u8; RawEntrySize];
/// Read a raw utmpx struct
// After testing, this method doesn't work
pub fn read_raw0<R: Read>(reader: &mut R) -> RawEntry {
let mut entry: RawEntry = unsafe { std::mem::zeroed() };
unsafe {
let mut entry_buf = std::mem::transmute::<RawEntry, RawEntryBuffer>(entry);
reader.read_exact(&mut entry_buf[..]);
}
return entry;
}
/// Read a raw utmpx struct
pub fn read_raw1<R: Read>(reader: &mut R) -> RawEntry {
// Worried this could cause alignment issues, or maybe it's okay
// because transmute copies
let mut buffer: RawEntryBuffer = [0; RawEntrySize];
reader.read_exact(&mut buffer[..]);
let entry = unsafe {
std::mem::transmute::<RawEntryBuffer, RawEntry>(buffer)
};
return entry;
}
/// Read a raw utmpx struct
pub fn read_raw2<R: Read>(reader: &mut R) -> RawEntry {
let mut entry: RawEntry = unsafe { std::mem::zeroed() };
unsafe {
let entry_ptr = std::mem::transmute::<&mut RawEntry, *mut u8>(&mut entry);
let entry_slice = std::slice::from_raw_parts_mut(entry_ptr, RawEntrySize);
reader.read_exact(entry_slice);
}
return entry;
}

Nota: Después de más pruebas, parece read_raw0que no funciona. Creo que esto se debe a que transmutar crea un nuevo búfer en lugar de hacer referencia a la estructura.


Solución del problema

Esto es lo que se me ocurrió, que imagino que debería ser lo más rápido posible para leer una sola entrada. Sigue el espíritu de tu última entrada, pero evita la transmutación (Transmutar &mut Ta *mut u8se puede hacer con dos lanzamientos: t as *mut T as *mut u8). También usa MaybeUniniten lugar de zeroedser un poco más explícito (el ensamblaje probablemente sea el mismo una vez optimizado). Por último, la función no será segura de ninguna manera, por lo que también podemos marcarla como tal y eliminar los unsafebloqueos.

use std::io::{self, Read};
use std::slice::from_raw_parts_mut;
use std::mem::{MaybeUninit, size_of};
pub unsafe fn read_raw_struct<R: Read, T: Sized>(src: &mut R) -> io::Result<T> {
let mut buffer = MaybeUninit::uninit();
let buffer_slice = from_raw_parts_mut(buffer.as_mut_ptr() as *mut u8, size_of::<T>());

src.read_exact(buffer_slice)?;
Ok(buffer.assume_init())
}

No hay comentarios:

Publicar un comentario

Regla de Firestore para acceder a la generación de subcolección Permisos faltantes o insuficientes

Tengo problemas con las reglas de Firestore para permitir el acceso a algunos recursos en una subcolección. Tengo algunos requests document...