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