using System;
using System.Diagnostics;
using System.Collections;
using System.Runtime.InteropServices;
using System.IO;
using System.Text;
namespace RaptorDB
{
internal class StorageFile
{
System.IO.Stream fromfile;
private int _maxKeyLen;
public static byte[] _fileheader = { (byte)'M', (byte)'G', (byte)'D', (byte)'B',
0, // -- [flags] = [shutdownOK:1],
0 // -- [maxkeylen]
};
public static byte[] _rowheader = { (byte)'M', (byte)'G', (byte)'R' ,
0, // 4 [keylen]
0,0,0,0,0,0,0,0, // 5-12 [datetime] 8 bytes = insert time
0,0,0,0, // 13-16 [data length] 4 bytes
0, // 17 -- [flags] = isCommited:1
// isRollback:1
// isCompressed:1
// isDeleted:1
// isVersioned:1
0 // 18 -- [crc] = header crc check
};
private enum HDR_POS
{
KeyLen = 3,
DateTime = 4,
DataLength = 12,
Flags = 16,
CRC = 17
}
public StorageFile(System.IO.Stream file, int maxkeylen)
{
fromfile = file;
_maxKeyLen = maxkeylen;
if (fromfile.Length == 0)
{
// new file
byte b = (byte)maxkeylen;
_fileheader[5] = b;
fromfile.Write(_fileheader, 0, _fileheader.Length);
fromfile.Flush();
}
else
{
// TODO : check file header exists
// TODO : check file flags ok
}
bw = new BinaryWriter(ms, Encoding.UTF8);
}
public long WriteData(byte[] key, byte[] data)
{
byte[] k = key;
int kl = k.Length;
// seek end of file
long offset = fromfile.Seek(0L, System.IO.SeekOrigin.End);
byte[] hdr = CreateRowHeader(kl, data.Length);
// write header info
fromfile.Write(hdr, 0, hdr.Length);
// write key
fromfile.Write(k, 0, kl);
// write data block
fromfile.Write(data, 0, data.Length);
fromfile.Flush();
// return starting offset
return offset;
}
MemoryStream ms = new MemoryStream();
BinaryWriter bw;
private byte[] CreateRowHeader(int keylen, int datalen)
{
ms.Seek(0L, SeekOrigin.Begin);
bw.Write(_rowheader, 0, 3);
bw.Write((byte)keylen);
bw.Write(FastDateTime.Now.Ticks);
bw.Write(datalen);
bw.Write(0);
bw.Flush();
return ms.ToArray();
}
public byte[] ReadData(long offset)
{
// seek offset in file
byte[] hdr = new byte[_rowheader.Length];
fromfile.Seek(offset, System.IO.SeekOrigin.Begin);
// read header
fromfile.Read(hdr, 0, _rowheader.Length);
// check header
if (CheckHeader(hdr))
{
// skip key bytes
fromfile.Seek(hdr[(int)HDR_POS.KeyLen], System.IO.SeekOrigin.Current);
int dl = Helper.ToInt32(hdr, (int)HDR_POS.DataLength);
byte[] data = new byte[dl];
// read data block
fromfile.Read(data, 0, dl);
return data;
}
else
throw new Exception("data header error");
}
private bool CheckHeader(byte[] hdr)
{
if (hdr[0] != (byte)'M' && hdr[1] != (byte)'G' && hdr[2] != (byte)'R' && hdr[(int)HDR_POS.CRC] != 0)
return false;
return true;
}
public void Shutdown()
{
this.fromfile.Flush();
this.fromfile.Close();
}
}
}