Dash Core  0.12.2.1
P2P Digital Currency
flat-database.h
Go to the documentation of this file.
1 // Copyright (c) 2014-2017 The Dash Core developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #ifndef FLAT_DATABASE_H
6 #define FLAT_DATABASE_H
7 
8 #include "chainparams.h"
9 #include "clientversion.h"
10 #include "hash.h"
11 #include "streams.h"
12 #include "util.h"
13 
14 #include <boost/filesystem.hpp>
15 
21 template<typename T>
22 class CFlatDB
23 {
24 private:
25 
26  enum ReadResult {
27  Ok,
34  };
35 
36  boost::filesystem::path pathDB;
37  std::string strFilename;
38  std::string strMagicMessage;
39 
40  bool Write(const T& objToSave)
41  {
42  // LOCK(objToSave.cs);
43 
44  int64_t nStart = GetTimeMillis();
45 
46  // serialize, checksum data up to that point, then append checksum
48  ssObj << strMagicMessage; // specific magic message for this type of object
49  ssObj << FLATDATA(Params().MessageStart()); // network specific magic number
50  ssObj << objToSave;
51  uint256 hash = Hash(ssObj.begin(), ssObj.end());
52  ssObj << hash;
53 
54  // open output file, and associate with CAutoFile
55  FILE *file = fopen(pathDB.string().c_str(), "wb");
57  if (fileout.IsNull())
58  return error("%s: Failed to open file %s", __func__, pathDB.string());
59 
60  // Write and commit header, data
61  try {
62  fileout << ssObj;
63  }
64  catch (std::exception &e) {
65  return error("%s: Serialize or I/O error - %s", __func__, e.what());
66  }
67  fileout.fclose();
68 
69  LogPrintf("Written info to %s %dms\n", strFilename, GetTimeMillis() - nStart);
70  LogPrintf(" %s\n", objToSave.ToString());
71 
72  return true;
73  }
74 
75  ReadResult Read(T& objToLoad, bool fDryRun = false)
76  {
77  //LOCK(objToLoad.cs);
78 
79  int64_t nStart = GetTimeMillis();
80  // open input file, and associate with CAutoFile
81  FILE *file = fopen(pathDB.string().c_str(), "rb");
83  if (filein.IsNull())
84  {
85  error("%s: Failed to open file %s", __func__, pathDB.string());
86  return FileError;
87  }
88 
89  // use file size to size memory buffer
90  int fileSize = boost::filesystem::file_size(pathDB);
91  int dataSize = fileSize - sizeof(uint256);
92  // Don't try to resize to a negative number if file is small
93  if (dataSize < 0)
94  dataSize = 0;
95  std::vector<unsigned char> vchData;
96  vchData.resize(dataSize);
97  uint256 hashIn;
98 
99  // read data and checksum from file
100  try {
101  filein.read((char *)&vchData[0], dataSize);
102  filein >> hashIn;
103  }
104  catch (std::exception &e) {
105  error("%s: Deserialize or I/O error - %s", __func__, e.what());
106  return HashReadError;
107  }
108  filein.fclose();
109 
110  CDataStream ssObj(vchData, SER_DISK, CLIENT_VERSION);
111 
112  // verify stored checksum matches input data
113  uint256 hashTmp = Hash(ssObj.begin(), ssObj.end());
114  if (hashIn != hashTmp)
115  {
116  error("%s: Checksum mismatch, data corrupted", __func__);
117  return IncorrectHash;
118  }
119 
120 
121  unsigned char pchMsgTmp[4];
122  std::string strMagicMessageTmp;
123  try {
124  // de-serialize file header (file specific magic message) and ..
125  ssObj >> strMagicMessageTmp;
126 
127  // ... verify the message matches predefined one
128  if (strMagicMessage != strMagicMessageTmp)
129  {
130  error("%s: Invalid magic message", __func__);
131  return IncorrectMagicMessage;
132  }
133 
134 
135  // de-serialize file header (network specific magic number) and ..
136  ssObj >> FLATDATA(pchMsgTmp);
137 
138  // ... verify the network matches ours
139  if (memcmp(pchMsgTmp, Params().MessageStart(), sizeof(pchMsgTmp)))
140  {
141  error("%s: Invalid network magic number", __func__);
142  return IncorrectMagicNumber;
143  }
144 
145  // de-serialize data into T object
146  ssObj >> objToLoad;
147  }
148  catch (std::exception &e) {
149  objToLoad.Clear();
150  error("%s: Deserialize or I/O error - %s", __func__, e.what());
151  return IncorrectFormat;
152  }
153 
154  LogPrintf("Loaded info from %s %dms\n", strFilename, GetTimeMillis() - nStart);
155  LogPrintf(" %s\n", objToLoad.ToString());
156  if(!fDryRun) {
157  LogPrintf("%s: Cleaning....\n", __func__);
158  objToLoad.CheckAndRemove();
159  LogPrintf(" %s\n", objToLoad.ToString());
160  }
161 
162  return Ok;
163  }
164 
165 
166 public:
167  CFlatDB(std::string strFilenameIn, std::string strMagicMessageIn)
168  {
169  pathDB = GetDataDir() / strFilenameIn;
170  strFilename = strFilenameIn;
171  strMagicMessage = strMagicMessageIn;
172  }
173 
174  bool Load(T& objToLoad)
175  {
176  LogPrintf("Reading info from %s...\n", strFilename);
177  ReadResult readResult = Read(objToLoad);
178  if (readResult == FileError)
179  LogPrintf("Missing file %s, will try to recreate\n", strFilename);
180  else if (readResult != Ok)
181  {
182  LogPrintf("Error reading %s: ", strFilename);
183  if(readResult == IncorrectFormat)
184  {
185  LogPrintf("%s: Magic is ok but data has invalid format, will try to recreate\n", __func__);
186  }
187  else {
188  LogPrintf("%s: File format is unknown or invalid, please fix it manually\n", __func__);
189  // program should exit with an error
190  return false;
191  }
192  }
193  return true;
194  }
195 
196  bool Dump(T& objToSave)
197  {
198  int64_t nStart = GetTimeMillis();
199 
200  LogPrintf("Verifying %s format...\n", strFilename);
201  T tmpObjToLoad;
202  ReadResult readResult = Read(tmpObjToLoad, true);
203 
204  // there was an error and it was not an error on file opening => do not proceed
205  if (readResult == FileError)
206  LogPrintf("Missing file %s, will try to recreate\n", strFilename);
207  else if (readResult != Ok)
208  {
209  LogPrintf("Error reading %s: ", strFilename);
210  if(readResult == IncorrectFormat)
211  LogPrintf("%s: Magic is ok but data has invalid format, will try to recreate\n", __func__);
212  else
213  {
214  LogPrintf("%s: File format is unknown or invalid, please fix it manually\n", __func__);
215  return false;
216  }
217  }
218 
219  LogPrintf("Writing info to %s...\n", strFilename);
220  Write(objToSave);
221  LogPrintf("%s dump finished %dms\n", strFilename, GetTimeMillis() - nStart);
222 
223  return true;
224  }
225 
226 };
227 
228 
229 #endif
const boost::filesystem::path & GetDataDir(bool fNetSpecific)
Definition: util.cpp:547
bool Write(const T &objToSave)
Definition: flat-database.h:40
static FILE * fileout
Definition: util.cpp:210
bool Dump(T &objToSave)
const_iterator end() const
Definition: streams.h:120
#define FLATDATA(obj)
Definition: serialize.h:387
std::string strMagicMessage
Definition: flat-database.h:38
std::string strFilename
Definition: flat-database.h:37
#define LogPrintf(...)
Definition: util.h:98
const_iterator begin() const
Definition: streams.h:118
static bool error(const char *format)
Definition: util.h:131
boost::filesystem::path pathDB
Definition: flat-database.h:36
uint256 Hash(const T1 pbegin, const T1 pend)
Definition: hash.h:123
bool Load(T &objToLoad)
CFlatDB(std::string strFilenameIn, std::string strMagicMessageIn)
const CChainParams & Params()
int64_t GetTimeMillis()
Definition: utiltime.cpp:34
static const int CLIENT_VERSION
Definition: clientversion.h:54
ReadResult Read(T &objToLoad, bool fDryRun=false)
Definition: flat-database.h:75