linear_disk_cache.h 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. // Copyright 2013 Dolphin Emulator Project
  2. // Licensed under GPLv2
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include "common/common.h"
  6. #include <fstream>
  7. // defined in Version.cpp
  8. extern const char *scm_rev_git_str;
  9. // On disk format:
  10. //header{
  11. // u32 'DCAC';
  12. // u32 version; // svn_rev
  13. // u16 sizeof(key_type);
  14. // u16 sizeof(value_type);
  15. //}
  16. //key_value_pair{
  17. // u32 value_size;
  18. // key_type key;
  19. // value_type[value_size] value;
  20. //}
  21. template <typename K, typename V>
  22. class LinearDiskCacheReader
  23. {
  24. public:
  25. virtual void Read(const K &key, const V *value, u32 value_size) = 0;
  26. };
  27. // Dead simple unsorted key-value store with append functionality.
  28. // No random read functionality, all reading is done in OpenAndRead.
  29. // Keys and values can contain any characters, including \0.
  30. //
  31. // Suitable for caching generated shader bytecode between executions.
  32. // Not tuned for extreme performance but should be reasonably fast.
  33. // Does not support keys or values larger than 2GB, which should be reasonable.
  34. // Keys must have non-zero length; values can have zero length.
  35. // K and V are some POD type
  36. // K : the key type
  37. // V : value array type
  38. template <typename K, typename V>
  39. class LinearDiskCache
  40. {
  41. public:
  42. // return number of read entries
  43. u32 OpenAndRead(const char *filename, LinearDiskCacheReader<K, V> &reader)
  44. {
  45. using std::ios_base;
  46. // close any currently opened file
  47. Close();
  48. m_num_entries = 0;
  49. // try opening for reading/writing
  50. OpenFStream(m_file, filename, ios_base::in | ios_base::out | ios_base::binary);
  51. m_file.seekg(0, std::ios::end);
  52. std::fstream::pos_type end_pos = m_file.tellg();
  53. m_file.seekg(0, std::ios::beg);
  54. std::fstream::pos_type start_pos = m_file.tellg();
  55. std::streamoff file_size = end_pos - start_pos;
  56. if (m_file.is_open() && ValidateHeader())
  57. {
  58. // good header, read some key/value pairs
  59. K key;
  60. V *value = NULL;
  61. u32 value_size;
  62. u32 entry_number;
  63. std::fstream::pos_type last_pos = m_file.tellg();
  64. while (Read(&value_size))
  65. {
  66. std::streamoff next_extent = (last_pos - start_pos) + sizeof(value_size) + value_size;
  67. if (next_extent > file_size)
  68. break;
  69. delete[] value;
  70. value = new V[value_size];
  71. // read key/value and pass to reader
  72. if (Read(&key) &&
  73. Read(value, value_size) &&
  74. Read(&entry_number) &&
  75. entry_number == m_num_entries+1)
  76. {
  77. reader.Read(key, value, value_size);
  78. }
  79. else
  80. {
  81. break;
  82. }
  83. m_num_entries++;
  84. last_pos = m_file.tellg();
  85. }
  86. m_file.seekp(last_pos);
  87. m_file.clear();
  88. delete[] value;
  89. return m_num_entries;
  90. }
  91. // failed to open file for reading or bad header
  92. // close and recreate file
  93. Close();
  94. m_file.open(filename, ios_base::out | ios_base::trunc | ios_base::binary);
  95. WriteHeader();
  96. return 0;
  97. }
  98. void Sync()
  99. {
  100. m_file.flush();
  101. }
  102. void Close()
  103. {
  104. if (m_file.is_open())
  105. m_file.close();
  106. // clear any error flags
  107. m_file.clear();
  108. }
  109. // Appends a key-value pair to the store.
  110. void Append(const K &key, const V *value, u32 value_size)
  111. {
  112. // TODO: Should do a check that we don't already have "key"? (I think each caller does that already.)
  113. Write(&value_size);
  114. Write(&key);
  115. Write(value, value_size);
  116. m_num_entries++;
  117. Write(&m_num_entries);
  118. }
  119. private:
  120. void WriteHeader()
  121. {
  122. Write(&m_header);
  123. }
  124. bool ValidateHeader()
  125. {
  126. char file_header[sizeof(Header)];
  127. return (Read(file_header, sizeof(Header))
  128. && !memcmp((const char*)&m_header, file_header, sizeof(Header)));
  129. }
  130. template <typename D>
  131. bool Write(const D *data, u32 count = 1)
  132. {
  133. return m_file.write((const char*)data, count * sizeof(D)).good();
  134. }
  135. template <typename D>
  136. bool Read(const D *data, u32 count = 1)
  137. {
  138. return m_file.read((char*)data, count * sizeof(D)).good();
  139. }
  140. struct Header
  141. {
  142. Header()
  143. : id(*(u32*)"DCAC")
  144. , key_t_size(sizeof(K))
  145. , value_t_size(sizeof(V))
  146. {
  147. memcpy(ver, scm_rev_git_str, 40);
  148. }
  149. const u32 id;
  150. const u16 key_t_size, value_t_size;
  151. char ver[40];
  152. } m_header;
  153. std::fstream m_file;
  154. u32 m_num_entries;
  155. };