Unverified 提交 86379c34 authored 作者: Noel Grandin's avatar Noel Grandin 提交者: GitHub

Merge pull request #768 from katzyn/DataUtils

Add DataUtils.parseChecksummedMap()
......@@ -259,7 +259,7 @@ public class Chunk {
DataUtils.appendMap(buff, "block", block);
DataUtils.appendMap(buff, "version", version);
byte[] bytes = buff.toString().getBytes(StandardCharsets.ISO_8859_1);
int checksum = DataUtils.getFletcher32(bytes, bytes.length);
int checksum = DataUtils.getFletcher32(bytes, 0, bytes.length);
DataUtils.appendMap(buff, "fletcher", checksum);
while (buff.length() < Chunk.FOOTER_LENGTH - 1) {
buff.append(' ');
......
......@@ -10,6 +10,7 @@ import java.io.IOException;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
......@@ -672,6 +673,49 @@ public final class DataUtils {
return map;
}
/**
* Parse a key-value pair list and checks its checksum.
*
* @param bytes encoded map
* @return the map without mapping for {@code "fletcher"}, or {@code null} if checksum is wrong
* @throws IllegalStateException if parsing failed
*/
public static HashMap<String, String> parseChecksummedMap(byte[] bytes) {
int start = 0, end = bytes.length;
while (start < end && bytes[start] <= ' ') {
start++;
}
while (start < end && bytes[end - 1] <= ' ') {
end--;
}
String s = new String(bytes, start, end - start, StandardCharsets.ISO_8859_1);
HashMap<String, String> map = New.hashMap();
StringBuilder buff = new StringBuilder();
for (int i = 0, size = s.length(); i < size;) {
int startKey = i;
i = s.indexOf(':', i);
if (i < 0) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT, "Not a map: {0}", s);
}
if (i - startKey == 8 && s.regionMatches(startKey, "fletcher", 0, 8)) {
DataUtils.parseMapValue(buff, s, i + 1, size);
int check = (int) Long.parseLong(buff.toString(), 16);
if (check == DataUtils.getFletcher32(bytes, start, startKey - 1)) {
return map;
}
// Corrupted map
return null;
}
String key = s.substring(startKey, i++);
i = DataUtils.parseMapValue(buff, s, i, size);
map.put(key, buff.toString());
buff.setLength(0);
}
// Corrupted map
return null;
}
/**
* Parse a name from key-value pair list.
*
......@@ -721,22 +765,23 @@ public final class DataUtils {
* Calculate the Fletcher32 checksum.
*
* @param bytes the bytes
* @param offset initial offset
* @param length the message length (if odd, 0 is appended)
* @return the checksum
*/
public static int getFletcher32(byte[] bytes, int length) {
public static int getFletcher32(byte[] bytes, int offset, int length) {
int s1 = 0xffff, s2 = 0xffff;
int i = 0, evenLength = length / 2 * 2;
while (i < evenLength) {
int i = offset, len = offset + (length & ~1);
while (i < len) {
// reduce after 360 words (each word is two bytes)
for (int end = Math.min(i + 720, evenLength); i < end;) {
for (int end = Math.min(i + 720, len); i < end;) {
int x = ((bytes[i++] & 0xff) << 8) | (bytes[i++] & 0xff);
s2 += s1 += x;
}
s1 = (s1 & 0xffff) + (s1 >>> 16);
s2 = (s2 & 0xffff) + (s2 >>> 16);
}
if (i < length) {
if ((length & 1) != 0) {
// odd length: append 0
int x = (bytes[i] & 0xff) << 8;
s2 += s1 += x;
......
......@@ -575,9 +575,9 @@ public final class MVStore {
fileHeaderBlocks.get(buff);
// the following can fail for various reasons
try {
String s = new String(buff, 0, BLOCK_SIZE,
StandardCharsets.ISO_8859_1).trim();
HashMap<String, String> m = DataUtils.parseMap(s);
HashMap<String, String> m = DataUtils.parseChecksummedMap(buff);
if (m == null)
continue;
int blockSize = DataUtils.readHexInt(
m, "blockSize", BLOCK_SIZE);
if (blockSize != BLOCK_SIZE) {
......@@ -586,15 +586,6 @@ public final class MVStore {
"Block size {0} is currently not supported",
blockSize);
}
int check = DataUtils.readHexInt(m, "fletcher", 0);
m.remove("fletcher");
s = s.substring(0, s.lastIndexOf("fletcher") - 1);
byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
int checksum = DataUtils.getFletcher32(bytes,
bytes.length);
if (check != checksum) {
continue;
}
long version = DataUtils.readHexLong(m, "version", 0);
if (newest == null || version > newest.version) {
validStoreHeader = true;
......@@ -804,14 +795,8 @@ public final class MVStore {
end - Chunk.FOOTER_LENGTH, Chunk.FOOTER_LENGTH);
byte[] buff = new byte[Chunk.FOOTER_LENGTH];
lastBlock.get(buff);
String s = new String(buff, StandardCharsets.ISO_8859_1).trim();
HashMap<String, String> m = DataUtils.parseMap(s);
int check = DataUtils.readHexInt(m, "fletcher", 0);
m.remove("fletcher");
s = s.substring(0, s.lastIndexOf("fletcher") - 1);
byte[] bytes = s.getBytes(StandardCharsets.ISO_8859_1);
int checksum = DataUtils.getFletcher32(bytes, bytes.length);
if (check == checksum) {
HashMap<String, String> m = DataUtils.parseChecksummedMap(buff);
if (m != null) {
int chunk = DataUtils.readHexInt(m, "chunk", 0);
Chunk c = new Chunk(chunk);
c.version = DataUtils.readHexLong(m, "version", 0);
......@@ -833,7 +818,7 @@ public final class MVStore {
}
DataUtils.appendMap(buff, storeHeader);
byte[] bytes = buff.toString().getBytes(StandardCharsets.ISO_8859_1);
int checksum = DataUtils.getFletcher32(bytes, bytes.length);
int checksum = DataUtils.getFletcher32(bytes, 0, bytes.length);
DataUtils.appendMap(buff, "fletcher", checksum);
buff.append("\n");
bytes = buff.toString().getBytes(StandardCharsets.ISO_8859_1);
......
......@@ -54,24 +54,24 @@ public class TestDataUtils extends TestBase {
private void testFletcher() {
byte[] data = new byte[10000];
for (int i = 0; i < 10000; i += 1000) {
assertEquals(-1, DataUtils.getFletcher32(data, i));
assertEquals(-1, DataUtils.getFletcher32(data, 0, i));
}
Arrays.fill(data, (byte) 255);
for (int i = 0; i < 10000; i += 1000) {
assertEquals(-1, DataUtils.getFletcher32(data, i));
assertEquals(-1, DataUtils.getFletcher32(data, 0, i));
}
for (int i = 0; i < 1000; i++) {
for (int j = 0; j < 255; j++) {
Arrays.fill(data, 0, i, (byte) j);
data[i] = 0;
int a = DataUtils.getFletcher32(data, i);
int a = DataUtils.getFletcher32(data, 0, i);
if (i % 2 == 1) {
// add length: same as appending a 0
int b = DataUtils.getFletcher32(data, i + 1);
int b = DataUtils.getFletcher32(data, 0, i + 1);
assertEquals(a, b);
}
data[i] = 10;
int c = DataUtils.getFletcher32(data, i);
int c = DataUtils.getFletcher32(data, 0, i);
assertEquals(a, c);
}
}
......@@ -79,16 +79,18 @@ public class TestDataUtils extends TestBase {
for (int i = 1; i < 255; i++) {
Arrays.fill(data, (byte) i);
for (int j = 0; j < 10; j += 2) {
int x = DataUtils.getFletcher32(data, j);
int x = DataUtils.getFletcher32(data, 0, j);
assertTrue(x != last);
last = x;
}
}
Arrays.fill(data, (byte) 10);
assertEquals(0x1e1e1414,
DataUtils.getFletcher32(data, 10000));
DataUtils.getFletcher32(data, 0, 10000));
assertEquals(0x1e3fa7ed,
DataUtils.getFletcher32("Fletcher32".getBytes(), 10));
DataUtils.getFletcher32("Fletcher32".getBytes(), 0, 10));
assertEquals(0x1e3fa7ed,
DataUtils.getFletcher32("XFletcher32".getBytes(), 1, 10));
}
private void testMap() {
......
......@@ -525,7 +525,7 @@ public class ArchiveToolStore {
}
key[0] = cs;
key[1] = bucket;
key[2] = DataUtils.getFletcher32(buff, buff.length);
key[2] = DataUtils.getFletcher32(buff, 0, buff.length);
return key;
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论