/
ChunkFooter.cs
87 lines (72 loc) · 2.92 KB
/
ChunkFooter.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
using System;
using System.IO;
using EventStore.Common.Utils;
using EventStore.Core.TransactionLog.Chunks.TFChunk;
namespace EventStore.Core.TransactionLog.Chunks {
public class ChunkFooter {
public const int Size = TFConsts.ChunkFooterSize;
public const int ChecksumSize = 16;
// flags within single byte
public readonly bool IsCompleted;
public readonly bool IsMap12Bytes;
public readonly int PhysicalDataSize; // the size of a section of data in chunk
public readonly long
LogicalDataSize; // the size of a logical data size (after scavenge LogicalDataSize can be > physicalDataSize)
public readonly int MapSize;
public readonly byte[] MD5Hash;
public readonly int MapCount; // calculated, not stored
public ChunkFooter(bool isCompleted, bool isMap12Bytes, int physicalDataSize, long logicalDataSize, int mapSize,
byte[] md5Hash) {
Ensure.Nonnegative(physicalDataSize, "physicalDataSize");
Ensure.Nonnegative(logicalDataSize, "logicalDataSize");
if (logicalDataSize < physicalDataSize)
throw new ArgumentOutOfRangeException("logicalDataSize",
string.Format("LogicalDataSize {0} is less than PhysicalDataSize {1}", logicalDataSize,
physicalDataSize));
Ensure.Nonnegative(mapSize, "mapSize");
Ensure.NotNull(md5Hash, "md5Hash");
if (md5Hash.Length != ChecksumSize)
throw new ArgumentException("MD5Hash is of wrong length.", "md5Hash");
IsCompleted = isCompleted;
IsMap12Bytes = isMap12Bytes;
PhysicalDataSize = physicalDataSize;
LogicalDataSize = logicalDataSize;
MapSize = mapSize;
MD5Hash = md5Hash;
var posMapSize = isMap12Bytes ? PosMap.FullSize : PosMap.DeprecatedSize;
if (MapSize % posMapSize != 0)
throw new Exception(string.Format("Wrong MapSize {0} -- not divisible by PosMap.Size {1}.", MapSize,
posMapSize));
MapCount = mapSize / posMapSize;
}
public byte[] AsByteArray() {
var array = new byte[Size];
using (var memStream = new MemoryStream(array))
using (var writer = new BinaryWriter(memStream)) {
var flags = (byte)((IsCompleted ? 1 : 0) | (IsMap12Bytes ? 2 : 0));
writer.Write(flags);
writer.Write(PhysicalDataSize);
if (IsMap12Bytes)
writer.Write(LogicalDataSize);
else
writer.Write((int)LogicalDataSize);
writer.Write(MapSize);
memStream.Position = Size - ChecksumSize;
writer.Write(MD5Hash);
}
return array;
}
public static ChunkFooter FromStream(Stream stream) {
var reader = new BinaryReader(stream);
var flags = reader.ReadByte();
var isCompleted = (flags & 1) != 0;
var isMap12Bytes = (flags & 2) != 0;
var physicalDataSize = reader.ReadInt32();
var logicalDataSize = isMap12Bytes ? reader.ReadInt64() : reader.ReadInt32();
var mapSize = reader.ReadInt32();
stream.Seek(-ChecksumSize, SeekOrigin.End);
var hash = reader.ReadBytes(ChecksumSize);
return new ChunkFooter(isCompleted, isMap12Bytes, physicalDataSize, logicalDataSize, mapSize, hash);
}
}
}