mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-12-26 19:00:53 +00:00
362 lines
8.6 KiB
C++
362 lines
8.6 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// Copyright (C) 2010 Winch Gate Property Limited
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#include "db_delta_file.h"
|
|
|
|
#include <nel/misc/debug.h>
|
|
|
|
using namespace NLMISC;
|
|
using namespace std;
|
|
|
|
/*
|
|
* Constructor
|
|
*/
|
|
CDBDeltaFile::CDBDeltaFile()
|
|
{
|
|
}
|
|
|
|
/*
|
|
* Constructor
|
|
*/
|
|
CDBDeltaFile::~CDBDeltaFile()
|
|
{
|
|
}
|
|
|
|
|
|
/*
|
|
* Setup file name and path
|
|
*/
|
|
void CDBDeltaFile::setup(const std::string& name, const std::string& path, uint32 rowSize, const CTimestamp& startTimestamp, const CTimestamp& endTimestamp)
|
|
{
|
|
uint32 tableId;
|
|
CTimestamp timestamp;
|
|
nlassert(isDeltaFileName(name, tableId, timestamp));
|
|
|
|
_Name = name;
|
|
_Path = NLMISC::CPath::standardizePath(path);
|
|
|
|
_Header.RowSize = rowSize;
|
|
_Header.FullRowSize = rowSize + getRowHeaderSize();
|
|
//_Header.Timestamp = timestamp.toTime();
|
|
_Header.StartTimestamp = uint32(startTimestamp.toTime());
|
|
_Header.EndTimestamp = uint32(endTimestamp.toTime());
|
|
}
|
|
|
|
/*
|
|
* Setup file name and path
|
|
*/
|
|
void CDBDeltaFile::setup(const std::string& filepath, uint32 rowSize, const CTimestamp& startTimestamp, const CTimestamp& endTimestamp)
|
|
{
|
|
setup(CFile::getFilename(filepath), NLMISC::CPath::standardizePath(CFile::getPath(filepath)), rowSize, startTimestamp, endTimestamp);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Write next row modification
|
|
*/
|
|
bool CDBDeltaFile::write(uint32 index, const uint8* rowdata)
|
|
{
|
|
string filepath = _Path+_Name;
|
|
|
|
// check file already open
|
|
if (_File == NULL)
|
|
{
|
|
// not?
|
|
// check file exists
|
|
if (CFile::fileExists(filepath))
|
|
{
|
|
nlwarning("CDBDeltaFile::write(): failed, file '%s' exists yet", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
// open file
|
|
if (!open(filepath.c_str(), "wb"))
|
|
{
|
|
nlwarning("CDBDeltaFile::write(): failed, cannot open file '%s'", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
setInOut(false);
|
|
|
|
// serial header
|
|
try
|
|
{
|
|
if (!serialHeader())
|
|
{
|
|
nlwarning("CDBDeltaFile::write(): failed, cannot write file '%s' header", filepath.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
catch (Exception& e)
|
|
{
|
|
nlwarning("CDBDeltaFile::write(): failed, cannot write file '%s' header, exception '%s'", filepath.c_str(), e.what());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// check row doesn't belong to map yet
|
|
TIndexMap::iterator it = _IndexMap.find(index);
|
|
if (it == _IndexMap.end())
|
|
{
|
|
// seek to end (should be after last row)
|
|
uint32 rowSeek = _DataStart + _Header.FullRowSize*(uint32)_IndexMap.size();
|
|
|
|
// a little check
|
|
if (fseek(_File, 0, SEEK_END) != 0)
|
|
{
|
|
nlwarning("CDBDeltaFile::write(): failed to seek end of file '%s'", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
if (rowSeek != (uint32)ftell(_File))
|
|
{
|
|
nlwarning("CDBDeltaFile::write(): failed to seek end of file, computed seek '%d' different from end of file '%s' position '%d'", rowSeek, filepath.c_str(), ftell(_File));
|
|
return false;
|
|
}
|
|
|
|
_IndexMap[index] = rowSeek;
|
|
|
|
static uint8 rowHdrBuffer[32];
|
|
*(uint32*)rowHdrBuffer = index;
|
|
|
|
// write data
|
|
if (!writeBuffer(rowHdrBuffer, getRowHeaderSize()))
|
|
{
|
|
nlwarning("CDBDeltaFile::write(): failed, can't write index '%d' header in file '%s'", index, filepath.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
uint32 rowSeek = (*it).second;
|
|
|
|
// a little check
|
|
if (fseek(_File, rowSeek+getRowHeaderSize(), SEEK_SET) != 0)
|
|
{
|
|
nlwarning("CDBDeltaFile::write(): failed to seek to index '%d' data of file '%s'", index, filepath.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// write data
|
|
if (!writeBuffer(rowdata, _Header.RowSize))
|
|
{
|
|
nlwarning("CDBDeltaFile::write(): failed, can't write index '%d' data in file '%s'", index, filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*
|
|
* Read next row modification
|
|
*/
|
|
bool CDBDeltaFile::read(uint32& index, uint8* rowdata)
|
|
{
|
|
string filepath = _Path+_Name;
|
|
|
|
if (!preload())
|
|
{
|
|
nlwarning("CDBDeltaFile::read(): failed to preload() file '%s'", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
static uint8 rowHdrBuffer[32];
|
|
|
|
// read data
|
|
uint readLen;
|
|
if (!readBuffer(rowHdrBuffer, getRowHeaderSize(), readLen))
|
|
{
|
|
// failed to read, check if end of file
|
|
if (feof(_File) && readLen == 0)
|
|
{
|
|
index = 0xffffffff;
|
|
return true;
|
|
}
|
|
|
|
nlwarning("CDBDeltaFile::read(): failed, can't read index header in file '%s'", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
index = *(uint32*)rowHdrBuffer;
|
|
|
|
// write data
|
|
if (!readBuffer(rowdata, _Header.RowSize))
|
|
{
|
|
nlwarning("CDBDeltaFile::read(): failed, can't read index '%d' data in file '%s'", index, filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Preload file
|
|
*/
|
|
bool CDBDeltaFile::preload()
|
|
{
|
|
// check file already open
|
|
if (_File != NULL)
|
|
return true;
|
|
|
|
string filepath = _Path+_Name;
|
|
|
|
// not?
|
|
// check file exists
|
|
if (!CFile::fileExists(filepath))
|
|
{
|
|
nlwarning("CDBDeltaFile::read(): failed, file '%s' doesn't exists", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
// open file
|
|
if (!open(filepath.c_str(), "rb"))
|
|
{
|
|
nlwarning("CDBDeltaFile::read(): failed, cannot open file '%s'", filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
setInOut(true);
|
|
|
|
// serial header
|
|
try
|
|
{
|
|
if (!serialHeader())
|
|
{
|
|
nlwarning("CDBDeltaFile::read(): failed, cannot write file '%s' header", filepath.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
catch (Exception& e)
|
|
{
|
|
nlwarning("CDBDeltaFile::read(): failed, cannot write file '%s' header, exception '%s'", filepath.c_str(), e.what());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Serial file header
|
|
*/
|
|
bool CDBDeltaFile::serialHeader()
|
|
{
|
|
serialCheck((uint32)'DbDt');
|
|
uint version = serialVersion(0);
|
|
|
|
if (isReading())
|
|
{
|
|
// on reading, read header in a temp buffer
|
|
CDeltaHeader hdr;
|
|
serial(hdr);
|
|
|
|
// check header complies
|
|
if (_Header.RowSize != 0 && hdr.RowSize != _Header.RowSize)
|
|
return false;
|
|
|
|
// compy temp to header
|
|
_Header = hdr;
|
|
}
|
|
else
|
|
{
|
|
serial(_Header);
|
|
}
|
|
|
|
serialCheck((uint32)'Data');
|
|
|
|
_DataStart = ftell(_File);
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
* Concats a delta file to this one
|
|
*/
|
|
bool CDBDeltaFile::concat(CDBDeltaFile& delta, const CTimestamp& starttime, const CTimestamp& endtime)
|
|
{
|
|
string filepath = _Path+_Name;
|
|
|
|
if (!delta.preload())
|
|
{
|
|
nlwarning("CDBDeltaFile::concat(): failed to concat in file '%s', cannot preload file '%s'", filepath.c_str(), delta._Name.c_str());
|
|
return false;
|
|
}
|
|
|
|
// check file has valid row size
|
|
if (_Header.RowSize == 0)
|
|
{
|
|
setup(_Name, _Path, delta.getRowSize(), starttime, endtime);
|
|
}
|
|
else if (_Header.RowSize != delta.getRowSize())
|
|
{
|
|
nlwarning("CDBDeltaFile::concat(): failed, file '%s' has different row size from '%s'", delta._Name.c_str(), filepath.c_str());
|
|
return false;
|
|
}
|
|
|
|
// check & set header ids
|
|
if (_Header.StartDeltaId == 0 && _Header.EndDeltaId == 0)
|
|
{
|
|
// header ids not yet set
|
|
_Header.StartDeltaId = delta._Header.StartDeltaId;
|
|
_Header.EndDeltaId = delta._Header.EndDeltaId;
|
|
}
|
|
else if (_Header.EndDeltaId == delta._Header.StartDeltaId ||
|
|
_Header.EndDeltaId == delta._Header.StartDeltaId-1)
|
|
{
|
|
// update delta id
|
|
_Header.EndDeltaId = delta._Header.EndDeltaId;
|
|
}
|
|
else
|
|
{
|
|
// failure!
|
|
nlwarning("CDBDeltaFile::concat(): non consecutive delta ids in delta files: file '%s' end=%d, file '%s' start=%d", filepath.c_str(), _Header.EndDeltaId, delta._Path.c_str(), delta._Header.StartDeltaId);
|
|
return false;
|
|
}
|
|
|
|
vector<uint8> databuffer(_Header.RowSize);
|
|
uint8* data = &(databuffer[0]);
|
|
|
|
uint32 row;
|
|
|
|
// read a row, and write it if read row is valid
|
|
// loop till there are rows to read
|
|
while (true)
|
|
{
|
|
if (!delta.read(row, data))
|
|
{
|
|
nlwarning("CDBDeltaFile::concat(): failed to concat to '%s', cannot read next row update in file '%s'", filepath.c_str(), delta._Name.c_str());
|
|
return false;
|
|
}
|
|
|
|
if (row == 0xffffffff)
|
|
break;
|
|
|
|
if (!write(row, data))
|
|
{
|
|
nlwarning("CDBDeltaFile::concat(): failed to write row '%d' update in file '%s'", row, filepath.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|