1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include "db_reference_file.h"
21 #include "pds_table_buffer.h"
23 #include <nel/misc/debug.h>
25 using namespace NLMISC
;
31 CDBReferenceFile::CDBReferenceFile()
39 CDBReferenceFile::~CDBReferenceFile()
48 void CDBReferenceFile::clear()
57 _Header
.BaseIndex
= 0;
59 _Header
.OverIndex
= 0;
61 _Header
.FullRowSize
= 0;
62 _Header
.Timestamp
= 0;
72 void CDBReferenceFile::close()
76 PDS_LOG_DEBUG(1)("CDBReferenceFile::clear(): closing file '%s%s' in %s mode", _Path
.c_str(), _Name
.c_str(), (_Mode
== Read
? "Read" : "Update"));
78 // in update mode, postwrite to validate file
85 CMixedStreamFile::close();
90 * Setup file name and path
92 void CDBReferenceFile::setup(const string
& name
, const string
& path
, uint32 baseIndex
, uint32 overIndex
, uint32 rowSize
)
98 nlassert(isRefFile(name
, tableId
, refFile
));
103 _Header
.BaseIndex
= baseIndex
;
104 _Header
.EndIndex
= baseIndex
;
105 _Header
.OverIndex
= overIndex
;
106 _Header
.RowSize
= rowSize
;
107 _Header
.FullRowSize
= rowSize
+ getRowHeaderSize();
108 _Header
.Timestamp
= CTableBuffer::getCommonStamp(); //CStampHandler::getStamp();
116 * Builds an empty file
118 bool CDBReferenceFile::buildEmptyRef()
120 string filepath
= _Path
+_Name
;
124 nlwarning("CDBReferenceFile::buildEmptyRef(): failed, file '%s' already open", filepath
.c_str());
128 // check file doesn't exist yet
129 if (CFile::fileExists(filepath
))
131 nlwarning("CDBReferenceFile::buildEmptyRef(): failed, file '%s' already exists", filepath
.c_str());
137 nlwarning("CDBReferenceFile::buildEmptyRef(): failed, cannot prewrite file '%s'", filepath
.c_str());
150 * Prewrite reference file.
151 * At least, read file header to known the base and index index in file
153 bool CDBReferenceFile::prewrite(bool failIfNotExist
)
155 // check file already open
159 string filepath
= _Path
+_Name
;
163 if (!CFile::fileExists(filepath
))
167 nlwarning("CDBReferenceFile::prewrite(): failed, file '%s' does not exist", filepath
.c_str());
172 if (!open(filepath
.c_str(), "wb"))
174 nlwarning("CDBReferenceFile::prewrite(): failed, cannot open file '%s' for write", filepath
.c_str());
178 // write header, set to output mode
184 if (!open(filepath
.c_str(), "r+b"))
186 nlwarning("CDBReferenceFile::prewrite(): failed, cannot open file '%s' for read", filepath
.c_str());
190 if (fseek(_File
, 0, SEEK_SET
) != 0)
192 nlwarning("CDBReferenceFile::prewrite(): failed, cannot seek start of '%s' to read header", filepath
.c_str());
196 // read header, set to input mode
205 nlwarning("CDBReferenceFile::prewrite(): failed, cannot read file '%s' header", filepath
.c_str());
209 catch (const Exception
& e
)
211 nlwarning("CDBReferenceFile::prewrite(): failed, cannot read file '%s' header, exception '%s'", filepath
.c_str(), e
.what());
215 // write data, set to output mode
221 PDS_LOG_DEBUG(1)("CDBReferenceFile::prewrite(): opened file '%s' in Update mode", filepath
.c_str());
227 * Postwrite reference file
228 * Mark file as valid, close file, flush anything still alive...
230 bool CDBReferenceFile::postwrite()
235 string filepath
= _Path
+_Name
;
237 if (fseek(_File
, 0, SEEK_SET
) != 0)
239 nlwarning("CDBReferenceFile::postwrite(): failed, cannot seek start of '%s' to read header", filepath
.c_str());
248 nlwarning("CDBReferenceFile::postwrite(): failed, cannot read file '%s' header", filepath
.c_str());
252 catch (const Exception
& e
)
254 nlwarning("CDBReferenceFile::postwrite(): failed, cannot read file '%s' header, exception '%s'", filepath
.c_str(), e
.what());
263 * Update Start/End Delta Ids
265 bool CDBReferenceFile::updateDeltaIds(uint32 startId
, uint32 endId
)
267 if (_Header
.StartDeltaId
== 0 && _Header
.EndDeltaId
== 0)
269 _Header
.StartDeltaId
= startId
;
270 _Header
.EndDeltaId
= endId
;
274 if (_Header
.EndDeltaId
!= startId
&& _Header
.EndDeltaId
!= startId
-1)
276 string filepath
= _Path
+_Name
;
277 nlwarning("CDBReferenceFile::updateDeltaIds(): non consecutive delta ids, file '%s' end=%d, update start=%d", filepath
.c_str(), _Header
.EndDeltaId
, startId
);
281 _Header
.EndDeltaId
= endId
;
287 * Get Start/End Delta Ids
289 void CDBReferenceFile::getUpdateDeltaIds(uint32
& startId
, uint32
& endId
)
291 startId
= _Header
.StartDeltaId
;
292 endId
= _Header
.EndDeltaId
;
297 * Update a row in the reference file
298 * \param index is the absolute row index to update, not relative to file base index
299 * \param data is the data buffer to store in file
301 bool CDBReferenceFile::update(uint32 index
, const uint8
* rowdata
)
303 string filepath
= _Path
+_Name
;
307 nlwarning("CDBReferenceFile::update(): failed, failed to prewrite '%s'", filepath
.c_str());
313 nlwarning("CDBReferenceFile::update(): failed, file '%s' not opened in Update mode", filepath
.c_str());
317 // check row belongs to file (not over OverIndex)
318 if (index
>= _Header
.OverIndex
)
320 nlwarning("CDBReferenceFile::update(): failed, index '%d' is over file '%s' limit '%s'", index
, filepath
.c_str(), _Header
.OverIndex
);
324 // check row is not beyong physical file data
325 if (index
>= _Header
.EndIndex
)
328 // increase file size by filling blank, fill row indices where needed)
331 if (fseek(_File
, getSeekPos(_Header
.EndIndex
), SEEK_SET
) != 0)
333 nlwarning("CDBReferenceFile::update(): failed, can't seek to end in file '%s'", filepath
.c_str());
337 // allocate blank buffer
338 uint8
* tempRowBuffer
= new uint8
[_Header
.FullRowSize
];
339 memset(tempRowBuffer
, 0, _Header
.FullRowSize
);
341 // dump empty rows till we get to end index
342 while (_Header
.EndIndex
<= index
)
345 *(uint32
*)tempRowBuffer
= index
;
346 if (!writeBuffer(tempRowBuffer
, _Header
.FullRowSize
))
348 nlwarning("CDBReferenceFile::update(): failed, can't increase file '%s' size", filepath
.c_str());
349 delete[] tempRowBuffer
;
356 delete[] tempRowBuffer
;
359 // seek to row in file
360 if (fseek(_File
, getSeekPos(index
)+getRowHeaderSize(), SEEK_SET
) != 0)
362 nlwarning("CDBReferenceFile::update(): failed, can't seek to index '%d' data in file '%s'", index
, filepath
.c_str());
367 if (!writeBuffer(rowdata
, _Header
.RowSize
))
369 nlwarning("CDBReferenceFile::update(): failed, can't write index '%d' data in file '%s'", index
, filepath
.c_str());
378 * Preload reference file.
379 * At least, read file header to known the base and index index in file
381 bool CDBReferenceFile::preload()
383 // check file already open
390 string filepath
= _Path
+_Name
;
392 // file doesn't exist, do nothing
393 if (!CFile::fileExists(filepath
))
397 if (!open(filepath
.c_str(), "rb"))
399 nlwarning("CDBReferenceFile::preload(): failed, cannot open file '%s'", filepath
.c_str());
404 PDS_LOG_DEBUG(1)("CDBReferenceFile::preload(): opened file '%s' in Read mode", filepath
.c_str());
413 nlwarning("CDBReferenceFile::preload(): failed, cannot read file '%s' header", filepath
.c_str());
417 catch (const Exception
& e
)
419 nlwarning("CDBReferenceFile::preload(): failed, cannot read file '%s' header, exception '%s'", filepath
.c_str(), e
.what());
427 * Read a row in the reference file
428 * \param index is the absolute row index to read, not relative to file base index
429 * \param data is the data buffer to store data read from file
431 bool CDBReferenceFile::read(uint32 index
, uint8
* rowdata
)
433 string filepath
= _Path
+_Name
;
435 // preload will fail only if file exists and cannot be read
436 // preload returns true when everything ok or file doesn't exist
439 nlwarning("CDBReferenceFile::read(): failed, failed to preload '%s'", filepath
.c_str());
446 nlwarning("CDBReferenceFile::read(): failed, file '%s' not opened in Read mode", filepath
.c_str());
450 // check row belongs to file (not over OverIndex)
451 if (index
>= _Header
.OverIndex
)
453 nlwarning("CDBReferenceFile::read(): failed, index '%d' is over file '%s' end '%d'", index
, filepath
.c_str(), _Header
.OverIndex
);
457 // check file opened or row is not beyond file end
458 if (_File
== NULL
|| index
>= _Header
.EndIndex
)
460 PDS_LOG_DEBUG(1)("CDBReferenceFile::read(): row '%d' is beyond file '%s' end '%d', row is empty", index
, filepath
.c_str(), _Header
.EndIndex
);
461 memset(rowdata
, 0, _Header
.RowSize
);
465 // seek to row in file
466 if (fseek(_File
, getSeekPos(index
)+getRowHeaderSize(), SEEK_SET
) != 0)
468 nlwarning("CDBReferenceFile::read(): failed, can't seek to index '%d' data in file '%s'", index
, filepath
.c_str());
473 if (!readBuffer(rowdata
, _Header
.RowSize
))
475 nlwarning("CDBReferenceFile::read(): failed, can't read index '%d' data in file '%s'", index
, filepath
.c_str());
489 bool CDBReferenceFile::serialHeader()
491 serialCheck(NELID("DbRf"));
492 uint version
= serialVersion(0);
496 // on reading, read header in a temp buffer
500 // check header complies
501 if ((_Header
.BaseIndex
!= 0 && hdr
.BaseIndex
!= _Header
.BaseIndex
) || (isReading() && _Header
.RowSize
!= 0 && hdr
.RowSize
!= _Header
.RowSize
))
504 // compy temp to header
512 serialCheck(NELID("Data"));
514 _DataStart
= ftell(_File
);
518 // get file size to compute real EndIndex
519 uint32 filesize
= CFile::getFileSize(_File
);
521 uint32 numRows
= (filesize
-_DataStart
) / _Header
.FullRowSize
;
522 // check exact number of rows in file...
523 if ((filesize
-_DataStart
) % _Header
.FullRowSize
!= 0)
525 nlwarning("CDBReferenceFile::serialHeader(): failed, file doesn't contain an exact number of rows");
529 // compute exact end index
530 _Header
.EndIndex
= _Header
.BaseIndex
+ numRows
;