📄 database.cpp
字号:
#include "StuffHeaders.hpp"
#include "Database.hpp"
#include <ToolOS.hpp>
//===========================================================================//
// File: Database.cpp //
// Contents: Database functionality //
//---------------------------------------------------------------------------//
// Copyright (C) Microsoft Corporation. All rights reserved. //
//===========================================================================//
//
// A pointer to this structure is the handle to the database
//
class Stuff::Database
{
public:
enum {
e_DataBlockSize=1021,
e_Tag = 'DBV#',
e_Version = 2
};
Database();
DWORD
m_tag, // Magic number to identity file
m_version; // Version number
DWORD
m_numberOfRecords, // Number of used records in database
m_nextRecordID; // Sequential index assigned in ADD
DWORD
m_idOffsets[e_DataBlockSize], // Offsets to DatabaseRecords ( sorted by index )
m_nameOffsets[e_DataBlockSize]; // Offsets to DatabaseRecords ( sorted by HASH )
void
TestInstance() const
{Verify(m_tag == e_Tag && m_version <= e_Version);}
static int
FilesOpened;
};
//
// Each database record has this header
//
class Stuff::Record
{
public:
Record::Record(
const RecordHandle *handle,
DWORD record_hash,
DWORD name_length
);
void
Unhook(const RecordHandle *handle);
__int64
m_lastModified; // Time record was last modifyed
DWORD
m_nextIDRecord, // offset to chain of records that share the same hash
m_nextNameRecord, // offset to chain of records that share the same hash
m_ID, // ID
m_hash, // Hash value
m_nameLength,
m_length; // If this is zero, the record has been deleted (used to signify gaps before compressing)
bool
m_mustFree; // When 1 gos_Free must be called on the block
char
m_name[1];
BYTE
m_data[1];
void
TestInstance() const
{}
};
static HGOSHEAP
Database_Heap = NULL;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
static DWORD
GenerateHash(const char* name)
{
DWORD hash=0;
while (*name)
{
hash=(hash<<4) + (*name&15);
if (hash&0xf0000000)
hash=hash^(hash>>28);
name++;
}
return hash|0x80000000;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
Record::Record(
const RecordHandle *handle,
DWORD record_hash,
DWORD name_length
)
{
Check_Pointer(this);
Check_Object(handle);
DatabaseHandle *db_handle = handle->m_databaseHandle;
Check_Object(db_handle);
Database *db = db_handle->m_dataBase;
Check_Object(db);
//
//------------------
// Set up the record
//------------------
//
m_mustFree = true;
m_ID = handle->m_ID;
m_hash = record_hash;
m_nameLength = name_length;
m_length = handle->m_length;
m_lastModified = gos_GetTimeDate();
memcpy(&m_name[name_length+1], handle->m_data, m_length);
//
//------------------
// Store in database
//------------------
//
DWORD index=m_ID % Database::e_DataBlockSize;
DWORD offset = (DWORD)this - db_handle->m_baseAddress;
m_nextIDRecord = db->m_idOffsets[index];
db->m_idOffsets[index] = offset;
Check_Pointer(handle->m_name);
memcpy(m_name, handle->m_name, name_length+1);
index = record_hash % Database::e_DataBlockSize;
m_nextNameRecord = db->m_nameOffsets[index];
db->m_nameOffsets[index] = offset;
//
//----------------------------
// Increase the database count
//----------------------------
//
db->m_numberOfRecords++;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
Record::Unhook(const RecordHandle *handle)
{
Check_Pointer(this);
Check_Object(handle);
DatabaseHandle *db_handle = handle->m_databaseHandle;
Check_Object(db_handle);
Database *db = db_handle->m_dataBase;
Check_Object(db);
//
//--------------------------------------------
// Make sure that we can find the record by ID
//--------------------------------------------
//
Record* record;
DWORD index = m_ID % Database::e_DataBlockSize;
#ifdef _ARMOR
record = reinterpret_cast<Record*>(db->m_idOffsets[index]);
while (record)
{
record = reinterpret_cast<Record*>((DWORD)record + db_handle->m_baseAddress);
Check_Object(record);
if (record->m_ID == m_ID)
break;
record =
reinterpret_cast<Record*>(record->m_nextIDRecord);
}
Verify(this == record);
#endif
//
//-------------------------------------------
// Now remove the record from the index database
//-------------------------------------------
//
record = reinterpret_cast<Record*>(db->m_idOffsets[index] + db_handle->m_baseAddress);
if (record == this)
db->m_idOffsets[index] = m_nextIDRecord;
else
{
record = reinterpret_cast<Record*>(db->m_idOffsets[index]);
while (record)
{
record = reinterpret_cast<Record*>((DWORD)record + db_handle->m_baseAddress);
Check_Object(record);
if ((DWORD)record->m_nextIDRecord+db_handle->m_baseAddress == (DWORD)this)
{
record->m_nextIDRecord = m_nextIDRecord;
break;
}
record = reinterpret_cast<Record*>(record->m_nextIDRecord);
}
}
//
//---------------------------------
// Now remove from hash index database
//---------------------------------
//
index = m_hash % Database::e_DataBlockSize;
record = reinterpret_cast<Record*>(db->m_nameOffsets[index] + db_handle->m_baseAddress);
if (record == this)
db->m_nameOffsets[index] = m_nextNameRecord;
else
{
record = reinterpret_cast<Record*>(db->m_nameOffsets[index]);
while (record)
{
record = reinterpret_cast<Record*>((DWORD)record + db_handle->m_baseAddress);
Check_Object(record);
if ((DWORD)record->m_nextNameRecord+db_handle->m_baseAddress == (DWORD)this)
{
record->m_nextNameRecord = m_nextNameRecord;
break;
}
record = reinterpret_cast<Record*>(record->m_nextNameRecord);
}
}
db->m_numberOfRecords--;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RecordHandle::Add()
{
Check_Object(this);
gos_PushCurrentHeap(Database_Heap);
//
//------------------
// Find our database
//------------------
//
Check_Object(m_databaseHandle);
Verify(!m_databaseHandle->m_readOnly);
m_databaseHandle->m_dirtyFlag = true;
Database* db = m_databaseHandle->m_dataBase;
Check_Object(db);
//
//-------------------------------------------
// Make sure the record doesn't already exist
//-------------------------------------------
//
Verify(!m_record);
#ifdef _ARMOR
if (m_name)
{
RecordHandle dup_check = *this;
if (dup_check.FindName())
STOP(( "Duplicate Record" ));
}
#endif
//
//------------------
// Set the record index
//------------------
//
m_ID=db->m_nextRecordID++;
//
//---------------------------------------------------
// Figure out how long the name is and its hash value
//---------------------------------------------------
//
DWORD record_hash, name_length;
if (m_name)
{
record_hash = GenerateHash(m_name);
name_length = strlen(m_name);
Verify(name_length > 0);
}
else
{
record_hash = 0;
name_length = 0;
}
//
//------------------
// Set up the record
//------------------
//
Verify(!m_record);
Record *data =
new(new BYTE[sizeof(*m_record) + m_length + name_length])
Record(this, record_hash, name_length);
Check_Object(data);
m_data = &data->m_name[name_length+1];
if (m_name)
m_name = data->m_name;
m_timeStamp = data->m_lastModified;
//
//------------------
// Update statistics
//------------------
//
m_record = data;
gos_PopCurrentHeap();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RecordHandle::Replace()
{
Check_Object(this);
gos_PushCurrentHeap(Database_Heap);
//
//------------------
// Find our database
//------------------
//
Check_Object(m_databaseHandle);
Verify(!m_databaseHandle->m_readOnly);
m_databaseHandle->m_dirtyFlag = true;
//
//----------------------
// Unhook the old record
//----------------------
//
Check_Object(m_record);
const_cast<Record*>(m_record)->Unhook(this);
//
//---------------------------------------------------
// Figure out how long the name is and its hash value
//---------------------------------------------------
//
DWORD record_hash, name_length;
if (m_name)
{
record_hash = GenerateHash(m_name);
name_length = strlen(m_name);
Verify(name_length > 0);
}
else
{
record_hash = 0;
name_length = 0;
}
//
//------------------
// Set up the record
//------------------
//
Record *data =
new(new BYTE[sizeof(*m_record) + m_length + name_length])
Record(this, record_hash, name_length);
Check_Object(data);
m_data = &data->m_name[name_length+1];
if (m_name)
m_name = data->m_name;
m_timeStamp = data->m_lastModified;
//
//------------------
// Update statistics
//------------------
//
if (m_record->m_mustFree)
delete const_cast<Record*>(m_record);
m_record = data;
gos_PopCurrentHeap();
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void
RecordHandle::Delete()
{
Check_Object(this);
//
//------------------
// Find our database
//------------------
//
Check_Object(m_databaseHandle);
Verify(!m_databaseHandle->m_readOnly);
m_databaseHandle->m_dirtyFlag = true;
//
//----------------------
// Delete the old record
//----------------------
//
Check_Object(m_record);
const_cast<Record*>(m_record)->Unhook(this);
if (m_record->m_mustFree)
delete const_cast<Record*>(m_record);
m_record = NULL;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
RecordHandle::FindID()
{
Check_Object(this);
Check_Object(m_databaseHandle);
Database* db = m_databaseHandle->m_dataBase;
Check_Object(db);
DWORD index=m_ID % Database::e_DataBlockSize;
Record* record = reinterpret_cast<Record*>(db->m_idOffsets[index]);
while (record)
{
record =
reinterpret_cast<Record*>(
(DWORD)record + m_databaseHandle->m_baseAddress
);
Check_Object(record);
if (record->m_ID==m_ID)
{
m_length = record->m_length;
m_data = &record->m_data[record->m_nameLength];
m_name = record->m_name;
m_record = record;
m_timeStamp = record->m_lastModified;
return true;
}
record = reinterpret_cast<Record*>(record->m_nextIDRecord);
}
m_record = NULL;
return false;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
bool
RecordHandle::FindName()
{
Check_Object(this);
Check_Object(m_databaseHandle);
Database* db = m_databaseHandle->m_dataBase;
Check_Object(db);
Check_Pointer(m_name);
DWORD hash = GenerateHash(m_name);
DWORD index = hash % Database::e_DataBlockSize;
Record* record = reinterpret_cast<Record*>(db->m_nameOffsets[index]);
while (record)
{
record = reinterpret_cast<Record*>(
(DWORD)record + m_databaseHandle->m_baseAddress
);
Check_Object(record);
if (record->m_hash == hash && !_stricmp(m_name,record->m_name))
{
m_length = record->m_length;
m_data = &record->m_data[record->m_nameLength];
m_ID = record->m_ID;
m_name = record->m_name;
m_record = record;
m_timeStamp = record->m_lastModified;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -