Implementation of journaling
This commit is contained in:
		| @@ -23,7 +23,7 @@ HashTable::htNode *HashTable::Retrieve(const char *key) | ||||
| 	return _FindNode(key); | ||||
| } | ||||
|  | ||||
| //Adds an entry into the hash table | ||||
| //Adds an entry into the hash table with current time | ||||
| void HashTable::Store(const char *key, const char *value, bool temporary) | ||||
| { | ||||
| 	time_t stamp = 0; | ||||
| @@ -34,6 +34,22 @@ void HashTable::Store(const char *key, const char *value, bool temporary) | ||||
| 	_Insert(key, value, stamp); | ||||
| } | ||||
|  | ||||
| //Adds an entry into the hash table with preset time | ||||
| void HashTable::Store(const char *key, const char *value, time_t stamp) | ||||
| { | ||||
| 	_Insert(key, value, stamp); | ||||
| } | ||||
|  | ||||
| //Erases a key | ||||
| void HashTable::EraseKey(const char *key) | ||||
| { | ||||
| 	HashTable::htNodeSet *set = _FindNodeSet(key); | ||||
| 	HashTable::htNode *node = _FindNode(key, false); | ||||
|  | ||||
| 	if (set && node) | ||||
| 		_Unlink(set, node); | ||||
| } | ||||
|  | ||||
| //Deletes all keys between the two times. | ||||
| // 0 specifies "match all" | ||||
| //All specifies whether permanent keys (time_t = 0) are erased | ||||
| @@ -106,7 +122,20 @@ void HashTable::Clear() | ||||
|  | ||||
| bool HashTable::KeyExists(const char *key) | ||||
| { | ||||
| 	return _FindNode(key, false); | ||||
| 	return (_FindNode(key, false) != NULL); | ||||
| } | ||||
|  | ||||
| size_t HashTable::UsedHashes() | ||||
| { | ||||
| 	size_t num = 0; | ||||
|  | ||||
| 	for (uint32_t i=0; i<HT_SIZE; i++) | ||||
| 	{ | ||||
| 		if (m_Table[i]) | ||||
| 			num++; | ||||
| 	} | ||||
|  | ||||
| 	return num; | ||||
| } | ||||
|  | ||||
| //////////////////// | ||||
|   | ||||
| @@ -34,15 +34,19 @@ public:		//STRUCTORS | ||||
| public:		//PRE-DEF | ||||
| 	class iterator; | ||||
| 	struct htNode; | ||||
| 	friend class Vault; | ||||
| private:	//PRE-DEF | ||||
| 	struct htNodeSet; | ||||
| public:		//PUBLIC FUNCTIONS | ||||
| 	void Store(const char *key, const char *value, bool temporary=true); | ||||
| 	void Store(const char *key, const char *value, time_t stamp); | ||||
| 	htNode *Retrieve(const char *key); | ||||
| 	iterator Enumerate(); | ||||
| 	size_t Prune(time_t begin, time_t end, bool all=false); | ||||
| 	void Clear(); | ||||
| 	bool KeyExists(const char *key); | ||||
| 	size_t UsedHashes(); | ||||
| 	void EraseKey(const char *key); | ||||
| public:		//PUBLIC CLASSES | ||||
| 	class iterator | ||||
| 	{ | ||||
|   | ||||
							
								
								
									
										328
									
								
								dlls/nvault/journal.cpp
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										328
									
								
								dlls/nvault/journal.cpp
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,328 @@ | ||||
| #include <stdlib.h> | ||||
| #include "journal.h" | ||||
| #include "sdk/CVector.h" | ||||
|  | ||||
| struct j_info | ||||
| { | ||||
| 	int id; | ||||
| 	Vault *vault; | ||||
| }; | ||||
|  | ||||
| Journal::Journal(const char *file) | ||||
| { | ||||
| 	m_File.assign(file); | ||||
| 	m_Fp = NULL; | ||||
| 	m_LastId = 0; | ||||
| } | ||||
|  | ||||
| #define rd(v,s) if (fread(&v, sizeof(s), 1, m_Fp) != 1) { \ | ||||
| 	fclose(m_Fp); \ | ||||
| 	m_Fp = NULL; \ | ||||
| 	goto _error; } | ||||
| #define rds(v,l) if (fread(v, sizeof(char), l, m_Fp) != l) { \ | ||||
| 	fclose(m_Fp); \ | ||||
| 	m_Fp = NULL; \ | ||||
| 	goto _error; } else { \ | ||||
| 	v[l] = '\0'; } | ||||
|  | ||||
| bool Journal::Replay(size_t &files, size_t &ops) | ||||
| { | ||||
| 	m_Fp = fopen(m_File.c_str(), "rb"); | ||||
|  | ||||
| 	files = 0; | ||||
| 	ops = 0; | ||||
|  | ||||
| 	if (!m_Fp) | ||||
| 		return false; | ||||
|  | ||||
| 	//this must come before the first jump... | ||||
| 	CVector<j_info *> table; | ||||
| 	uint32_t magic; | ||||
|  | ||||
| 	rd(magic, uint32_t); | ||||
| 	if (magic != JOURNAL_MAGIC) | ||||
| 		return false; | ||||
|  | ||||
| 	j_info *j; | ||||
| 	uint8_t op, klen; | ||||
| 	uint16_t vlen; | ||||
| 	uint32_t id; | ||||
| 	size_t i; | ||||
| 	char *key=NULL, *val=NULL; | ||||
| 	while (!feof(m_Fp)) | ||||
| 	{ | ||||
| 		if (fread(&op, sizeof(uint8_t), 1, m_Fp) != 1) | ||||
| 		{ | ||||
| 			if (feof(m_Fp)) | ||||
| 				break; | ||||
| 			else | ||||
| 				goto _error; | ||||
| 		} | ||||
| 		switch (op) | ||||
| 		{ | ||||
| 		case Journal_Nop: | ||||
| 			{ | ||||
| 				break; | ||||
| 			} | ||||
| 		case Journal_Name: | ||||
| 			{ | ||||
| 				rd(id, uint32_t); | ||||
| 				rd(klen, uint8_t); | ||||
| 				key = new char[klen+1]; | ||||
| 				rds(key, klen); | ||||
| 				j = new j_info; | ||||
| 				j->id = id; | ||||
| 				j->vault = new Vault(key); | ||||
| 				j->vault->ReadFromFile(); | ||||
| 				table.push_back(j); | ||||
| 				files++; | ||||
| 				delete [] key; | ||||
| 				key = NULL; | ||||
| 				break; | ||||
| 			} | ||||
| 		case Journal_Store: | ||||
| 			{ | ||||
| 				//Stores key/val (id,time,klen,vlen,[],[]) | ||||
| 				uint32_t stamp; | ||||
| 				rd(id, uint32_t); | ||||
| 				rd(stamp, uint32_t); | ||||
| 				rd(klen, uint8_t); | ||||
| 				rd(vlen, uint16_t); | ||||
| 				key = new char[klen+1]; | ||||
| 				val = new char[vlen+1]; | ||||
| 				rds(key, klen); | ||||
| 				rds(val, vlen); | ||||
| 				for (i=0; i<table.size(); i++) | ||||
| 				{ | ||||
| 					if (table.at(i)->id == id) | ||||
| 					{ | ||||
| 						table.at(i)->vault->Store(key, val, (time_t)stamp); | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				delete [] key; | ||||
| 				delete [] val; | ||||
| 				key = NULL; | ||||
| 				val = NULL; | ||||
| 				break; | ||||
| 			} | ||||
| 		case Journal_Erase: | ||||
| 			{ | ||||
| 				//Erases key (id,klen,[]) | ||||
| 				rd(id, uint32_t); | ||||
| 				rd(klen, uint8_t); | ||||
| 				key = new char[klen+1]; | ||||
| 				rds(key, klen); | ||||
| 				for (i=0; i<table.size(); i++) | ||||
| 				{ | ||||
| 					if (table.at(i)->id == id) | ||||
| 					{ | ||||
| 						table.at(i)->vault->EraseKey(key); | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				delete [] key; | ||||
| 				key = NULL; | ||||
| 				break; | ||||
| 			} | ||||
| 		case Journal_Clear: | ||||
| 			{ | ||||
| 				//Clears (id) | ||||
| 				rd(id, uint32_t); | ||||
| 				for (i=0; i<table.size(); i++) | ||||
| 				{ | ||||
| 					if (table.at(i)->id == id) | ||||
| 					{ | ||||
| 						table.at(i)->vault->Clear(); | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 		case Journal_Prune: | ||||
| 			{ | ||||
| 				//Prunes (id,t1,t2,all) | ||||
| 				rd(id, uint32_t); | ||||
| 				uint32_t begin, end; | ||||
| 				uint8_t all; | ||||
| 				rd(begin, uint32_t); | ||||
| 				rd(end, uint32_t); | ||||
| 				rd(all, uint8_t); | ||||
| 				for (i=0; i<table.size(); i++) | ||||
| 				{ | ||||
| 					if (table.at(i)->id == id) | ||||
| 					{ | ||||
| 						table.at(i)->vault->Prune((time_t)begin, (time_t)end, all?true:false); | ||||
| 						break; | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 		default: | ||||
| 			{ | ||||
| 				goto _error; | ||||
| 			} | ||||
| 		} //end while | ||||
| 		ops++; | ||||
| 	} | ||||
|  | ||||
| 	for (uint32_t i=0; i<table.size(); i++) | ||||
| 	{ | ||||
| 		j = table.at(i); | ||||
| 		j->vault->WriteToFile(); | ||||
| 		delete j->vault; | ||||
| 		delete j; | ||||
| 	} | ||||
|      | ||||
| 	fclose(m_Fp); | ||||
|  | ||||
| 	return true; | ||||
| _error: | ||||
| 	for (uint32_t i=0; i<table.size(); i++) | ||||
| 	{ | ||||
| 		j = table.at(i); | ||||
| 		j->vault->WriteToFile(); | ||||
| 		delete j->vault; | ||||
| 		delete j; | ||||
| 	} | ||||
| 	if (key) | ||||
| 	{ | ||||
| 		delete [] key; | ||||
| 		key = NULL; | ||||
| 	} | ||||
| 	if (val) | ||||
| 	{ | ||||
| 		delete [] val; | ||||
| 		val = NULL; | ||||
| 	} | ||||
| 	return false; | ||||
| } | ||||
|  | ||||
| void Journal::ClearJournal() | ||||
| { | ||||
| 	m_Fp = fopen(m_File.c_str(), "wb"); | ||||
|  | ||||
| 	if (m_Fp) | ||||
| 	{ | ||||
| 		fclose(m_Fp); | ||||
| 		m_Fp = NULL; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| bool Journal::StartJournal() | ||||
| { | ||||
| 	m_Fp = fopen(m_File.c_str(), "wb"); | ||||
|  | ||||
| 	if (!m_Fp) | ||||
| 		return false; | ||||
|  | ||||
| 	uint32_t magic = JOURNAL_MAGIC; | ||||
|  | ||||
| 	fwrite(&magic, sizeof(uint32_t), 1, m_Fp); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void Journal::EndJournal() | ||||
| { | ||||
| 	if (m_Fp) | ||||
| 	{ | ||||
| 		fclose(m_Fp); | ||||
| 		m_Fp = NULL; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| //Stores key/val (id,time,klen,vlen,[],[] | ||||
| void Journal::Store(const char *name, const char *key, const char *val, time_t stamp) | ||||
| { | ||||
| 	uint32_t time32 = (uint32_t)stamp; | ||||
| 	uint16_t vlen = (uint16_t)strlen(val); | ||||
| 	uint8_t klen = (uint8_t)strlen(key); | ||||
|  | ||||
| 	BeginOp(name, Journal_Store); | ||||
| 		WriteInt(time32); | ||||
| 		WriteByte(klen); | ||||
| 		WriteShort(vlen); | ||||
| 		WriteString(key); | ||||
| 		WriteString(val); | ||||
| 	EndOp(); | ||||
| } | ||||
|  | ||||
| //Erases key (id,klen,[]) | ||||
| void Journal::Erase(const char *name, const char *key) | ||||
| { | ||||
| 	uint8_t klen = (uint8_t)strlen(key); | ||||
|  | ||||
| 	BeginOp(name, Journal_Erase); | ||||
| 		WriteByte(klen); | ||||
| 		WriteString(key); | ||||
| 	EndOp(); | ||||
| } | ||||
|  | ||||
| //Clears (id) | ||||
| void Journal::Clear(const char *name) | ||||
| { | ||||
| 	BeginOp(name, Journal_Clear); | ||||
| 	EndOp(); | ||||
| } | ||||
|  | ||||
| //Prunes (id,t1,t2,all) | ||||
| void Journal::Prune(const char *name, time_t begin, time_t end, bool all) | ||||
| { | ||||
| 	uint32_t begin32 = (uint32_t)begin; | ||||
| 	uint32_t end32 = (uint32_t)end; | ||||
| 	uint8_t all8 = (uint8_t)all; | ||||
|  | ||||
| 	BeginOp(name, Journal_Prune); | ||||
| 		WriteInt(begin32); | ||||
| 		WriteInt(end32); | ||||
| 		WriteByte(all8); | ||||
| 	EndOp(); | ||||
| } | ||||
|  | ||||
| void Journal::BeginOp(const char *name, JournalOp jop) | ||||
| { | ||||
| 	uint32_t id; | ||||
|  | ||||
| 	if (!m_Names.KeyExists(name)) | ||||
| 	{ | ||||
| 		char name_buf[12]; | ||||
| 		id = ++m_LastId; | ||||
| 		sprintf(name_buf, "%d", id); | ||||
| 		m_Names.Store(name, name_buf, false); | ||||
| 		WriteByte(Journal_Name); | ||||
| 		WriteInt(id); | ||||
| 		WriteByte(strlen(name)); | ||||
| 		WriteString(name); | ||||
| 	} else { | ||||
| 		id = atoi(m_Names.Retrieve(name)->val.c_str()); | ||||
| 	} | ||||
|  | ||||
| 	WriteByte(jop); | ||||
| 	WriteInt(id); | ||||
| } | ||||
|  | ||||
| void Journal::WriteByte(uint8_t num) | ||||
| { | ||||
| 	fwrite(&num, sizeof(uint8_t), 1, m_Fp); | ||||
| } | ||||
|  | ||||
| void Journal::WriteShort(uint16_t num) | ||||
| { | ||||
| 	fwrite(&num, sizeof(uint16_t), 1, m_Fp); | ||||
| } | ||||
|  | ||||
| void Journal::WriteInt(uint32_t num) | ||||
| { | ||||
| 	fwrite(&num, sizeof(uint32_t), 1, m_Fp); | ||||
| } | ||||
|  | ||||
| void Journal::WriteString(const char *str) | ||||
| { | ||||
| 	fwrite(str, sizeof(char), strlen(str), m_Fp); | ||||
| } | ||||
|  | ||||
| size_t Journal::EndOp() | ||||
| { | ||||
| 	return 1; | ||||
| } | ||||
							
								
								
									
										46
									
								
								dlls/nvault/journal.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										46
									
								
								dlls/nvault/journal.h
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| #ifndef _INCLUDE_JOURNAL_H | ||||
| #define _INCLUDE_JOURNAL_H | ||||
|  | ||||
| #include "nvault.h" | ||||
|  | ||||
| #define JOURNAL_MAGIC	0x6E564A4C | ||||
|  | ||||
| class Journal | ||||
| { | ||||
| public: | ||||
| 	enum JournalOp | ||||
| 	{ | ||||
| 		Journal_Nop,		//Nothing | ||||
| 		Journal_Name,		//Maps name to Id (id,len,[]) | ||||
| 		Journal_Store,		//Stores key/val (id,time,klen,vlen,[],[]) | ||||
| 		Journal_Erase,		//Erases key (id,klen,[]) | ||||
| 		Journal_Clear,		//Clears (id) | ||||
| 		Journal_Prune		//Prunes (id,t1,t2,all) | ||||
| 	}; | ||||
| public: | ||||
| 	Journal(const char *file); | ||||
| public: | ||||
| 	bool Replay(size_t &files, size_t &ops); | ||||
| 	void ClearJournal(); | ||||
| 	bool StartJournal(); | ||||
| 	void EndJournal(); | ||||
| public: | ||||
| 	void Store(const char *name, const char *key, const char *val, time_t stamp); | ||||
| 	void Erase(const char *name, const char *key); | ||||
| 	void Clear(const char *name); | ||||
| 	void Prune(const char  *name, time_t begin, time_t end, bool all); | ||||
| private: | ||||
| 	void BeginOp(const char *name, JournalOp jop); | ||||
| 	void WriteByte(uint8_t num); | ||||
| 	void WriteShort(uint16_t num); | ||||
| 	void WriteInt(uint32_t num); | ||||
| 	void WriteString(const char *str); | ||||
| 	size_t EndOp(); | ||||
| private: | ||||
| 	String m_File; | ||||
| 	FILE *m_Fp; | ||||
| 	HashTable m_Names; | ||||
| 	uint32_t m_LastId; | ||||
| }; | ||||
|  | ||||
| #endif //_INCLUDE_JOURNAL_H | ||||
| @@ -1,2 +1,206 @@ | ||||
| #include "nvault.h" | ||||
|  | ||||
| Vault::Vault(const char *name) | ||||
| { | ||||
| 	m_File.assign(name); | ||||
| 	m_Vault = NULL; | ||||
| } | ||||
|  | ||||
| Vault::~Vault() | ||||
| { | ||||
| 	if (m_Vault) | ||||
| 	{ | ||||
| 		delete m_Vault; | ||||
| 		m_Vault = NULL; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void Vault::Clear() | ||||
| { | ||||
| 	if (m_Vault) | ||||
| 		m_Vault->Clear(); | ||||
| } | ||||
|  | ||||
| void Vault::EraseKey(const char *key) | ||||
| { | ||||
| 	if (m_Vault) | ||||
| 		m_Vault->EraseKey(key); | ||||
| } | ||||
|  | ||||
| HashTable::htNode *Vault::Find(const char *key) | ||||
| { | ||||
| 	if (m_Vault) | ||||
| 		return m_Vault->Retrieve(key); | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| bool Vault::KeyExists(const char *key) | ||||
| { | ||||
| 	if (m_Vault) | ||||
| 		return m_Vault->KeyExists(key); | ||||
|  | ||||
| 	return NULL; | ||||
| } | ||||
|  | ||||
| size_t Vault::Prune(time_t begin, time_t end, bool all) | ||||
| { | ||||
| 	if (m_Vault) | ||||
| 		return m_Vault->Prune(begin, end, all); | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void Vault::Store(const char *key, const char *value, bool temporary) | ||||
| { | ||||
| 	if (m_Vault) | ||||
| 		m_Vault->Store(key, value, temporary); | ||||
| } | ||||
|  | ||||
| void Vault::Store(const char *key, const char *value, time_t stamp) | ||||
| { | ||||
| 	if (m_Vault) | ||||
| 		m_Vault->Store(key, value, stamp); | ||||
| } | ||||
|  | ||||
| #define wr(v,s) fwrite(&v, sizeof(s), 1, fp) | ||||
|  | ||||
| bool Vault::WriteToFile() | ||||
| { | ||||
| 	FILE *fp = fopen(m_File.c_str(), "wb"); | ||||
|  | ||||
| 	if (!fp) | ||||
| 		return false; | ||||
|  | ||||
| 	uint32_t hashes = m_Vault->UsedHashes(); | ||||
|  | ||||
| 	_WriteHeaders(fp, hashes); | ||||
|  | ||||
| 	HashTable::htNode *node; | ||||
| 	uint32_t keys, stamp; | ||||
| 	uint16_t vChars; | ||||
| 	uint8_t kChars; | ||||
| 	for (uint32_t i=0; i<HT_SIZE; i++) | ||||
| 	{ | ||||
| 		if (m_Vault->m_Table[i]) | ||||
| 		{ | ||||
| 			keys = 0; | ||||
| 			node = m_Vault->m_Table[i]->head;; | ||||
| 			while (node != NULL) | ||||
| 			{ | ||||
| 				keys++; | ||||
| 				node = node->next; | ||||
| 			} | ||||
| 			wr(i, uint32_t); | ||||
| 			wr(keys, uint32_t); | ||||
| 			node = m_Vault->m_Table[i]->head; | ||||
| 			while (node != NULL) | ||||
| 			{ | ||||
| 				stamp = (uint32_t)(node->stamp); | ||||
| 				wr(stamp, uint32_t); | ||||
| 				kChars = (uint8_t)(node->key.size()); | ||||
| 				vChars = (uint16_t)(node->val.size()); | ||||
| 				wr(kChars, uint8_t); | ||||
| 				wr(vChars, uint16_t); | ||||
| 				fwrite(node->key.c_str(), sizeof(char), kChars, fp); | ||||
| 				fwrite(node->val.c_str(), sizeof(char), vChars, fp); | ||||
| 				node = node->next; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	fclose(fp); | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| #define rd(v,s) if (fread(&v, sizeof(s), 1, fp) != 1) { \ | ||||
| 	fclose(fp); \ | ||||
| 	return Vault_ReadFail; } | ||||
|  | ||||
| Vault::VaultError Vault::ReadFromFile() | ||||
| { | ||||
| 	FILE *fp = fopen(m_File.c_str(), "rb"); | ||||
|  | ||||
| 	if (!fp) | ||||
| 	{ | ||||
| 		fp = fopen(m_File.c_str(), "wb"); | ||||
| 		if (!fp) | ||||
| 			return Vault_ReadFail; | ||||
| 		_WriteHeaders(fp, 0); | ||||
| 		fclose(fp); | ||||
| 		m_Vault = new HashTable(); | ||||
| 		return Vault_Ok; | ||||
| 	} | ||||
|  | ||||
| 	uint32_t magic, keysize, hashes; | ||||
| 	uint8_t timesize; | ||||
|  | ||||
| 	rd(magic, uint32_t); | ||||
| 	if (magic != VAULT_MAGIC) | ||||
| 	{ | ||||
| 		fclose(fp); | ||||
| 		return Vault_BadMagic; | ||||
| 	} | ||||
| 	rd(timesize, uint8_t); | ||||
| 	rd(keysize, uint32_t); | ||||
| 	rd(hashes, uint32_t); | ||||
| 	 | ||||
| 	m_Vault = new HashTable(); | ||||
|  | ||||
| 	uint32_t hash, keys, stamp; | ||||
| 	uint16_t vChars; | ||||
| 	uint8_t kChars; | ||||
| 	char *key, *value; | ||||
| 	for (uint32_t i=0; i<hashes; i++) | ||||
| 	{ | ||||
| 		rd(hash, uint32_t); | ||||
| 		rd(keys, uint32_t); | ||||
| 		for (uint32_t d=0; d<keys; d++) | ||||
| 		{ | ||||
| 			rd(stamp, uint32_t); | ||||
| 			rd(kChars, uint8_t); | ||||
| 			rd(vChars, uint16_t); | ||||
| 			key = new char[kChars+1]; | ||||
| 			if (fread(key, sizeof(char), kChars, fp) != kChars) | ||||
| 			{ | ||||
| 				delete [] key; | ||||
| 				fclose(fp); | ||||
| 				return Vault_ReadFail; | ||||
| 			} | ||||
| 			value = new char[vChars+1]; | ||||
| 			if (fread(value, sizeof(char), vChars, fp) != vChars) | ||||
| 			{ | ||||
| 				delete [] key; | ||||
| 				delete [] value; | ||||
| 				return Vault_ReadFail; | ||||
| 			} | ||||
| 			key[kChars] = '\0'; | ||||
| 			value[vChars] = '\0'; | ||||
| 			m_Vault->Store(key, value, (time_t)stamp); | ||||
| 			delete [] key; | ||||
| 			delete [] value; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	fclose(fp); | ||||
|  | ||||
| 	return Vault_Ok; | ||||
| } | ||||
|  | ||||
| /////////////////// | ||||
| // Private stuff // | ||||
| /////////////////// | ||||
|  | ||||
| void Vault::_WriteHeaders(FILE *fp, uint32_t keys) | ||||
| { | ||||
| 	uint32_t magic = VAULT_MAGIC; | ||||
| 	uint32_t keysize = (1<<11); | ||||
| 	uint8_t timesize = sizeof(time_t); | ||||
|  | ||||
| 	fwrite(&magic, sizeof(uint32_t), 1, fp); | ||||
| 	fwrite(×ize, sizeof(uint8_t), 1, fp); | ||||
| 	fwrite(&keysize, sizeof(uint32_t), 1, fp); | ||||
| 	fwrite(&keys, sizeof(uint32_t), 1, fp); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -4,47 +4,50 @@ | ||||
| #include "sdk/CString.h" | ||||
| #include "hash.h" | ||||
|  | ||||
| class Journal | ||||
| /** | ||||
|  * Vault file format: | ||||
|  *  Headers | ||||
|  *   uint32_t - nVLT | ||||
|  *   uint8_t  - sizeof(time_t) | ||||
|  *   uint32_t - key size (will be used in future maybe) | ||||
|  *   uint32_t - number of hashes stored | ||||
|  *  Data | ||||
|  *   uint32_t - key hash | ||||
|  *   uint32_t - # of keys in this hash | ||||
|  *   Data | ||||
|  *    uint32_t - Time | ||||
|  *    uint8_t  - Characters in key | ||||
|  *    uint16_t - Characters in value | ||||
|  *    char[]   - Key | ||||
|  *    char[]   - Value | ||||
|  */ | ||||
|  | ||||
| #define VAULT_MAGIC		0x6E564C54 | ||||
|  | ||||
| class Vault | ||||
| { | ||||
| public: | ||||
| 	enum JournalOp | ||||
| 	Vault(const char *name); | ||||
| 	~Vault(); | ||||
| 	enum VaultError | ||||
| 	{ | ||||
| 		Journal_Store, | ||||
| 		Journal_Erase, | ||||
| 		Journal_Clear, | ||||
| 		Journal_Prune | ||||
| 		Vault_Ok=0, | ||||
| 		Vault_ReadFail, | ||||
| 		Vault_BadMagic, | ||||
| 	}; | ||||
| public: | ||||
| 	Journal(const char *file); | ||||
| public: | ||||
| 	bool Replay(size_t &files, size_t &ops); | ||||
| 	void Clear(); | ||||
| public: | ||||
| 	void Begin(const char *name, JournalOp jop); | ||||
| 	void WriteByte(uint8_t num); | ||||
| 	void WriteInt(uint32_t num); | ||||
| 	void WriteTime(time_t n); | ||||
| 	void WriteString(const char *str); | ||||
| 	size_t End(); | ||||
| private: | ||||
| 	String m_File; | ||||
| 	FILE *m_Fp; | ||||
| 	size_t m_WriteSize; | ||||
| }; | ||||
|  | ||||
| class nVault | ||||
| { | ||||
| public: | ||||
| 	nVault(const char *name); | ||||
| public: | ||||
| 	bool WriteToFile(); | ||||
| 	bool ReadFromFile(); | ||||
| 	VaultError ReadFromFile(); | ||||
| public: | ||||
| 	void Store(const char *key, const char *value, bool temporary=true); | ||||
| 	void Store(const char *key, const char *value, time_t stamp); | ||||
| 	size_t Prune(time_t begin, time_t end, bool all=false); | ||||
| 	HashTable::htNode *Find(const char *key); | ||||
| 	bool KeyExists(const char *key); | ||||
| 	void Clear(); | ||||
| 	void EraseKey(const char *key); | ||||
| private: | ||||
| 	void _WriteHeaders(FILE *fp, uint32_t hashes); | ||||
| private: | ||||
| 	String m_File; | ||||
| 	HashTable *m_Vault; | ||||
|   | ||||
| @@ -23,7 +23,7 @@ | ||||
| 				MinimalRebuild="TRUE" | ||||
| 				BasicRuntimeChecks="3" | ||||
| 				RuntimeLibrary="1" | ||||
| 				UsePrecompiledHeader="3" | ||||
| 				UsePrecompiledHeader="0" | ||||
| 				WarningLevel="3" | ||||
| 				Detect64BitPortabilityProblems="TRUE" | ||||
| 				DebugInformationFormat="4"/> | ||||
| @@ -117,9 +117,24 @@ | ||||
| 			UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"> | ||||
| 			<File | ||||
| 				RelativePath=".\hash.cpp"> | ||||
| 				<FileConfiguration | ||||
| 					Name="Debug|Win32"> | ||||
| 					<Tool | ||||
| 						Name="VCCLCompilerTool" | ||||
| 						UsePrecompiledHeader="0"/> | ||||
| 				</FileConfiguration> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath=".\journal.cpp"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath=".\nvault.cpp"> | ||||
| 				<FileConfiguration | ||||
| 					Name="Debug|Win32"> | ||||
| 					<Tool | ||||
| 						Name="VCCLCompilerTool" | ||||
| 						Detect64BitPortabilityProblems="FALSE"/> | ||||
| 				</FileConfiguration> | ||||
| 			</File> | ||||
| 		</Filter> | ||||
| 		<Filter | ||||
| @@ -129,6 +144,9 @@ | ||||
| 			<File | ||||
| 				RelativePath=".\hash.h"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath=".\journal.h"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath=".\nvault.h"> | ||||
| 			</File> | ||||
|   | ||||
							
								
								
									
										444
									
								
								dlls/nvault/sdk/CVector.h
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										444
									
								
								dlls/nvault/sdk/CVector.h
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,444 @@ | ||||
| /* AMX Mod X | ||||
| * | ||||
| * by the AMX Mod X Development Team | ||||
| *  originally developed by OLO | ||||
| * | ||||
| * | ||||
| *  This program is free software; you can redistribute it and/or modify it | ||||
| *  under the terms of the GNU General Public License as published by the | ||||
| *  Free Software Foundation; either version 2 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 | ||||
| *  General Public License for more details. | ||||
| * | ||||
| *  You should have received a copy of the GNU General Public License | ||||
| *  along with this program; if not, write to the Free Software Foundation, | ||||
| *  Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
| * | ||||
| *  In addition, as a special exception, the author gives permission to | ||||
| *  link the code of this program with the Half-Life Game Engine ("HL | ||||
| *  Engine") and Modified Game Libraries ("MODs") developed by Valve, | ||||
| *  L.L.C ("Valve"). You must obey the GNU General Public License in all | ||||
| *  respects for all of the code used other than the HL Engine and MODs | ||||
| *  from Valve. If you modify this file, you may extend this exception | ||||
| *  to your version of the file, but you are not obligated to do so. If | ||||
| *  you do not wish to do so, delete this exception statement from your | ||||
| *  version. | ||||
| */ | ||||
|  | ||||
| #ifndef __CVECTOR_H__ | ||||
| #define __CVECTOR_H__ | ||||
|  | ||||
| #include <assert.h> | ||||
|  | ||||
| // Vector | ||||
| template <class T> class CVector | ||||
| { | ||||
| 	bool Grow() | ||||
| 	{ | ||||
| 		// automatic grow | ||||
| 		size_t newSize = m_Size * 2; | ||||
| 		if (newSize == 0) | ||||
| 			newSize = 8;					// a good init value | ||||
| 		T *newData = new T[newSize]; | ||||
| 		if (!newData) | ||||
| 			return false; | ||||
| 		if (m_Data) | ||||
| 		{ | ||||
| 			memcpy(newData, m_Data, m_Size * sizeof(T)); | ||||
| 			delete [] m_Data; | ||||
| 		} | ||||
| 		m_Data = newData; | ||||
| 		m_Size = newSize; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	bool GrowIfNeeded() | ||||
| 	{ | ||||
| 		if (m_CurrentUsedSize >= m_Size) | ||||
| 			return Grow(); | ||||
| 		else | ||||
| 			return true; | ||||
| 	} | ||||
|  | ||||
| 	bool ChangeSize(size_t size) | ||||
| 	{ | ||||
| 		// change size | ||||
| 		if (size == m_Size) | ||||
| 			return true; | ||||
| 		T *newData = new T[size]; | ||||
| 		if (!newData) | ||||
| 			return false; | ||||
| 		if (m_Data) | ||||
| 		{ | ||||
| 			memcpy(newData, m_Data, (m_Size < size) ? (m_Size * sizeof(T)) : (size * sizeof(T))); | ||||
| 			delete [] m_Data; | ||||
| 		} | ||||
| 		if (m_Size < size) | ||||
| 			m_CurrentSize = size; | ||||
| 		m_Data = newData; | ||||
| 		m_Size = size; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	void FreeMemIfPossible() | ||||
| 	{ | ||||
|  | ||||
| 	} | ||||
| protected: | ||||
| 	T *m_Data; | ||||
| 	size_t m_Size; | ||||
| 	size_t m_CurrentUsedSize; | ||||
| 	size_t m_CurrentSize; | ||||
| public: | ||||
| 	class iterator | ||||
| 	{ | ||||
| 	protected: | ||||
| 		T *m_Ptr; | ||||
| 	public: | ||||
| 		// constructors / destructors | ||||
| 		iterator() | ||||
| 		{ | ||||
| 			m_Ptr = NULL; | ||||
| 		} | ||||
|  | ||||
| 		iterator(T * ptr) | ||||
| 		{ | ||||
| 			m_Ptr = ptr; | ||||
| 		} | ||||
|  | ||||
| 		// member functions | ||||
| 		T * base() | ||||
| 		{ | ||||
| 			return m_Ptr; | ||||
| 		} | ||||
|  | ||||
| 		const T * base() const | ||||
| 		{ | ||||
| 			return m_Ptr; | ||||
| 		} | ||||
|  | ||||
| 		// operators | ||||
| 		T & operator*() | ||||
| 		{ | ||||
| 			return *m_Ptr; | ||||
| 		} | ||||
|  | ||||
| 		T * operator->() | ||||
| 		{ | ||||
| 			return m_Ptr; | ||||
| 		} | ||||
|  | ||||
| 		iterator & operator++()		// preincrement | ||||
| 		{ | ||||
| 			++m_Ptr; | ||||
| 			return (*this); | ||||
| 		} | ||||
|  | ||||
| 		iterator operator++(int)	// postincrement | ||||
| 		{ | ||||
| 			iterator tmp = *this; | ||||
| 			++m_Ptr; | ||||
| 			return tmp; | ||||
| 		} | ||||
|  | ||||
| 		iterator & operator--()		// predecrement | ||||
| 		{ | ||||
| 			--m_Ptr; | ||||
| 			return (*this); | ||||
| 		} | ||||
|  | ||||
| 		iterator operator--(int)	// postdecrememnt | ||||
| 		{ | ||||
| 			iterator tmp = *this; | ||||
| 			--m_Ptr; | ||||
| 			return tmp; | ||||
| 		} | ||||
|  | ||||
| 		bool operator==(T * right) const | ||||
| 		{ | ||||
| 			return (m_Ptr == right); | ||||
| 		} | ||||
|  | ||||
| 		bool operator==(const iterator & right) const | ||||
| 		{ | ||||
| 			return (m_Ptr == right.m_Ptr); | ||||
| 		} | ||||
|  | ||||
| 		bool operator!=(T * right) const | ||||
| 		{ | ||||
| 			return (m_Ptr != right); | ||||
| 		} | ||||
|  | ||||
| 		bool operator!=(const iterator & right) const | ||||
| 		{ | ||||
| 			return (m_Ptr != right.m_Ptr); | ||||
| 		} | ||||
|  | ||||
| 		iterator & operator+=(size_t offset) | ||||
| 		{ | ||||
| 			m_Ptr += offset; | ||||
| 			return (*this); | ||||
| 		} | ||||
|  | ||||
| 		iterator & operator-=(size_t offset) | ||||
| 		{ | ||||
| 			m_Ptr += offset; | ||||
| 			return (*this); | ||||
| 		} | ||||
|  | ||||
| 		iterator operator+(size_t offset) const | ||||
| 		{ | ||||
| 			iterator tmp(*this); | ||||
| 			tmp.m_Ptr += offset; | ||||
| 			return tmp; | ||||
| 		} | ||||
|  | ||||
| 		iterator operator-(size_t offset) const | ||||
| 		{ | ||||
| 			iterator tmp(*this); | ||||
| 			tmp.m_Ptr += offset; | ||||
| 			return tmp; | ||||
| 		} | ||||
| 		 | ||||
| 		T & operator[](size_t offset) | ||||
| 		{ | ||||
| 			return (*(*this + offset)); | ||||
| 		} | ||||
|  | ||||
| 		const T & operator[](size_t offset) const | ||||
| 		{ | ||||
| 			return (*(*this + offset)); | ||||
| 		} | ||||
|  | ||||
| 		bool operator<(const iterator & right) const | ||||
| 		{ | ||||
| 			return m_Ptr < right.m_Ptr; | ||||
| 		} | ||||
|  | ||||
| 		bool operator>(const iterator & right) const | ||||
| 		{ | ||||
| 			return m_Ptr > right.m_Ptr; | ||||
| 		} | ||||
|  | ||||
| 		bool operator<=(const iterator & right) const | ||||
| 		{ | ||||
| 			return m_Ptr <= right.m_Ptr; | ||||
| 		} | ||||
|  | ||||
| 		bool operator>=(const iterator & right) const | ||||
| 		{ | ||||
| 			return m_Ptr >= right.m_Ptr; | ||||
| 		} | ||||
|  | ||||
| 		size_t operator-(const iterator & right) const | ||||
| 		{ | ||||
| 			return m_Ptr - right.m_Ptr; | ||||
| 		} | ||||
| 	}; | ||||
|  | ||||
| 	// constructors / destructors | ||||
| 	CVector<T>() | ||||
| 	{ | ||||
| 		m_Size = 0; | ||||
| 		m_CurrentUsedSize = 0; | ||||
| 		m_Data = NULL; | ||||
| 	} | ||||
|  | ||||
| 	CVector<T>(const CVector<T> & other) | ||||
| 	{ | ||||
| 		// copy data | ||||
| 		m_Data = new T [other.m_Size]; | ||||
| 		m_Size = other.m_Size; | ||||
| 		m_CurrentUsedSize = other.m_CurrentUsedSize; | ||||
| 		memcpy(m_Data, other.m_Data, m_CurrentUsedSize * sizeof(T)); | ||||
| 	} | ||||
|  | ||||
| 	~CVector<T>() | ||||
| 	{ | ||||
| 		clear(); | ||||
| 	} | ||||
|  | ||||
| 	// interface | ||||
| 	size_t size() const | ||||
| 	{ | ||||
| 		return m_CurrentUsedSize; | ||||
| 	} | ||||
|  | ||||
| 	size_t capacity() const | ||||
| 	{ | ||||
| 		return m_Size; | ||||
| 	} | ||||
|  | ||||
| 	iterator begin() | ||||
| 	{ | ||||
| 		return iterator(m_Data); | ||||
| 	} | ||||
|  | ||||
| 	iterator end() | ||||
| 	{ | ||||
| 		return iterator(m_Data + m_CurrentUsedSize); | ||||
| 	} | ||||
|  | ||||
| 	iterator iterAt(size_t pos) | ||||
| 	{ | ||||
| 		if (pos > m_CurrentUsedSize) | ||||
| 			assert(0); | ||||
| 		return iterator(m_Data + pos); | ||||
| 	} | ||||
|  | ||||
| 	bool reserve(size_t newSize) | ||||
| 	{ | ||||
| 		return ChangeSize(newSize); | ||||
| 	} | ||||
|  | ||||
| 	bool push_back(const T & elem) | ||||
| 	{ | ||||
| 		++m_CurrentUsedSize; | ||||
| 		if (!GrowIfNeeded()) | ||||
| 		{ | ||||
| 			--m_CurrentUsedSize; | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		m_Data[m_CurrentUsedSize - 1] = elem; | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	void pop_back() | ||||
| 	{ | ||||
| 		--m_CurrentUsedSize; | ||||
| 		if (m_CurrentUsedSize < 0) | ||||
| 			m_CurrentUsedSize = 0; | ||||
| 		// :TODO: free memory sometimes | ||||
| 	} | ||||
|  | ||||
| 	bool resize(size_t newSize) | ||||
| 	{ | ||||
| 		if (!ChangeSize(newSize)) | ||||
| 			return false; | ||||
| 		FreeMemIfPossible(); | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	bool empty() const | ||||
| 	{ | ||||
| 		return (m_CurrentUsedSize == 0); | ||||
| 	} | ||||
|  | ||||
| 	T & at(size_t pos) | ||||
| 	{ | ||||
| 		if (pos > m_CurrentUsedSize) | ||||
| 		{ | ||||
| 			assert(0); | ||||
| 		} | ||||
| 		return m_Data[pos]; | ||||
| 	} | ||||
|  | ||||
| 	const  T & at(size_t pos) const | ||||
| 	{ | ||||
| 		if (pos > m_CurrentUsedSize) | ||||
| 		{ | ||||
| 			assert(0); | ||||
| 		} | ||||
| 		return m_Data[pos]; | ||||
| 	} | ||||
|  | ||||
| 	T & operator[](size_t pos) | ||||
| 	{ | ||||
| 		return at(pos); | ||||
| 	} | ||||
|  | ||||
| 	const T & operator[](size_t pos) const | ||||
| 	{ | ||||
| 		return at(pos); | ||||
| 	} | ||||
|  | ||||
| 	T & front() | ||||
| 	{ | ||||
| 		if (m_CurrentUsedSize < 1) | ||||
| 		{ | ||||
| 			assert(0); | ||||
| 		} | ||||
| 		return m_Data[0]; | ||||
| 	} | ||||
|  | ||||
| 	const T & front() const | ||||
| 	{ | ||||
| 		if (m_CurrentUsedSize < 1) | ||||
| 		{ | ||||
| 			assert(0); | ||||
| 		} | ||||
| 		return m_Data[0]; | ||||
| 	} | ||||
|  | ||||
| 	T & back() | ||||
| 	{ | ||||
| 		if (m_CurrentUsedSize < 1) | ||||
| 		{ | ||||
| 			assert(0); | ||||
| 		} | ||||
| 		return m_Data[m_CurrentUsedSize - 1]; | ||||
| 	} | ||||
|  | ||||
| 	const T & back() const | ||||
| 	{ | ||||
| 		if (m_CurrentUsedSize < 1) | ||||
| 		{ | ||||
| 			assert(0); | ||||
| 		} | ||||
| 		return m_Data[m_CurrentUsedSize - 1]; | ||||
| 	} | ||||
|  | ||||
| 	bool insert(iterator where, const T & value) | ||||
| 	{ | ||||
| 		// we have to insert before | ||||
| 		// if it is begin, don't decrement | ||||
| 		if (where != m_Data) | ||||
| 			--where; | ||||
| 		// validate iter | ||||
| 		if (where < m_Data || where >= (m_Data + m_CurrentUsedSize)) | ||||
| 			return false; | ||||
|  | ||||
| 		++m_CurrentUsedSize; | ||||
| 		if (!GrowIfNeeded()) | ||||
| 		{ | ||||
| 			--m_CurrentUsedSize; | ||||
| 			return false; | ||||
| 		} | ||||
|  | ||||
| 		memmove(where.base() + 1, where.base(), m_CurrentUsedSize - (where - m_Data)); | ||||
| 		memcpy(where.base(), &value, sizeof(T)); | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	void erase(iterator where) | ||||
| 	{ | ||||
| 		// validate iter | ||||
| 		if (where < m_Data || where >= (m_Data + m_CurrentUsedSize)) | ||||
| 			return false; | ||||
|  | ||||
| 		if (m_CurrentUsedSize > 1) | ||||
| 		{ | ||||
| 			// move | ||||
| 			memmove(where.base(), where.base() + 1, m_CurrentUsedSize - 1); | ||||
| 		} | ||||
|  | ||||
| 		--m_CurrentUsedSize; | ||||
| 		// :TODO: free memory sometimes | ||||
| 	} | ||||
|  | ||||
| 	void clear() | ||||
| 	{ | ||||
| 		m_Size = 0; | ||||
| 		m_CurrentUsedSize = 0; | ||||
| 		delete [] m_Data; | ||||
| 		m_Data = NULL; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| #endif // __CVECTOR_H__ | ||||
|  | ||||
		Reference in New Issue
	
	Block a user