Una función hash rodante (también conocida como hash recursivo o suma de verificación rodante) es una función hash en la que la entrada se procesa mediante una ventana que se desplaza a través de la entrada.
Algunas funciones hash permiten calcular un hash rodante muy rápidamente: el nuevo valor hash se calcula rápidamente a partir únicamente del valor hash anterior, se elimina el valor anterior de la ventana y se agrega el nuevo valor a la ventana, de forma similar a como se puede calcular una función de promedio móvil mucho más rápido que otros filtros de paso bajo; y de forma similar a como se puede actualizar rápidamente un hash Zobrist a partir del valor hash anterior.
Una de las principales aplicaciones es el algoritmo de búsqueda de cadenas Rabin-Karp , que utiliza el hash rodante descrito a continuación. Otra aplicación popular es el programa rsync , que utiliza una suma de verificación basada en adler-32 de Mark Adler como hash rodante. El sistema de archivos de red de bajo ancho de banda (LBFS) utiliza una huella digital Rabin como hash rodante. FastCDC (Fast Content-Defined Chunking) utiliza una huella digital Gear de alta eficiencia computacional como hash rodante.
En el mejor de los casos, los valores hash rodantes son independientes por pares [ 1 ] o fuertemente universales . No pueden ser independientes por tres , por ejemplo.
Hash rodante polinomial
El algoritmo de búsqueda de cadenas de Rabin-Karp se suele explicar utilizando una función hash rodante que solo emplea multiplicaciones y sumas:
- ,
dóndees una constante, yson los caracteres de entrada (pero esta función no es una huella digital de Rabin , véase más abajo).
Para evitar manipular grandes cantidadesvalores, todas las operaciones matemáticas se realizan módulo. La elección deyes fundamental para obtener un buen hashing; en particular, el móduloes típicamente un número primo . Consulte el generador congruencial lineal para obtener más información.
Eliminar y añadir caracteres simplemente implica sumar o restar el primer o último término. Desplazar todos los caracteres una posición a la izquierda requiere multiplicar la suma completa.porDesplazar todos los caracteres una posición a la derecha requiere dividir la suma total.por. Tenga en cuenta que en aritmética modular,se puede elegir para que tenga un inverso multiplicativopor cualSe puede multiplicar para obtener el resultado de la división sin realizar realmente una división.
Huella dactilar de Rabin
The Rabin fingerprint is another hash, which also interprets the input as a polynomial, but over the Galois fieldGF(2). Instead of seeing the input as a polynomial of bytes, it is seen as a polynomial of bits, and all arithmetic is done in GF(2) (similarly to CRC-32). The hash is the remainder after the division of that polynomial by an irreducible polynomial over GF(2). It is possible to update a Rabin fingerprint using only the entering and the leaving byte, making it effectively a rolling hash.[2]
Because it shares the same author as the Rabin–Karp string search algorithm, which is often explained with another, simpler rolling hash, and because this simpler rolling hash is also a polynomial, both rolling hashes are often mistaken for each other.[3]
Cyclic polynomial
Hashing by cyclic polynomial[4]—sometimes called Buzhash[5]—is also simple and it has the benefit of avoiding multiplications, using circular shift instead. It is a form of tabulation hashing: it presumes that there is some substitution function from characters to integers in the interval , essentially a lookup table (each of the 32 bit-positions of the values of s should be balanced, i.e. have as many 1s as there are 0s). Let the function be bitwise rotation. E.g., . Let be the bitwise exclusive or. Let be the i-th byte in a stream, and be the window size in use.
We precalculate for removing the contribution of a byte that is out of the window:[4]:Table III
The hash values is defined as the following recurrence relation:[4]:Table III
All values of H are within the interval . This recurrence relation describes the way to compute the hash in a rolling fashion:[4]:Table III
- Hash is initialized at 0.
- When the window is being filled, adding a character involves left-rotating the old hash by one position and XORing the new .
- When the window is full, the same procedure is used to add a character, followed by removal of the contribution of the out-of-window character by XORing .
The value of H is neither formally uniform nor 2-universal, despite its empirical uniformity. However, it can be made formally uniform and pairwise independent if only a consecutive Se toman bits del hash. En la práctica, esto puede ser una operación AND (enmascaramiento) a nivel de bits:, dóndees una operación AND bit a bit yes un desplazamiento a la izquierda. [ 1 ]
Además, los autores de borg señalan que w no debería ser un múltiplo de 2 L si se utiliza una semilla para modificar s[] mediante la operación XOR de cada valor con la semilla. [ 6 ]
Hashing de engranajes
El agrupamiento de engranajes es otro tipo de hash tabulado. Sea s una tabla inmutable de 256 enteros aleatorios sin signo de 32 bits, H el acumulador hash (entero sin signo, de al menos 32 bits) y f el archivo representado como una matriz de bytes (enteros de 8 bits, subíndice basado en 1).sea el operador de desplazamiento a la izquierda. La relación de recurrencia es: [ 7 ]
En comparación con el hash polinomial cíclico, la operación de rotación a la izquierda se reemplaza por un desplazamiento a la izquierda, lo que elimina la necesidad de eliminar la contribución de un byte fuera de la ventana. La operación XOR también se reemplaza por una suma. La segmentación se realiza en función de los bits superiores de H. Este tipo de segmentación genera resultados comparables con la huella digital de Rabin en un tercio del tiempo. [ 7 ] Sin embargo, en la práctica, la distribución de tamaños de división fue más amplia que la de Rabin, lo que hizo que los resultados de deduplicación fueran aproximadamente un 1 % peores para los casos típicos y un 6 % peores para el peor caso. [ 8 ]
El uso de los bits inferiores también es aceptable , pero reduce el tamaño efectivo de la ventana deslizante. El mayor tamaño efectivo aparece cuando la máscara muestrea una serie de bits no consecutivos de un "intervalo" relativamente amplio de H. [ 8 ]
Segmentación basada en contenido mediante un hash rotatorio
Una de las aplicaciones interesantes de la función hash rodante es que puede crear fragmentos dinámicos basados en el contenido de un flujo o archivo. Esto resulta especialmente útil cuando se requiere enviar solo los fragmentos modificados de un archivo grande a través de una red: una simple adición de bytes al principio del archivo normalmente provocaría que todas las ventanas de tamaño fijo se actualizaran, cuando en realidad, solo se ha modificado el primer "fragmento". [ 9 ]
Un enfoque simple para hacer fragmentos dinámicos es calcular un hash rodante, y si el valor hash coincide con un patrón arbitrario (por ejemplo, todos ceros) en los N bits inferiores (con una probabilidad deDado que el hash tiene una distribución de probabilidad uniforme, se elige como límite de un fragmento. Cada fragmento tendrá, por lo tanto, un tamaño promedio debytes. Este enfoque garantiza que los datos no modificados (a más de un tamaño de ventana de distancia de los cambios) tendrán los mismos límites. Una vez que se conocen los límites, los fragmentos deben compararse mediante un valor hash criptográfico para detectar cambios. [ 10 ]
Este tipo de segmentación definida por contenido (CDC) o segmentación basada en contenido (CBC) se utiliza a menudo para la deduplicación de datos . [ 9 ] [ 11 ] La función hash utilizada puede ser cualquier algoritmo de hash rodante. Algunos ejemplos son:
- Agrupación en los fragmentos menos significativos
- Huella digital de Rabin, tal como se utiliza en el software de copia de seguridad restic (con un tamaño de blob que varía entre 512 KiB y 8 MiB y una ventana de 64 bytes). [ 9 ]
- Agrupación en cualquier bit consecutivo
- Polinomio cíclico (buzhash), como el que se usa en el software de copia de seguridad Borg . Borg proporciona un rango de tamaño de fragmento personalizable para dividir flujos de archivos, basado en la variación de N , por defecto entre 512 KiB y 8 MiB ). [ 11 ] Utiliza una ventana de 4095 bytes [ 11 ] y una función de sustitución no balanceada. [ 13 ]
- Fragmentación en cualquier colección de bits
La segmentación basada en contenido tiene la ventaja de que, en la mayoría de los casos, los cambios locales en un archivo solo afectan al fragmento en el que se encuentra y posiblemente al siguiente, pero no a ningún otro. La elección de distintos algoritmos y funciones hash ofrece diferentes niveles de garantía.
Segmentación basada en contenido mediante suma móvil
Varios programas, incluidos gzip (con la --rsyncableopción) y rsyncrypto, realizan un seccionamiento basado en el contenido basado en esta suma móvil específica (no ponderada): [ 12 ]
dónde
- es bytedel archivo,
- es un "valor hash" que consiste en los 12 bits inferiores de la suma de 8196 bytes consecutivos que terminan con el byte.
Desplazar la ventana un byte simplemente implica sumar el nuevo carácter a la suma y restar el carácter más antiguo (que ya no está en la ventana) de la suma. Gracias a las propiedades de la aritmética modular, el almacenamiento requerido es de tan solo 12 bits.
Por cadadónde, estos programas cortan el archivo entrey.
FastCDC
FastCDC optimiza el CDC basado en Gear [ 7 ] principalmente mediante la adición de un bucle de "arranque" para los bytes anteriores al tamaño mínimo deseado. Al omitir la comprobación de corte, se mejora el rendimiento y, además, se añade una función que permite controlar el tamaño mínimo. [ 8 ] El nuevo esquema duplica aproximadamente la velocidad con respecto al antiguo algoritmo basado en Gear y es 10 veces más rápido que el enfoque CDC basado en Rabin. [ 15 ]
El pseudocódigo de la versión básica se proporciona a continuación:
entrada del algoritmo FastCDC : búfer de datos src , longitud de datos n , salida: punto de corte iMinSize ← 2KB // tamaño mínimo de fragmento dividido es 2 KB MaxSize ← 64KB // tamaño máximo de fragmento dividido es 64 KB Mask ← 0x0000d93003530000 // 13 bits activados -> tamaño promedio deseado es 2^13 bytes = 8 KB fp ← 0 // uint64 i ← 0 // El tamaño del búfer es menor que el tamaño mínimo del fragmento. Si n ≤ MinSize , entonces devuelve n. Si n ≥ MaxSize , entonces n ← MaxSize. // Saltar los primeros MinSize bytes y arrancar el hash mientras i < MinSize hacer fp ← ( fp << 1 ) + Gear [ src [ i ]] i ← i + 1 mientras i < n hacer fp ← ( fp << 1 ) + Gear [ src [ i ]] si !( fp & Mask ) entonces devolver i i ← i + 1 regreso i
Donde la matriz Gear es equivalente a la tabla s anterior.
Una versión avanzada utiliza dos máscaras diferentes derivadas de la máscara anterior , una con 15 bits activados y la otra con 11 bits activados. La primera se usa cuando i < 8 KB; posteriormente, se usa la segunda. Esto ajusta la distribución del tamaño de los bloques alrededor del promedio deseado y mejora la deduplicación. [ 8 ]
Complejidad computacional
Todas las funciones hash rodantes se pueden calcular en tiempo lineal para el número de caracteres y actualizar en tiempo constante cuando los caracteres se desplazan una posición. En particular, el cálculo del hash rodante de Rabin-Karp de una cadena de longitudrequiereoperaciones aritméticas modulares y el hash mediante polinomios cíclicos requiereOR exclusivos a nivel de bits y desplazamientos circulares . [ 1 ]
Véase también
Referencias
- 1 2 3 Daniel Lemire, Owen Kaser: El hash recursivo de n -gramas es independiente por pares, en el mejor de los casos, Computer Speech & Language 24 (4), páginas 698–710, 2010. arXiv:0705.4676 .
- ↑ Huellas dactilares mediante polinomios aleatorios. Rabin, M. (1981)
- ↑ "Referencias — documentación de restic 0.9.0" . restic.readthedocs.io . Consultado el 24 de mayo de 2018 .
- 1 2 3 4 Cohen, Jonathan D. (julio de 1997). "Funciones hash recursivas para n-gramas". ACM Transactions on Information Systems . 15 (3): 291– 320. doi : 10.1145/256163.256168 .
- ^ Uzgalis, Robert (1995). "BUZ Hash" .
- ↑ "docs: se agregaron algunas ideas de "Voltara", corrige #903 · ThomasWaldmann/borg@ec93073" . GitHub .
- 1 2 3 4 Xia, Wen; Jiang, Hong; Feng, Dan; Tian, Lei; Fu, Min; Zhou, Yukun (septiembre de 2014). "Ddelta: Un enfoque de compresión delta rápida inspirado en la deduplicación". Performance Evaluation . 79 : 258–272 . doi : 10.1016/j.peva.2014.07.016 .
- 1 2 3 4 Xia, Wen; Zhou, Yukun; Jiang, Hong; Feng, Dan; Hua, Yu; Hu, Yuchong; Liu, Qing; Zhang, Yucheng (2016). FastCDC: Un enfoque de segmentación rápido y eficiente definido por contenido para la deduplicación de datos . Conferencia Técnica Anual USENIX 2016 (ATC '16). Asociación Usenix. ISBN 9781931971300. Consultado el 24 de julio de 2020 .
- 1 2 3 "Fundamentos: Introducción a la segmentación definida por contenido (CDC)" . 2015.
- 1 2 Horvath, Adam (24 de octubre de 2012). "Rabin Karp rolling hash: fragmentos de tamaño dinámico basados en el contenido hash" .
- 1 2 3 "Estructuras de datos y formatos de archivo — Documentación de Borg - Deduplicating Archiver 1.1.5" . borgbackup.readthedocs.io . Consultado el 24 de mayo de 2018 .
- 1 2 "Algoritmo Rsyncrypto" .
- ^ Waldmann, Thomas. "Documentos de borg: ideas/discusión de buzhash" . GitHub .
- ↑ Leeb-du Toit, J. "Introducción a la segmentación definida por contenido" . joshleeb.com .
- ↑ Xia, Wen; Zou, Xiangyu; Jiang, Hong; Zhou, Yukun; Liu, Chuanyi; Feng, Dan; Hua, Yu; Hu, Yuchong; Zhang, Yucheng (16 de junio de 2020). "El diseño de fragmentación rápida definida por contenido para sistemas de almacenamiento basados en deduplicación de datos". Transacciones IEEE en sistemas paralelos y distribuidos . 31 (9): 2017– 2031. Bibcode : 2020ITPDS..31.2017X . doi : 10.1109/TPDS.2020.2984632 . S2CID 215817722 .
Enlaces externos
- MIT 6.006: Introducción a los algoritmos 2011 - Sesión 9 - Hash rotatorio
- Funciones hash