libspatialindex API Reference  (git-trunk)
DiskStorageManager.cc
Go to the documentation of this file.
1 /******************************************************************************
2  * Project: libspatialindex - A C++ library for spatial indexing
3  * Author: Marios Hadjieleftheriou, mhadji@gmail.com
4  ******************************************************************************
5  * Copyright (c) 2002, Marios Hadjieleftheriou
6  *
7  * All rights reserved.
8  *
9  * Permission is hereby granted, free of charge, to any person obtaining a
10  * copy of this software and associated documentation files (the "Software"),
11  * to deal in the Software without restriction, including without limitation
12  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13  * and/or sell copies of the Software, and to permit persons to whom the
14  * Software is furnished to do so, subject to the following conditions:
15  *
16  * The above copyright notice and this permission notice shall be included
17  * in all copies or substantial portions of the Software.
18  *
19  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25  * DEALINGS IN THE SOFTWARE.
26 ******************************************************************************/
27 
28 #include <fstream>
29 #include <cstring>
30 
31 // For checking if a file exists - hobu
32 #include <sys/stat.h>
33 
34 #ifdef WIN32
35 #define stat _stat64
36 #endif
37 
39 #include "DiskStorageManager.h"
41 
42 using namespace SpatialIndex;
43 using namespace SpatialIndex::StorageManager;
44 
46 {
47  bool bExists = false;
48 
49  std::string filename("");
50  std::string idx("idx");
51  std::string dat("dat");
52 
53  Tools::Variant idx_name;
54  Tools::Variant dat_name;
55  Tools::Variant fn;
56 
57  idx_name = ps.getProperty("FileNameIdx");
58  dat_name = ps.getProperty("FileNameDat");
59  fn = ps.getProperty("FileName");
60 
61  if (idx_name.m_varType != Tools::VT_EMPTY) dat = std::string(idx_name.m_val.pcVal);
62  if (dat_name.m_varType != Tools::VT_EMPTY) idx = std::string(dat_name.m_val.pcVal);
63  if (fn.m_varType != Tools::VT_EMPTY) filename = std::string(fn.m_val.pcVal);
64 
65  struct stat stats;
66 
67  std::ostringstream os;
68  int ret;
69  os << filename <<"."<<dat;
70  std::string data_name = os.str();
71  ret = stat(data_name.c_str(), &stats);
72 
73  if (ret == 0) bExists = true;
74 
75  os.str("");
76  os << filename <<"."<<idx;
77  std::string index_name = os.str();
78  ret = stat(index_name.c_str(), &stats);
79 
80  if ((ret == 0) && (bExists == true)) bExists = true;
81 
82  return bExists;
83 }
85 {
86  IStorageManager* sm = new DiskStorageManager(ps);
87  return sm;
88 }
89 
91 {
92  Tools::Variant var;
94 
96  var.m_val.blVal = true;
97  ps.setProperty("Overwrite", var);
98  // overwrite the file if it exists.
99 
101  var.m_val.pcVal = const_cast<char*>(baseName.c_str());
102  ps.setProperty("FileName", var);
103  // .idx and .dat extensions will be added.
104 
106  var.m_val.ulVal = pageSize;
107  ps.setProperty("PageSize", var);
108  // specify the page size. Since the index may also contain user defined data
109  // there is no way to know how big a single node may become. The storage manager
110  // will use multiple pages per node if needed. Off course this will slow down performance.
111 
112  return returnDiskStorageManager(ps);
113 }
114 
116 {
117  Tools::Variant var;
119 
121  var.m_val.pcVal = const_cast<char*>(baseName.c_str());
122  ps.setProperty("FileName", var);
123  // .idx and .dat extensions will be added.
124 
125  return returnDiskStorageManager(ps);
126 }
127 
128 DiskStorageManager::DiskStorageManager(Tools::PropertySet& ps) : m_pageSize(0), m_nextPage(-1), m_buffer(nullptr)
129 {
130  Tools::Variant var;
131 
132  // Open/Create flag.
133  bool bOverwrite = false;
134  bool bFileExists = false;
135  std::streamoff length = 0;
136 
137  var = ps.getProperty("Overwrite");
138 
139  if (var.m_varType != Tools::VT_EMPTY)
140  {
141  if (var.m_varType != Tools::VT_BOOL)
142  throw Tools::IllegalArgumentException("SpatialIndex::DiskStorageManager: Property Overwrite must be Tools::VT_BOOL");
143  bOverwrite = var.m_val.blVal;
144  }
145 
146  // storage filename.
147  var = ps.getProperty("FileName");
148 
149  if (var.m_varType != Tools::VT_EMPTY)
150  {
151  if (!(var.m_varType == Tools::VT_PCHAR ||
152  var.m_varType == Tools::VT_PWCHAR))
153  throw Tools::IllegalArgumentException("SpatialIndex::DiskStorageManager: Property FileName must be Tools::VT_PCHAR or Tools::VT_PWCHAR");
154 
155  std::string idx("idx");
156  std::string dat("dat");
157 
158  Tools::Variant idx_name = ps.getProperty("FileNameIdx");
159  if (idx_name.m_varType != Tools::VT_EMPTY) idx = std::string(idx_name.m_val.pcVal);
160 
161  Tools::Variant dat_name = ps.getProperty("FileNameDat");
162  if (dat_name.m_varType != Tools::VT_EMPTY) dat = std::string(dat_name.m_val.pcVal);
163 
164  std::string sIndexFile = std::string(var.m_val.pcVal) + "." + idx;
165  std::string sDataFile = std::string(var.m_val.pcVal) + "." + dat;
166 
167  // check if file exists.
168  bFileExists = CheckFilesExists(ps);
169 
170  // check if file can be read/written.
171  if (bFileExists == true && bOverwrite == false)
172  {
173  std::ios_base::openmode mode = std::ios::in | std::ios::out | std::ios::binary;
174  m_indexFile.open(sIndexFile.c_str(), mode);
175  m_dataFile.open(sDataFile.c_str(), mode);
176 
177  if (m_indexFile.fail() || m_dataFile.fail())
178  throw Tools::IllegalArgumentException("SpatialIndex::DiskStorageManager: Index/Data file cannot be read/written.");
179  }
180  else
181  {
182  std::ios_base::openmode mode = std::ios::in | std::ios::out | std::ios::binary | std::ios::trunc;
183  m_indexFile.open(sIndexFile.c_str(), mode);
184  m_dataFile.open(sDataFile.c_str(), mode);
185 
186  if (m_indexFile.fail() || m_dataFile.fail())
187  throw Tools::IllegalArgumentException("SpatialIndex::DiskStorageManager: Index/Data file cannot be created.");
188 
189  }
190  }
191  else
192  {
193  throw Tools::IllegalArgumentException("SpatialIndex::DiskStorageManager: Property FileName was not specified.");
194  }
195 
196  // get current length of file
197  m_indexFile.seekg (0, m_indexFile.end);
198  length = m_indexFile.tellg();
199  m_indexFile.seekg (0, m_indexFile.beg);
200 
201  // find page size.
202  if ((bOverwrite == true) || (length == 0) || (bFileExists == false))
203  {
204  var = ps.getProperty("PageSize");
205 
206  if (var.m_varType != Tools::VT_EMPTY)
207  {
208  if (var.m_varType != Tools::VT_ULONG)
209  throw Tools::IllegalArgumentException("SpatialIndex::DiskStorageManager: Property PageSize must be Tools::VT_ULONG");
210  m_pageSize = var.m_val.ulVal;
211  m_nextPage = 0;
212  }
213  else
214  {
215  throw Tools::IllegalArgumentException("SpatialIndex::DiskStorageManager: A new storage manager is created and property PageSize was not specified.");
216  }
217  }
218  else
219  {
220  m_indexFile.read(reinterpret_cast<char*>(&m_pageSize), sizeof(uint32_t));
221  if (m_indexFile.fail())
222  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Failed reading pageSize.");
223 
224  m_indexFile.read(reinterpret_cast<char*>(&m_nextPage), sizeof(id_type));
225  if (m_indexFile.fail())
226  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Failed reading nextPage.");
227  }
228 
229  // create buffer.
230  m_buffer = new uint8_t[m_pageSize];
231  memset(m_buffer, 0, m_pageSize);
232 
233  if ((bOverwrite == false) && (length > 0))
234  {
235  uint32_t count;
236  id_type page, id;
237 
238  // load empty pages in memory.
239  m_indexFile.read(reinterpret_cast<char*>(&count), sizeof(uint32_t));
240  if (m_indexFile.fail())
241  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
242 
243  for (uint32_t cCount = 0; cCount < count; ++cCount)
244  {
245  m_indexFile.read(reinterpret_cast<char*>(&page), sizeof(id_type));
246  if (m_indexFile.fail())
247  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
248  m_emptyPages.insert(page);
249  }
250 
251  // load index table in memory.
252  m_indexFile.read(reinterpret_cast<char*>(&count), sizeof(uint32_t));
253  if (m_indexFile.fail())
254  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
255 
256  for (uint32_t cCount = 0; cCount < count; ++cCount)
257  {
258  Entry* e = new Entry();
259 
260  m_indexFile.read(reinterpret_cast<char*>(&id), sizeof(id_type));
261  if (m_indexFile.fail())
262  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
263 
264  m_indexFile.read(reinterpret_cast<char*>(&(e->m_length)), sizeof(uint32_t));
265  if (m_indexFile.fail())
266  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
267 
268  uint32_t count2;
269  m_indexFile.read(reinterpret_cast<char*>(&count2), sizeof(uint32_t));
270  if (m_indexFile.fail())
271  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
272 
273  for (uint32_t cCount2 = 0; cCount2 < count2; ++cCount2)
274  {
275  m_indexFile.read(reinterpret_cast<char*>(&page), sizeof(id_type));
276  if (m_indexFile.fail())
277  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
278  e->m_pages.push_back(page);
279  }
280  m_pageIndex.insert(std::pair<id_type, Entry* >(id, e));
281  }
282  }
283 }
284 
286 {
287  flush();
288  m_indexFile.close();
289  m_dataFile.close();
290  if (m_buffer != nullptr) delete[] m_buffer;
291 
292  for (auto& v: m_pageIndex)
293  delete v.second;
294 }
295 
297 {
298  m_indexFile.seekp(0, std::ios_base::beg);
299  if (m_indexFile.fail())
300  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
301 
302  m_indexFile.write(reinterpret_cast<const char*>(&m_pageSize), sizeof(uint32_t));
303  if (m_indexFile.fail())
304  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
305 
306  m_indexFile.write(reinterpret_cast<const char*>(&m_nextPage), sizeof(id_type));
307  if (m_indexFile.fail())
308  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
309 
310  uint32_t count = static_cast<uint32_t>(m_emptyPages.size());
311  m_indexFile.write(reinterpret_cast<const char*>(&count), sizeof(uint32_t));
312  if (m_indexFile.fail())
313  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
314 
315  for (std::set<id_type>::const_iterator it = m_emptyPages.begin(); it != m_emptyPages.end(); ++it)
316  {
317  m_indexFile.write(reinterpret_cast<const char*>(&(*it)), sizeof(id_type));
318  if (m_indexFile.fail())
319  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
320  }
321 
322  count = static_cast<uint32_t>(m_pageIndex.size());
323  m_indexFile.write(reinterpret_cast<const char*>(&count), sizeof(uint32_t));
324  if (m_indexFile.fail())
325  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
326 
327  for (std::map<id_type, Entry*>::iterator it = m_pageIndex.begin(); it != m_pageIndex.end(); ++it)
328  {
329  m_indexFile.write(reinterpret_cast<const char*>(&((*it).first)), sizeof(id_type));
330  if (m_indexFile.fail())
331  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
332 
333  m_indexFile.write(reinterpret_cast<const char*>(&((*it).second->m_length)), sizeof(uint32_t));
334  if (m_indexFile.fail())
335  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
336 
337  count = static_cast<uint32_t>((*it).second->m_pages.size());
338  m_indexFile.write(reinterpret_cast<const char*>(&count), sizeof(uint32_t));
339  if (m_indexFile.fail())
340  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
341 
342  for (uint32_t cIndex = 0; cIndex < count; ++cIndex)
343  {
344  m_indexFile.write(reinterpret_cast<const char*>(&((*it).second->m_pages[cIndex])), sizeof(id_type));
345  if (m_indexFile.fail())
346  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted storage manager index file.");
347  }
348  }
349 
350  m_indexFile.flush();
351  m_dataFile.flush();
352 }
353 
354 void DiskStorageManager::loadByteArray(const id_type page, uint32_t& len, uint8_t** data)
355 {
356  std::map<id_type, Entry*>::iterator it = m_pageIndex.find(page);
357 
358  if (it == m_pageIndex.end())
359  throw InvalidPageException(page);
360 
361  std::vector<id_type>& pages = (*it).second->m_pages;
362  uint32_t cNext = 0;
363  uint32_t cTotal = static_cast<uint32_t>(pages.size());
364 
365  len = (*it).second->m_length;
366  *data = new uint8_t[len];
367 
368  uint8_t* ptr = *data;
369  uint32_t cLen;
370  uint32_t cRem = len;
371 
372  do
373  {
374  m_dataFile.seekg(pages[cNext] * m_pageSize, std::ios_base::beg);
375  if (m_dataFile.fail())
376  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted data file.");
377 
378  m_dataFile.read(reinterpret_cast<char*>(m_buffer), m_pageSize);
379  if (m_dataFile.fail())
380  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted data file.");
381 
382  cLen = (cRem > m_pageSize) ? m_pageSize : cRem;
383  memcpy(ptr, m_buffer, cLen);
384 
385  ptr += cLen;
386  cRem -= cLen;
387  ++cNext;
388  }
389  while (cNext < cTotal);
390 }
391 
392 void DiskStorageManager::storeByteArray(id_type& page, const uint32_t len, const uint8_t* const data)
393 {
394  if (page == NewPage)
395  {
396  Entry* e = new Entry();
397  e->m_length = len;
398 
399  const uint8_t* ptr = data;
400  id_type cPage;
401  uint32_t cRem = len;
402  uint32_t cLen;
403 
404  while (cRem > 0)
405  {
406  if (! m_emptyPages.empty())
407  {
408  cPage = *m_emptyPages.begin();
409  m_emptyPages.erase(m_emptyPages.begin());
410  }
411  else
412  {
413  cPage = m_nextPage;
414  ++m_nextPage;
415  }
416 
417  cLen = (cRem > m_pageSize) ? m_pageSize : cRem;
418  memcpy(m_buffer, ptr, cLen);
419 
420  m_dataFile.seekp(cPage * m_pageSize, std::ios_base::beg);
421  if (m_dataFile.fail())
422  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted data file.");
423 
424  m_dataFile.write(reinterpret_cast<const char*>(m_buffer), m_pageSize);
425  if (m_dataFile.fail())
426  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted data file.");
427 
428  ptr += cLen;
429  cRem -= cLen;
430  e->m_pages.push_back(cPage);
431  }
432 
433  page = e->m_pages[0];
434  m_pageIndex.insert(std::pair<id_type, Entry*>(page, e));
435  }
436  else
437  {
438  // find the entry.
439  std::map<id_type, Entry*>::iterator it = m_pageIndex.find(page);
440 
441  // check if it exists.
442  if (it == m_pageIndex.end())
443  throw InvalidPageException(page);
444 
445  Entry* oldEntry = (*it).second;
446 
447  m_pageIndex.erase(it);
448 
449  Entry* e = new Entry();
450  e->m_length = len;
451 
452  const uint8_t* ptr = data;
453  id_type cPage;
454  uint32_t cRem = len;
455  uint32_t cLen, cNext = 0;
456 
457  while (cRem > 0)
458  {
459  if (cNext < oldEntry->m_pages.size())
460  {
461  cPage = oldEntry->m_pages[cNext];
462  ++cNext;
463  }
464  else if (! m_emptyPages.empty())
465  {
466  cPage = *m_emptyPages.begin();
467  m_emptyPages.erase(m_emptyPages.begin());
468  }
469  else
470  {
471  cPage = m_nextPage;
472  ++m_nextPage;
473  }
474 
475  cLen = (cRem > m_pageSize) ? m_pageSize : cRem;
476  memcpy(m_buffer, ptr, cLen);
477 
478  m_dataFile.seekp(cPage * m_pageSize, std::ios_base::beg);
479  if (m_dataFile.fail())
480  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted data file.");
481 
482  m_dataFile.write(reinterpret_cast<const char*>(m_buffer), m_pageSize);
483  if (m_dataFile.fail())
484  throw Tools::IllegalStateException("SpatialIndex::DiskStorageManager: Corrupted data file.");
485 
486  ptr += cLen;
487  cRem -= cLen;
488  e->m_pages.push_back(cPage);
489  }
490 
491  while (cNext < oldEntry->m_pages.size())
492  {
493  m_emptyPages.insert(oldEntry->m_pages[cNext]);
494  ++cNext;
495  }
496 
497  m_pageIndex.insert(std::pair<id_type, Entry*>(page, e));
498  delete oldEntry;
499  }
500 }
501 
503 {
504  std::map<id_type, Entry*>::iterator it = m_pageIndex.find(page);
505 
506  if (it == m_pageIndex.end())
507  throw InvalidPageException(page);
508 
509  for (uint32_t cIndex = 0; cIndex < (*it).second->m_pages.size(); ++cIndex)
510  {
511  m_emptyPages.insert((*it).second->m_pages[cIndex]);
512  }
513 
514  delete (*it).second;
515  m_pageIndex.erase(it);
516 }
void storeByteArray(id_type &page, const uint32_t len, const uint8_t *const data) override
VariantType m_varType
Definition: Tools.h:277
uint32_t ulVal
Definition: Tools.h:289
void setProperty(std::string property, Variant const &v)
Definition: Tools.cc:354
SIDX_DLL IStorageManager * returnDiskStorageManager(Tools::PropertySet &in)
char * pcVal
Definition: Tools.h:292
bool CheckFilesExists(Tools::PropertySet &ps)
union Tools::Variant::@0 m_val
SIDX_DLL IStorageManager * loadDiskStorageManager(std::string &baseName)
void loadByteArray(const id_type page, uint32_t &len, uint8_t **data) override
int64_t id_type
Definition: SpatialIndex.h:41
Variant getProperty(std::string property) const
Definition: Tools.cc:346
bool blVal
Definition: Tools.h:291
void deleteByteArray(const id_type page) override
SIDX_DLL IStorageManager * createNewDiskStorageManager(std::string &baseName, uint32_t pageSize)