| 
									
										
										
										
											2013-04-17 23:09:55 -04:00
										 |  |  | // Copyright 2013 Dolphin Emulator Project
 | 
					
						
							|  |  |  | // Licensed under GPLv2
 | 
					
						
							|  |  |  | // Refer to the license.txt file included.
 | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-10 13:54:46 -05:00
										 |  |  | #pragma once
 | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-20 04:11:52 +01:00
										 |  |  | #include <cstring>
 | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | #include <fstream>
 | 
					
						
							| 
									
										
										
										
											2014-03-12 15:33:41 -04:00
										 |  |  | #include <string>
 | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | #include "Common/Common.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-19 12:33:13 +01:00
										 |  |  | #include "Common/FileUtil.h"
 | 
					
						
							| 
									
										
										
										
											2014-02-17 05:18:15 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | // On disk format:
 | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | //header{
 | 
					
						
							|  |  |  | // u32 'DCAC';
 | 
					
						
							|  |  |  | // u32 version;  // svn_rev
 | 
					
						
							|  |  |  | // u16 sizeof(key_type);
 | 
					
						
							|  |  |  | // u16 sizeof(value_type);
 | 
					
						
							|  |  |  | //}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //key_value_pair{
 | 
					
						
							|  |  |  | // u32 value_size;
 | 
					
						
							|  |  |  | // key_type   key;
 | 
					
						
							|  |  |  | // value_type[value_size]   value;
 | 
					
						
							|  |  |  | //}
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | template <typename K, typename V> | 
					
						
							|  |  |  | class LinearDiskCacheReader | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | public: | 
					
						
							|  |  |  | 	virtual void Read(const K &key, const V *value, u32 value_size) = 0; | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Dead simple unsorted key-value store with append functionality.
 | 
					
						
							|  |  |  | // No random read functionality, all reading is done in OpenAndRead.
 | 
					
						
							|  |  |  | // Keys and values can contain any characters, including \0.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Suitable for caching generated shader bytecode between executions.
 | 
					
						
							|  |  |  | // Not tuned for extreme performance but should be reasonably fast.
 | 
					
						
							|  |  |  | // Does not support keys or values larger than 2GB, which should be reasonable.
 | 
					
						
							|  |  |  | // Keys must have non-zero length; values can have zero length.
 | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | // K and V are some POD type
 | 
					
						
							|  |  |  | // K : the key type
 | 
					
						
							|  |  |  | // V : value array type
 | 
					
						
							|  |  |  | template <typename K, typename V> | 
					
						
							|  |  |  | class LinearDiskCache | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | public: | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 	// return number of read entries
 | 
					
						
							| 
									
										
										
										
											2014-03-12 15:33:41 -04:00
										 |  |  | 	u32 OpenAndRead(const std::string& filename, LinearDiskCacheReader<K, V> &reader) | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 		using std::ios_base; | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// close any currently opened file
 | 
					
						
							|  |  |  | 		Close(); | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 		m_num_entries = 0; | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// try opening for reading/writing
 | 
					
						
							| 
									
										
										
										
											2013-02-28 19:33:39 -06:00
										 |  |  | 		OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary); | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		m_file.seekg(0, std::ios::end); | 
					
						
							|  |  |  | 		std::fstream::pos_type end_pos = m_file.tellg(); | 
					
						
							|  |  |  | 		m_file.seekg(0, std::ios::beg); | 
					
						
							|  |  |  | 		std::fstream::pos_type start_pos = m_file.tellg(); | 
					
						
							|  |  |  | 		std::streamoff file_size = end_pos - start_pos; | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 		if (m_file.is_open() && ValidateHeader()) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			// good header, read some key/value pairs
 | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 			K key; | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-09 21:14:26 +01:00
										 |  |  | 			V *value = nullptr; | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 			u32 value_size; | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 			u32 entry_number; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			std::fstream::pos_type last_pos = m_file.tellg(); | 
					
						
							| 
									
										
										
										
											2011-03-30 10:46:27 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 			while (Read(&value_size)) | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 				std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size; | 
					
						
							|  |  |  | 				if (next_extent > file_size) | 
					
						
							|  |  |  | 					break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 				delete[] value; | 
					
						
							|  |  |  | 				value = new V[value_size]; | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 				// read key/value and pass to reader
 | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 				if (Read(&key) && | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 					Read(value, value_size) && | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 					Read(&entry_number) && | 
					
						
							|  |  |  | 					entry_number == m_num_entries+1) | 
					
						
							| 
									
										
										
										
											2014-02-16 23:51:41 -05:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 					reader.Read(key, value, value_size); | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 				else | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 				{ | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 					break; | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 				m_num_entries++; | 
					
						
							|  |  |  | 				last_pos = m_file.tellg(); | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 			m_file.seekp(last_pos); | 
					
						
							| 
									
										
										
										
											2010-12-30 07:32:16 +00:00
										 |  |  | 			m_file.clear(); | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 			delete[] value; | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 			return m_num_entries; | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// failed to open file for reading or bad header
 | 
					
						
							|  |  |  | 		// close and recreate file
 | 
					
						
							|  |  |  | 		Close(); | 
					
						
							| 
									
										
										
										
											2011-06-11 19:37:21 +00:00
										 |  |  | 		m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary); | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 		WriteHeader(); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-10-29 01:23:17 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 	void Sync() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		m_file.flush(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	void Close() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		if (m_file.is_open()) | 
					
						
							|  |  |  | 			m_file.close(); | 
					
						
							|  |  |  | 		// clear any error flags
 | 
					
						
							|  |  |  | 		m_file.clear(); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Appends a key-value pair to the store.
 | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 	void Append(const K &key, const V *value, u32 value_size) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 		// TODO: Should do a check that we don't already have "key"? (I think each caller does that already.)
 | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 		Write(&value_size); | 
					
						
							|  |  |  | 		Write(&key); | 
					
						
							|  |  |  | 		Write(value, value_size); | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 		m_num_entries++; | 
					
						
							|  |  |  | 		Write(&m_num_entries); | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | private: | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 	void WriteHeader() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		Write(&m_header); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bool ValidateHeader() | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		char file_header[sizeof(Header)]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-03-11 00:30:55 +13:00
										 |  |  | 		return (Read(file_header, sizeof(Header)) && | 
					
						
							|  |  |  | 		        !memcmp((const char*)&m_header, file_header, sizeof(Header))); | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	template <typename D> | 
					
						
							|  |  |  | 	bool Write(const D *data, u32 count = 1) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return m_file.write((const char*)data, count * sizeof(D)).good(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	template <typename D> | 
					
						
							|  |  |  | 	bool Read(const D *data, u32 count = 1) | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		return m_file.read((char*)data, count * sizeof(D)).good(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	struct Header | 
					
						
							|  |  |  | 	{ | 
					
						
							|  |  |  | 		Header() | 
					
						
							|  |  |  | 			: id(*(u32*)"DCAC") | 
					
						
							|  |  |  | 			, key_t_size(sizeof(K)) | 
					
						
							|  |  |  | 			, value_t_size(sizeof(V)) | 
					
						
							| 
									
										
										
										
											2013-02-26 10:48:19 +01:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			memcpy(ver, scm_rev_git_str, 40); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-02-26 10:48:19 +01:00
										 |  |  | 		const u32 id; | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 		const u16 key_t_size, value_t_size; | 
					
						
							| 
									
										
										
										
											2013-02-26 10:48:19 +01:00
										 |  |  | 		char ver[40]; | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	} m_header; | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2010-11-15 05:22:03 +00:00
										 |  |  | 	std::fstream m_file; | 
					
						
							| 
									
										
										
										
											2011-12-30 20:37:46 -08:00
										 |  |  | 	u32 m_num_entries; | 
					
						
							| 
									
										
										
										
											2010-02-19 17:05:26 +00:00
										 |  |  | }; |