tera/Source/core/db/db-row.js
progr76@gmail.com 38de781bd4 0.895
2019-02-18 16:29:55 +03:00

257 lines
6.8 KiB
JavaScript

/*
* @project: TERA
* @version: Development (beta)
* @license: MIT (not for evil)
* @copyright: Yuriy Ivanov 2017-2019 [progr76@gmail.com]
* Web: https://terafoundation.org
* Twitter: https://twitter.com/terafoundation
* Telegram: https://web.telegram.org/#/im?p=@terafoundation
*/
"use strict";
const fs = require('fs');
module.exports = class CDBState extends require("./db")
{
constructor(FileName, DataSize, Format, bReadOnly)
{
super()
this.FileName = FileName
this.DataSize = DataSize
this.Format = Format
this.WorkStruct = {}
var FI = this.OpenDBFile(this.FileName, !bReadOnly);
this.FileNameFull = FI.fname
this.LastHash = undefined
this.WasUpdate = 1
this.BufMap = {}
this.BufMapCount = 0
setInterval(this.CheckBufMap.bind(this), 1000)
}
GetMaxNum()
{
var FI = this.OpenDBFile(this.FileName);
var Num = Math.floor(FI.size / this.DataSize) - 1;
return Num;
}
CheckNewNum(Data)
{
if(Data.Num === undefined)
Data.Num = this.GetMaxNum() + 1
}
Write(Data, RetBuf)
{
var startTime = process.hrtime();
this.LastHash = undefined
this.WasUpdate = 1
this.CheckNewNum(Data)
Data.Num = Math.trunc(Data.Num)
this.DeleteMap(Data.Num)
var BufWrite = BufLib.GetBufferFromObject(Data, this.Format, this.DataSize, this.WorkStruct, 1);
var Position = Data.Num * this.DataSize;
var FI = this.OpenDBFile(this.FileName, 1);
var written = fs.writeSync(FI.fd, BufWrite, 0, BufWrite.length, Position);
if(written !== BufWrite.length)
{
TO_ERROR_LOG("DB-ROW", 10, "Error write to file:" + written + " <> " + BufWrite.length)
return false;
}
if(RetBuf)
{
RetBuf.Buf = BufWrite
}
if(Position >= FI.size)
{
FI.size = Position + this.DataSize
}
ADD_TO_STAT_TIME("ROWS_WRITE_MS", startTime)
ADD_TO_STAT("ROWS_WRITE")
return true;
}
Read(Num, GetBufOnly)
{
Num = Math.trunc(Num)
var Data;
if(isNaN(Num) || Num < 0 || Num > this.GetMaxNum())
{
return undefined;
}
var BufRead = this.GetMap(Num);
if(!BufRead)
{
BufRead = BufLib.GetNewBuffer(this.DataSize)
var Position = Num * this.DataSize;
var FI = this.OpenDBFile(this.FileName);
var bytesRead = fs.readSync(FI.fd, BufRead, 0, BufRead.length, Position);
if(bytesRead !== BufRead.length)
return undefined;
this.SetMap(Num, BufRead)
}
if(GetBufOnly)
{
return BufRead;
}
try
{
Data = BufLib.GetObjectFromBuffer(BufRead, this.Format, this.WorkStruct)
}
catch(e)
{
ToLog("DBROW:" + e)
return undefined;
}
Data.Num = Num
return Data;
}
GetRows(start, count)
{
var arr = [];
for(var num = start; num < start + count; num++)
{
var Data = this.Read(num);
if(!Data)
break;
arr.push(Data)
}
return arr;
}
Truncate(LastNum)
{
var startTime = process.hrtime();
LastNum = Math.trunc(LastNum)
var Position = (LastNum + 1) * this.DataSize;
if(Position < 0)
Position = 0
var FI = this.OpenDBFile(this.FileName, 1);
if(Position < FI.size)
{
this.LastHash = undefined
this.WasUpdate = 1
if(LastNum < 0)
ToLog("Truncate " + this.FileName + " from 0")
FI.size = Position
fs.ftruncateSync(FI.fd, FI.size)
this.BufMap = {}
this.BufMapCount = 0
}
ADD_TO_STAT_TIME("ROWS_WRITE_MS", startTime)
}
DeleteHistory(BlockNumFrom)
{
var MaxNum = this.GetMaxNum();
if(MaxNum === - 1)
return ;
for(var num = MaxNum; num >= 0; num--)
{
var ItemCheck = this.Read(num);
if(!ItemCheck)
break;
if(ItemCheck.BlockNum < BlockNumFrom)
{
if(num < MaxNum)
{
this.Truncate(num)
}
return ;
}
}
this.Truncate( - 1)
}
FastFindBlockNum(BlockNum)
{
var MaxNum = this.GetMaxNum();
if(MaxNum === - 1)
return ;
var StartNum = 0;
var EndNum = MaxNum;
var CurNum = Math.trunc(MaxNum / 2);
while(true)
{
var Item = this.Read(CurNum);
if(Item)
{
if(Item.BlockNum > BlockNum)
{
EndNum = CurNum - 1
var Delta = CurNum - StartNum;
if(Delta === 0)
return "NoHistory";
Delta = Math.trunc((1 + Delta) / 2)
CurNum = CurNum - Delta
}
else
if(Item.BlockNum < BlockNum)
{
StartNum = CurNum + 1
var Delta = EndNum - CurNum;
if(Delta === 0)
return "NoPresent";
Delta = Math.trunc((1 + Delta) / 2)
CurNum = CurNum + Delta
}
else
if(Item.BlockNum === BlockNum)
break;
}
else
{
throw "Error read num";
return ;
}
}
var num = CurNum;
while(true)
{
num--
if(num < 0)
return CurNum;
var Item = this.Read(num);
if(Item)
{
if(Item.BlockNum === BlockNum)
CurNum = num
else
return CurNum;
}
else
{
throw "Error read num";
return ;
}
}
}
SetMap(Num, Value)
{
this.BufMap[Num] = Value
this.BufMapCount++
}
GetMap(Num)
{
return this.BufMap[Num];
}
DeleteMap(Num)
{
if(this.BufMap[Num])
{
delete this.BufMap[Num]
this.BufMapCount--
}
}
CheckBufMap()
{
if(this.BufMapCount > 1000)
{
this.ClearBufMap()
}
}
ClearBufMap()
{
this.BufMap = {}
this.BufMapCount = 0
}
Close()
{
this.ClearBufMap()
this.CloseDBFile(this.FileName)
}
};