libspatialindex API Reference  (git-trunk)
MVRTree.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 <limits>
29 
31 
32 #include "Node.h"
33 #include "Leaf.h"
34 #include "Index.h"
35 #include "MVRTree.h"
36 
37 #include <cstring>
38 
39 // set to 1 to enable debugging output
40 #define SI_DEBUG_OUTPUT 0
41 
42 using namespace SpatialIndex::MVRTree;
43 
44 SpatialIndex::MVRTree::Data::Data(uint32_t len, uint8_t* pData, TimeRegion& r, id_type id)
45  : m_id(id), m_region(r), m_pData(nullptr), m_dataLength(len)
46 {
47  if (m_dataLength > 0)
48  {
49  m_pData = new uint8_t[m_dataLength];
50  memcpy(m_pData, pData, m_dataLength);
51  }
52 }
53 
55 {
56  delete[] m_pData;
57 }
58 
60 {
61  return new Data(m_dataLength, m_pData, m_region, m_id);
62 }
63 
65 {
66  return m_id;
67 }
68 
70 {
71  *out = new TimeRegion(m_region);
72 }
73 
74 void SpatialIndex::MVRTree::Data::getData(uint32_t& len, uint8_t** data) const
75 {
76  len = m_dataLength;
77  *data = nullptr;
78 
79  if (m_dataLength > 0)
80  {
81  *data = new uint8_t[m_dataLength];
82  memcpy(*data, m_pData, m_dataLength);
83  }
84 }
85 
87 {
88  return
89  sizeof(id_type) +
90  sizeof(uint32_t) +
91  m_dataLength +
92  m_region.getByteArraySize();
93 }
94 
96 {
97  memcpy(&m_id, ptr, sizeof(id_type));
98  ptr += sizeof(id_type);
99 
100  delete[] m_pData;
101  m_pData = nullptr;
102 
103  memcpy(&m_dataLength, ptr, sizeof(uint32_t));
104  ptr += sizeof(uint32_t);
105 
106  if (m_dataLength > 0)
107  {
108  m_pData = new uint8_t[m_dataLength];
109  memcpy(m_pData, ptr, m_dataLength);
110  ptr += m_dataLength;
111  }
112 
113  m_region.loadFromByteArray(ptr);
114 }
115 
116 void SpatialIndex::MVRTree::Data::storeToByteArray(uint8_t** data, uint32_t& len)
117 {
118  // it is thread safe this way.
119  uint32_t regionsize;
120  uint8_t* regiondata = nullptr;
121  m_region.storeToByteArray(&regiondata, regionsize);
122 
123  len = sizeof(id_type) + sizeof(uint32_t) + m_dataLength + regionsize;
124 
125  *data = new uint8_t[len];
126  uint8_t* ptr = *data;
127 
128  memcpy(ptr, &m_id, sizeof(id_type));
129  ptr += sizeof(id_type);
130  memcpy(ptr, &m_dataLength, sizeof(uint32_t));
131  ptr += sizeof(uint32_t);
132 
133  if (m_dataLength > 0)
134  {
135  memcpy(ptr, m_pData, m_dataLength);
136  ptr += m_dataLength;
137  }
138 
139  memcpy(ptr, regiondata, regionsize);
140  delete[] regiondata;
141  // ptr += regionsize;
142 }
143 
145 {
147  return si;
148 }
149 
152  double fillFactor,
153  uint32_t indexCapacity,
154  uint32_t leafCapacity,
155  uint32_t dimension,
156  MVRTreeVariant rv,
157  id_type& indexIdentifier)
158 {
159  Tools::Variant var;
161 
163  var.m_val.dblVal = fillFactor;
164  ps.setProperty("FillFactor", var);
165 
167  var.m_val.ulVal = indexCapacity;
168  ps.setProperty("IndexCapacity", var);
169 
171  var.m_val.ulVal = leafCapacity;
172  ps.setProperty("LeafCapacity", var);
173 
175  var.m_val.ulVal = dimension;
176  ps.setProperty("Dimension", var);
177 
179  var.m_val.lVal = rv;
180  ps.setProperty("TreeVariant", var);
181 
182  ISpatialIndex* ret = returnMVRTree(sm, ps);
183 
185  var = ps.getProperty("IndexIdentifier");
186  indexIdentifier = var.m_val.llVal;
187 
188  return ret;
189 }
190 
192 {
193  Tools::Variant var;
195 
197  var.m_val.llVal = indexIdentifier;
198  ps.setProperty("IndexIdentifier", var);
199 
200  return returnMVRTree(sm, ps);
201 }
202 
204  m_pStorageManager(&sm),
205  m_headerID(StorageManager::NewPage),
206  m_treeVariant(RV_RSTAR),
207  m_fillFactor(0.7),
208  m_indexCapacity(100),
209  m_leafCapacity(100),
210  m_nearMinimumOverlapFactor(32),
211  m_splitDistributionFactor(0.4),
212  m_reinsertFactor(0.3),
213  m_strongVersionOverflow(0.8),
214  //m_strongVersionUnderflow(0.2),
215  m_versionUnderflow(0.3),
216  m_dimension(2),
217  m_bTightMBRs(true),
218  m_bHasVersionCopied(false),
219  m_currentTime(0.0),
220  m_pointPool(500),
221  m_regionPool(1000),
222  m_indexPool(100),
223  m_leafPool(100)
224 {
225 
226  Tools::Variant var = ps.getProperty("IndexIdentifier");
227  if (var.m_varType != Tools::VT_EMPTY)
228  {
229  if (var.m_varType == Tools::VT_LONGLONG) m_headerID = var.m_val.llVal;
230  else if (var.m_varType == Tools::VT_LONG) m_headerID = var.m_val.lVal;
231  // for backward compatibility only.
232  else throw Tools::IllegalArgumentException("MVRTree: Property IndexIdentifier must be Tools::VT_LONGLONG");
233 
234  initOld(ps);
235  }
236  else
237  {
238  initNew(ps);
240  var.m_val.llVal = m_headerID;
241  ps.setProperty("IndexIdentifier", var);
242  }
243 }
244 
246 {
247  storeHeader();
248 }
249 
250 //
251 // ISpatialIndex interface
252 //
253 
254 void SpatialIndex::MVRTree::MVRTree::insertData(uint32_t len, const uint8_t* pData, const IShape& shape, id_type id)
255 {
256  if (shape.getDimension() != m_dimension) throw Tools::IllegalArgumentException("insertData: Shape has the wrong number of dimensions.");
257  const Tools::IInterval* ti = dynamic_cast<const Tools::IInterval*>(&shape);
258  if (ti == nullptr) throw Tools::IllegalArgumentException("insertData: Shape does not support the Tools::IInterval interface.");
259  if (ti->getLowerBound() < m_currentTime) throw Tools::IllegalArgumentException("insertData: Shape start time is older than tree current time.");
260 
261  // convert the shape into a TimeRegion (R-Trees index regions only; i.e., approximations of the shapes).
262  Region mbrold;
263  shape.getMBR(mbrold);
264 
265  TimeRegionPtr mbr = m_regionPool.acquire();
266  mbr->makeDimension(mbrold.m_dimension);
267 
268  memcpy(mbr->m_pLow, mbrold.m_pLow, mbrold.m_dimension * sizeof(double));
269  memcpy(mbr->m_pHigh, mbrold.m_pHigh, mbrold.m_dimension * sizeof(double));
270  mbr->m_startTime = ti->getLowerBound();
271  mbr->m_endTime = std::numeric_limits<double>::max();
272 
273  uint8_t* buffer = nullptr;
274 
275  if (len > 0)
276  {
277  buffer = new uint8_t[len];
278  memcpy(buffer, pData, len);
279  }
280 
281  insertData_impl(len, buffer, *mbr, id);
282  // the buffer is stored in the tree. Do not delete here.
283 }
284 
286 {
287  if (shape.getDimension() != m_dimension) throw Tools::IllegalArgumentException("deleteData: Shape has the wrong number of dimensions.");
288  const Tools::IInterval* ti = dynamic_cast<const Tools::IInterval*>(&shape);
289  if (ti == nullptr) throw Tools::IllegalArgumentException("deleteData: Shape does not support the Tools::IInterval interface.");
290 
291  Region mbrold;
292  shape.getMBR(mbrold);
293 
294  TimeRegionPtr mbr = m_regionPool.acquire();
295  mbr->makeDimension(mbrold.m_dimension);
296 
297  memcpy(mbr->m_pLow, mbrold.m_pLow, mbrold.m_dimension * sizeof(double));
298  memcpy(mbr->m_pHigh, mbrold.m_pHigh, mbrold.m_dimension * sizeof(double));
299  mbr->m_startTime = ti->getLowerBound();
300  mbr->m_endTime = ti->getUpperBound();
301 
302  bool ret = deleteData_impl(*mbr, id);
303 
304  return ret;
305 }
306 
307 
309 {
310  throw Tools::IllegalStateException("internalNodesQuery: not implemented yet.");
311 }
312 
314 {
315  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("containsWhatQuery: Shape has the wrong number of dimensions.");
316  rangeQuery(ContainmentQuery, query, v);
317 }
318 
320 {
321  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("intersectsWithQuery: Shape has the wrong number of dimensions.");
322  rangeQuery(IntersectionQuery, query, v);
323 }
324 
326 {
327  if (query.m_dimension != m_dimension) throw Tools::IllegalArgumentException("pointLocationQuery: Shape has the wrong number of dimensions.");
328  const Tools::IInterval* ti = dynamic_cast<const Tools::IInterval*>(&query);
329  if (ti == nullptr) throw Tools::IllegalArgumentException("pointLocationQuery: Shape does not support the Tools::IInterval interface.");
330  TimeRegion r(query, query, *ti);
331  rangeQuery(IntersectionQuery, r, v);
332 }
333 
335 {
336  throw Tools::IllegalStateException("nearestNeighborQuery: not implemented yet.");
337 }
338 
339 double SpatialIndex::MVRTree::MVRTree::nearestNeighborQuery(uint32_t k, const IShape& query, IVisitor& v, double max_dist)
340 {
341  if (query.getDimension() != m_dimension) throw Tools::IllegalArgumentException("nearestNeighborQuery: Shape has the wrong number of dimensions.");
342  NNComparator nnc;
343  return nearestNeighborQuery(k, query, v, nnc, max_dist);
344 }
345 
347 {
348  throw Tools::IllegalStateException("selfJoinQuery: not implemented yet.");
349 }
350 
352 {
353  id_type next = m_roots[m_roots.size() - 1].m_id;
354  bool hasNext = true;
355 
356  while (hasNext)
357  {
358  NodePtr n = readNode(next);
359  qs.getNextEntry(*n, next, hasNext);
360  }
361 }
362 
364 {
365  Tools::Variant var;
366 
367  // dimension
369  var.m_val.ulVal = m_dimension;
370  out.setProperty("Dimension", var);
371 
372  // index capacity
374  var.m_val.ulVal = m_indexCapacity;
375  out.setProperty("IndexCapacity", var);
376 
377  // leaf capacity
379  var.m_val.ulVal = m_leafCapacity;
380  out.setProperty("LeafCapacity", var);
381 
382  // Tree variant
384  var.m_val.lVal = m_treeVariant;
385  out.setProperty("TreeVariant", var);
386 
387  // fill factor
389  var.m_val.dblVal = m_fillFactor;
390  out.setProperty("FillFactor", var);
391 
392  // near minimum overlap factor
394  var.m_val.ulVal = m_nearMinimumOverlapFactor;
395  out.setProperty("NearMinimumOverlapFactor", var);
396 
397  // split distribution factor
399  var.m_val.dblVal = m_splitDistributionFactor;
400  out.setProperty("SplitDistributionFactor", var);
401 
402  // reinsert factor
404  var.m_val.dblVal = m_reinsertFactor;
405  out.setProperty("ReinsertFactor", var);
406 
407  // tight MBRs
409  var.m_val.blVal = m_bTightMBRs;
410  out.setProperty("EnsureTightMBRs", var);
411 
412  // index pool capacity
414  var.m_val.ulVal = m_indexPool.getCapacity();
415  out.setProperty("IndexPoolCapacity", var);
416 
417  // leaf pool capacity
419  var.m_val.ulVal = m_leafPool.getCapacity();
420  out.setProperty("LeafPoolCapacity", var);
421 
422  // region pool capacity
424  var.m_val.ulVal = m_regionPool.getCapacity();
425  out.setProperty("RegionPoolCapacity", var);
426 
427  // point pool capacity
429  var.m_val.ulVal = m_pointPool.getCapacity();
430  out.setProperty("PointPoolCapacity", var);
431 
432  // strong version overflow
434  var.m_val.dblVal = m_strongVersionOverflow;
435  out.setProperty("StrongVersionOverflow", var);
436 
437  // strong version underflow
438  //var.m_varType = Tools::VT_DOUBLE;
439  //var.m_val.dblVal = m_strongVersionUnderflow;
440  //out.setProperty("StrongVersionUnderflow", var);
441 
442  // weak version underflow
444  var.m_val.dblVal = m_versionUnderflow;
445  out.setProperty("VersionUnderflow", var);
446 
448  var.m_val.llVal = m_headerID;
449  out.setProperty("IndexIdentifier", var);
450 }
451 
453 {
454  switch (ct)
455  {
456  case CT_NODEREAD:
457  m_readNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
458  break;
459  case CT_NODEWRITE:
460  m_writeNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
461  break;
462  case CT_NODEDELETE:
463  m_deleteNodeCommands.push_back(std::shared_ptr<ICommand>(pCommand));
464  break;
465  }
466 }
467 
469 {
470  bool ret = true;
471  std::stack<ValidateEntry> st;
472  std::set<id_type> visitedEntries;
473 #if SI_DEBUG_OUTPUT
474  uint32_t degenerateEntries = 0;
475 #endif
476 
477  for (uint32_t cRoot = 0; cRoot < m_roots.size(); ++cRoot)
478  {
479  NodePtr root = readNode(m_roots[cRoot].m_id);
480 
481  if (root->m_level != m_stats.m_treeHeight[cRoot] - 1)
482  {
483  std::cerr << "Invalid tree height." << std::endl;
484  return false;
485  }
486 
487  ValidateEntry e(0, root->m_nodeMBR, root);
488  e.m_bIsDead = (root->m_nodeMBR.m_endTime < std::numeric_limits<double>::max()) ? true : false;
489  st.push(e);
490  }
491 
492  while (! st.empty())
493  {
494  ValidateEntry e = st.top(); st.pop();
495 
496  std::set<id_type>::iterator itSet = visitedEntries.find(e.m_pNode->m_identifier);
497  if (itSet == visitedEntries.end())
498  {
499  visitedEntries.insert(e.m_pNode->m_identifier);
500 #if SI_DEBUG_OUTPUT
501  if (e.m_pNode->m_nodeMBR.m_startTime == e.m_pNode->m_nodeMBR.m_endTime) ++degenerateEntries;
502 # endif
503  }
504 
505  TimeRegion tmpRegion;
506  tmpRegion = m_infiniteRegion;
507 
508  for (uint32_t cDim = 0; cDim < tmpRegion.m_dimension; ++cDim)
509  {
510  for (uint32_t cChild = 0; cChild < e.m_pNode->m_children; ++cChild)
511  {
512  tmpRegion.m_pLow[cDim] = std::min(tmpRegion.m_pLow[cDim], e.m_pNode->m_ptrMBR[cChild]->m_pLow[cDim]);
513  tmpRegion.m_pHigh[cDim] = std::max(tmpRegion.m_pHigh[cDim], e.m_pNode->m_ptrMBR[cChild]->m_pHigh[cDim]);
514  }
515  }
516 
517  tmpRegion.m_startTime = e.m_pNode->m_nodeMBR.m_startTime;
518  tmpRegion.m_endTime = e.m_pNode->m_nodeMBR.m_endTime;
519  if (! (tmpRegion == e.m_pNode->m_nodeMBR))
520  {
521  std::cerr << "Invalid parent information." << std::endl;
522  ret = false;
523  }
524 
525  if (! e.m_bIsDead)
526  {
527  tmpRegion.m_startTime = e.m_parentMBR.m_startTime;
528  tmpRegion.m_endTime = e.m_parentMBR.m_endTime;
529  if (! (tmpRegion == e.m_parentMBR))
530  {
531  std::cerr << "Error in parent (Node id: " << e.m_pNode->m_identifier << ", Parent id: " << e.m_parentID << ")." << std::endl;
532  ret = false;
533  }
534  }
535 
536  if (e.m_pNode->m_level != 0)
537  {
538  for (uint32_t cChild = 0; cChild < e.m_pNode->m_children; ++cChild)
539  {
540  NodePtr ptrN = readNode(e.m_pNode->m_pIdentifier[cChild]);
541 
542  bool bIsDead =
543  (e.m_pNode->m_ptrMBR[cChild]->m_endTime < std::numeric_limits<double>::max() || e.m_bIsDead) ? true : false;
544 
545  // if the parent says that this child is dead, force it dead since
546  // this information is not propagated for efficiency and is inconsistent.
547  if (bIsDead) ptrN->m_nodeMBR.m_endTime = e.m_pNode->m_ptrMBR[cChild]->m_endTime;
548 
549  ValidateEntry tmpEntry(e.m_pNode->m_identifier, *(e.m_pNode->m_ptrMBR[cChild]), ptrN);
550  tmpEntry.m_bIsDead = bIsDead;
551  st.push(tmpEntry);
552  }
553  }
554  }
555 
556 #if SI_DEBUG_OUTPUT
557  std::cerr << "Total accessible nodes: " << visitedEntries.size() << std::endl;
558  std::cerr << "Degenerate nodes: " << degenerateEntries << std::endl;
559 #endif
560 
561  return ret;
562 }
563 
565 {
566  *out = new Statistics(m_stats);
567 }
568 
570 {
571  storeHeader();
572 }
573 
574 void SpatialIndex::MVRTree::MVRTree::initNew(Tools::PropertySet& ps)
575 {
576  Tools::Variant var;
577 
578  // tree variant
579  var = ps.getProperty("TreeVariant");
580  if (var.m_varType != Tools::VT_EMPTY)
581  {
582  if (var.m_varType != Tools::VT_LONG || (var.m_val.lVal != RV_LINEAR && var.m_val.lVal != RV_QUADRATIC && var.m_val.lVal != RV_RSTAR))
583  throw Tools::IllegalArgumentException("initNew: Property TreeVariant must be Tools::VT_LONG and of MVRTreeVariant type");
584 
585  m_treeVariant = static_cast<MVRTreeVariant>(var.m_val.lVal);
586  }
587 
588  // fill factor
589  // it cannot be larger than 50%, since linear and quadratic split algorithms
590  // require assigning to both nodes the same number of entries.
591  var = ps.getProperty("FillFactor");
592  if (var.m_varType != Tools::VT_EMPTY)
593  {
594  if (
595  var.m_varType != Tools::VT_DOUBLE ||
596  var.m_val.dblVal <= 0.0 ||
597  //((m_treeVariant == RV_LINEAR || m_treeVariant == RV_QUADRATIC) && var.m_val.dblVal > 0.5) ||
598  var.m_val.dblVal >= 1.0)
599  throw Tools::IllegalArgumentException("initNew: Property FillFactor must be Tools::VT_DOUBLE and in (0.0, 1.0) for RSTAR, (0.0, 0.5) for LINEAR and QUADRATIC");
600 
601  m_fillFactor = var.m_val.dblVal;
602  }
603 
604  // index capacity
605  var = ps.getProperty("IndexCapacity");
606  if (var.m_varType != Tools::VT_EMPTY)
607  {
608  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 10)
609  throw Tools::IllegalArgumentException("initNew: Property IndexCapacity must be Tools::VT_ULONG and >= 10");
610 
611  m_indexCapacity = var.m_val.ulVal;
612  }
613 
614  // leaf capacity
615  var = ps.getProperty("LeafCapacity");
616  if (var.m_varType != Tools::VT_EMPTY)
617  {
618  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 10)
619  throw Tools::IllegalArgumentException("initNew: Property LeafCapacity must be Tools::VT_ULONG and >= 10");
620 
621  m_leafCapacity = var.m_val.ulVal;
622  }
623 
624  // near minimum overlap factor
625  var = ps.getProperty("NearMinimumOverlapFactor");
626  if (var.m_varType != Tools::VT_EMPTY)
627  {
628  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 1 || var.m_val.ulVal > m_indexCapacity || var.m_val.ulVal > m_leafCapacity)
629  throw Tools::IllegalArgumentException("initNew: Property NearMinimumOverlapFactor must be Tools::VT_ULONG and less than both index and leaf capacities");
630 
631  m_nearMinimumOverlapFactor = var.m_val.ulVal;
632  }
633 
634  // split distribution factor
635  var = ps.getProperty("SplitDistributionFactor");
636  if (var.m_varType != Tools::VT_EMPTY)
637  {
638  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
639  throw Tools::IllegalArgumentException("initNew: Property SplitDistributionFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
640 
641  m_splitDistributionFactor = var.m_val.dblVal;
642  }
643 
644  // reinsert factor
645  var = ps.getProperty("ReinsertFactor");
646  if (var.m_varType != Tools::VT_EMPTY)
647  {
648  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
649  throw Tools::IllegalArgumentException("initNew: Property ReinsertFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
650 
651  m_reinsertFactor = var.m_val.dblVal;
652  }
653 
654  // dimension
655  var = ps.getProperty("Dimension");
656  if (var.m_varType != Tools::VT_EMPTY)
657  {
658  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property Dimension must be Tools::VT_ULONG");
659  if (var.m_val.ulVal <= 1) throw Tools::IllegalArgumentException("initNew: Property Dimension must be greater than 1");
660 
661  m_dimension = var.m_val.ulVal;
662  }
663 
664  // tight MBRs
665  var = ps.getProperty("EnsureTightMBRs");
666  if (var.m_varType != Tools::VT_EMPTY)
667  {
668  if (var.m_varType != Tools::VT_BOOL) throw Tools::IllegalArgumentException("initNew: Property EnsureTightMBRs must be Tools::VT_BOOL");
669 
670  m_bTightMBRs = var.m_val.blVal;
671  }
672 
673  // index pool capacity
674  var = ps.getProperty("IndexPoolCapacity");
675  if (var.m_varType != Tools::VT_EMPTY)
676  {
677  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property IndexPoolCapacity must be Tools::VT_ULONG");
678 
679  m_indexPool.setCapacity(var.m_val.ulVal);
680  }
681 
682  // leaf pool capacity
683  var = ps.getProperty("LeafPoolCapacity");
684  if (var.m_varType != Tools::VT_EMPTY)
685  {
686  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property LeafPoolCapacity must be Tools::VT_ULONG");
687 
688  m_leafPool.setCapacity(var.m_val.ulVal);
689  }
690 
691  // region pool capacity
692  var = ps.getProperty("RegionPoolCapacity");
693  if (var.m_varType != Tools::VT_EMPTY)
694  {
695  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property RegionPoolCapacity must be Tools::VT_ULONG");
696 
697  m_regionPool.setCapacity(var.m_val.ulVal);
698  }
699 
700  // point pool capacity
701  var = ps.getProperty("PointPoolCapacity");
702  if (var.m_varType != Tools::VT_EMPTY)
703  {
704  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initNew: Property PointPoolCapacity must be Tools::VT_ULONG");
705 
706  m_pointPool.setCapacity(var.m_val.ulVal);
707  }
708 
709  // strong version overflow
710  var = ps.getProperty("StrongVersionOverflow");
711  if (var.m_varType != Tools::VT_EMPTY)
712  {
713  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
714  throw Tools::IllegalArgumentException("initNew: Property StrongVersionOverflow must be Tools::VT_DOUBLE and in (0.0, 1.0)");
715 
716  m_strongVersionOverflow = var.m_val.dblVal;
717  }
718 
719  // strong version underflow
720  //var = ps.getProperty("StrongVersionUnderflow");
721  //if (var.m_varType != Tools::VT_EMPTY)
722  //{
723  // if (var.m_varType != Tools::VT_DOUBLE ||
724  // var.m_val.dblVal <= 0.0 ||
725  // var.m_val.dblVal >= 1.0) throw Tools::IllegalArgumentException("Property StrongVersionUnderflow must be Tools::VT_DOUBLE and in (0.0, 1.0)");
726 
727  // m_strongVersionUnderflow = var.m_val.dblVal;
728  //}
729 
730  // weak version underflow
731  var = ps.getProperty("VersionUnderflow");
732  if (var.m_varType != Tools::VT_EMPTY)
733  {
734  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
735  throw Tools::IllegalArgumentException("initNew: Property VersionUnderflow must be Tools::VT_DOUBLE and in (0.0, 1.0)");
736 
737  m_versionUnderflow = var.m_val.dblVal;
738  }
739 
740  m_infiniteRegion.makeInfinite(m_dimension);
741 
742  m_stats.m_treeHeight.push_back(1);
743  m_stats.m_nodesInLevel.push_back(1);
744 
745  Leaf root(this, -1);
746  root.m_nodeMBR.m_startTime = 0.0;
747  root.m_nodeMBR.m_endTime = std::numeric_limits<double>::max();
748  writeNode(&root);
749  m_roots.emplace_back(root.m_identifier, root.m_nodeMBR.m_startTime, root.m_nodeMBR.m_endTime);
750 
751  storeHeader();
752 }
753 
754 void SpatialIndex::MVRTree::MVRTree::initOld(Tools::PropertySet& ps)
755 {
756  loadHeader();
757 
758  // only some of the properties may be changed.
759  // the rest are just ignored.
760 
761  Tools::Variant var;
762 
763  // tree variant
764  var = ps.getProperty("TreeVariant");
765  if (var.m_varType != Tools::VT_EMPTY)
766  {
767  if (var.m_varType != Tools::VT_LONG || (var.m_val.lVal != RV_LINEAR && var.m_val.lVal != RV_QUADRATIC && var.m_val.lVal != RV_RSTAR))
768  throw Tools::IllegalArgumentException("initOld: Property TreeVariant must be Tools::VT_LONG and of MVRTreeVariant type");
769 
770  m_treeVariant = static_cast<MVRTreeVariant>(var.m_val.lVal);
771  }
772 
773  // near minimum overlap factor
774  var = ps.getProperty("NearMinimumOverlapFactor");
775  if (var.m_varType != Tools::VT_EMPTY)
776  {
777  if (var.m_varType != Tools::VT_ULONG || var.m_val.ulVal < 1 || var.m_val.ulVal > m_indexCapacity || var.m_val.ulVal > m_leafCapacity)
778  throw Tools::IllegalArgumentException("initOld: Property NearMinimumOverlapFactor must be Tools::VT_ULONG and less than both index and leaf capacities");
779 
780  m_nearMinimumOverlapFactor = var.m_val.ulVal;
781  }
782 
783  // split distribution factor
784  var = ps.getProperty("SplitDistributionFactor");
785  if (var.m_varType != Tools::VT_EMPTY)
786  {
787  if (var.m_varType != Tools::VT_DOUBLE || var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
788  throw Tools::IllegalArgumentException("initOld: Property SplitDistributionFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
789 
790  m_splitDistributionFactor = var.m_val.dblVal;
791  }
792 
793  // reinsert factor
794  var = ps.getProperty("ReinsertFactor");
795  if (var.m_varType != Tools::VT_EMPTY)
796  {
797  if (var.m_varType != Tools::VT_DOUBLE ||var.m_val.dblVal <= 0.0 || var.m_val.dblVal >= 1.0)
798  throw Tools::IllegalArgumentException("initOld: Property ReinsertFactor must be Tools::VT_DOUBLE and in (0.0, 1.0)");
799 
800  m_reinsertFactor = var.m_val.dblVal;
801  }
802 
803  // tight MBRs
804  var = ps.getProperty("EnsureTightMBRs");
805  if (var.m_varType != Tools::VT_EMPTY)
806  {
807  if (var.m_varType != Tools::VT_BOOL) throw Tools::IllegalArgumentException("initOld: Property EnsureTightMBRs must be Tools::VT_BOOL");
808 
809  m_bTightMBRs = var.m_val.blVal;
810  }
811 
812  // index pool capacity
813  var = ps.getProperty("IndexPoolCapacity");
814  if (var.m_varType != Tools::VT_EMPTY)
815  {
816  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property IndexPoolCapacity must be Tools::VT_ULONG");
817 
818  m_indexPool.setCapacity(var.m_val.ulVal);
819  }
820 
821  // leaf pool capacity
822  var = ps.getProperty("LeafPoolCapacity");
823  if (var.m_varType != Tools::VT_EMPTY)
824  {
825  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property LeafPoolCapacity must be Tools::VT_ULONG");
826 
827  m_leafPool.setCapacity(var.m_val.ulVal);
828  }
829 
830  // region pool capacity
831  var = ps.getProperty("RegionPoolCapacity");
832  if (var.m_varType != Tools::VT_EMPTY)
833  {
834  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property RegionPoolCapacity must be Tools::VT_ULONG");
835 
836  m_regionPool.setCapacity(var.m_val.ulVal);
837  }
838 
839  // point pool capacity
840  var = ps.getProperty("PointPoolCapacity");
841  if (var.m_varType != Tools::VT_EMPTY)
842  {
843  if (var.m_varType != Tools::VT_ULONG) throw Tools::IllegalArgumentException("initOld: Property PointPoolCapacity must be Tools::VT_ULONG");
844 
845  m_pointPool.setCapacity(var.m_val.ulVal);
846  }
847 
848  m_infiniteRegion.makeInfinite(m_dimension);
849 }
850 
851 void SpatialIndex::MVRTree::MVRTree::storeHeader()
852 {
853  const uint32_t headerSize =
854  sizeof(uint32_t) + // size of m_roots
855  static_cast<uint32_t>(m_roots.size())
856  * (sizeof(id_type) + 2 * sizeof(double)) + // m_roots
857  sizeof(MVRTreeVariant) + // m_treeVariant
858  sizeof(double)+ // m_fillFactor
859  sizeof(uint32_t) + // m_indexCapacity
860  sizeof(uint32_t) + // m_leafCapacity
861  sizeof(uint32_t) + // m_nearMinimumOverlapFactor
862  sizeof(double) + // m_splitDistributionFactor
863  sizeof(double) + // m_reinsertFactor
864  sizeof(uint32_t) + // m_dimension
865  sizeof(uint8_t) + // m_bTightMBRs
866  sizeof(uint32_t) + // m_stats.m_nodes
867  sizeof(uint64_t) + // m_stats.m_totalData
868  sizeof(uint32_t) + // m_stats.m_deadIndexNodes
869  sizeof(uint32_t) + // m_stats.m_deadLeafNodes
870  sizeof(uint64_t) + // m_stats.m_data
871  sizeof(uint32_t) + // size of m_stats.m_treeHeight
872  static_cast<uint32_t>(m_stats.m_treeHeight.size())
873  * sizeof(uint32_t) + // m_stats.m_treeHeight
874  sizeof(double) + // m_strongVersionOverflow
875  //sizeof(double) + // m_strongVersionUnderflow
876  sizeof(double) + // m_versionUnderflow
877  sizeof(double) + // m_currentTime
878  sizeof(uint32_t) + // m_nodesInLevel size
879  static_cast<uint32_t>(m_stats.m_nodesInLevel.size())
880  * sizeof(uint32_t); // m_nodesInLevel values
881 
882  uint8_t* header = new uint8_t[headerSize];
883  uint8_t* ptr = header;
884 
885  uint32_t u32I = static_cast<uint32_t>(m_roots.size());
886  memcpy(ptr, &u32I, sizeof(uint32_t));
887  ptr += sizeof(uint32_t);
888 
889  for (size_t cIndex = 0; cIndex < m_roots.size(); ++cIndex)
890  {
891  RootEntry& e = m_roots[cIndex];
892  memcpy(ptr, &(e.m_id), sizeof(id_type));
893  ptr += sizeof(id_type);
894  memcpy(ptr, &(e.m_startTime), sizeof(double));
895  ptr += sizeof(double);
896  memcpy(ptr, &(e.m_endTime), sizeof(double));
897  ptr += sizeof(double);
898  }
899 
900  memcpy(ptr, &m_treeVariant, sizeof(MVRTreeVariant));
901  ptr += sizeof(MVRTreeVariant);
902  memcpy(ptr, &m_fillFactor, sizeof(double));
903  ptr += sizeof(double);
904  memcpy(ptr, &m_indexCapacity, sizeof(uint32_t));
905  ptr += sizeof(uint32_t);
906  memcpy(ptr, &m_leafCapacity, sizeof(uint32_t));
907  ptr += sizeof(uint32_t);
908  memcpy(ptr, &m_nearMinimumOverlapFactor, sizeof(uint32_t));
909  ptr += sizeof(uint32_t);
910  memcpy(ptr, &m_splitDistributionFactor, sizeof(double));
911  ptr += sizeof(double);
912  memcpy(ptr, &m_reinsertFactor, sizeof(double));
913  ptr += sizeof(double);
914  memcpy(ptr, &m_dimension, sizeof(uint32_t));
915  ptr += sizeof(uint32_t);
916  uint8_t c = (uint8_t) m_bTightMBRs;
917  memcpy(ptr, &c, sizeof(uint8_t));
918  ptr += sizeof(uint8_t);
919  memcpy(ptr, &(m_stats.m_u32Nodes), sizeof(uint32_t));
920  ptr += sizeof(uint32_t);
921  memcpy(ptr, &(m_stats.m_u64TotalData), sizeof(uint64_t));
922  ptr += sizeof(uint64_t);
923  memcpy(ptr, &(m_stats.m_u32DeadIndexNodes), sizeof(uint32_t));
924  ptr += sizeof(uint32_t);
925  memcpy(ptr, &(m_stats.m_u32DeadLeafNodes), sizeof(uint32_t));
926  ptr += sizeof(uint32_t);
927  memcpy(ptr, &(m_stats.m_u64Data), sizeof(uint64_t));
928  ptr += sizeof(uint64_t);
929 
930  u32I = static_cast<uint32_t>(m_stats.m_treeHeight.size());
931  memcpy(ptr, &u32I, sizeof(uint32_t));
932  ptr += sizeof(uint32_t);
933 
934  for (size_t cIndex = 0; cIndex < m_stats.m_treeHeight.size(); ++cIndex)
935  {
936  u32I = m_stats.m_treeHeight[cIndex];
937  memcpy(ptr, &u32I, sizeof(uint32_t));
938  ptr += sizeof(uint32_t);
939  }
940 
941  memcpy(ptr, &m_strongVersionOverflow, sizeof(double));
942  ptr += sizeof(double);
943  //memcpy(ptr, &m_strongVersionUnderflow, sizeof(double));
944  //ptr += sizeof(double);
945  memcpy(ptr, &m_versionUnderflow, sizeof(double));
946  ptr += sizeof(double);
947  memcpy(ptr, &m_currentTime, sizeof(double));
948  ptr += sizeof(double);
949 
950  u32I = static_cast<uint32_t>(m_stats.m_nodesInLevel.size());
951  memcpy(ptr, &u32I, sizeof(uint32_t));
952  ptr += sizeof(uint32_t);
953 
954  for (size_t cLevel = 0; cLevel < m_stats.m_nodesInLevel.size(); ++cLevel)
955  {
956  u32I = m_stats.m_nodesInLevel[cLevel];
957  memcpy(ptr, &u32I, sizeof(uint32_t));
958  ptr += sizeof(uint32_t);
959  }
960 
961  m_pStorageManager->storeByteArray(m_headerID, headerSize, header);
962 
963  delete[] header;
964 }
965 
966 void SpatialIndex::MVRTree::MVRTree::loadHeader()
967 {
968  uint32_t headerSize;
969  uint8_t* header = nullptr;
970  m_pStorageManager->loadByteArray(m_headerID, headerSize, &header);
971 
972  uint8_t* ptr = header;
973 
974  uint32_t rootsSize;
975  memcpy(&rootsSize, ptr, sizeof(uint32_t));
976  ptr += sizeof(uint32_t);
977 
978  for (uint32_t cIndex = 0; cIndex < rootsSize; ++cIndex)
979  {
980  RootEntry e;
981  memcpy(&(e.m_id), ptr, sizeof(id_type));
982  ptr += sizeof(id_type);
983  memcpy(&(e.m_startTime), ptr, sizeof(double));
984  ptr += sizeof(double);
985  memcpy(&(e.m_endTime), ptr, sizeof(double));
986  ptr += sizeof(double);
987  m_roots.push_back(e);
988  }
989 
990  memcpy(&m_treeVariant, ptr, sizeof(MVRTreeVariant));
991  ptr += sizeof(MVRTreeVariant);
992  memcpy(&m_fillFactor, ptr, sizeof(double));
993  ptr += sizeof(double);
994  memcpy(&m_indexCapacity, ptr, sizeof(uint32_t));
995  ptr += sizeof(uint32_t);
996  memcpy(&m_leafCapacity, ptr, sizeof(uint32_t));
997  ptr += sizeof(uint32_t);
998  memcpy(&m_nearMinimumOverlapFactor, ptr, sizeof(uint32_t));
999  ptr += sizeof(uint32_t);
1000  memcpy(&m_splitDistributionFactor, ptr, sizeof(double));
1001  ptr += sizeof(double);
1002  memcpy(&m_reinsertFactor, ptr, sizeof(double));
1003  ptr += sizeof(double);
1004  memcpy(&m_dimension, ptr, sizeof(uint32_t));
1005  ptr += sizeof(uint32_t);
1006  uint8_t c;
1007  memcpy(&c, ptr, sizeof(uint8_t));
1008  m_bTightMBRs = (c != 0);
1009  ptr += sizeof(uint8_t);
1010  memcpy(&(m_stats.m_u32Nodes), ptr, sizeof(uint32_t));
1011  ptr += sizeof(uint32_t);
1012  memcpy(&(m_stats.m_u64TotalData), ptr, sizeof(uint64_t));
1013  ptr += sizeof(uint64_t);
1014  memcpy(&(m_stats.m_u32DeadIndexNodes), ptr, sizeof(uint32_t));
1015  ptr += sizeof(uint32_t);
1016  memcpy(&(m_stats.m_u32DeadLeafNodes), ptr, sizeof(uint32_t));
1017  ptr += sizeof(uint32_t);
1018  memcpy(&(m_stats.m_u64Data), ptr, sizeof(uint64_t));
1019  ptr += sizeof(uint64_t);
1020 
1021  uint32_t treeHeightSize;
1022  memcpy(&treeHeightSize, ptr, sizeof(uint32_t));
1023  ptr += sizeof(uint32_t);
1024 
1025  for (uint32_t cIndex = 0; cIndex < treeHeightSize; ++cIndex)
1026  {
1027  uint32_t u32I;
1028  memcpy(&u32I, ptr, sizeof(uint32_t));
1029  m_stats.m_treeHeight.push_back(u32I);
1030  ptr += sizeof(uint32_t);
1031  }
1032 
1033  memcpy(&m_strongVersionOverflow, ptr, sizeof(double));
1034  ptr += sizeof(double);
1035  //memcpy(&m_strongVersionUnderflow, ptr, sizeof(double));
1036  //ptr += sizeof(double);
1037  memcpy(&m_versionUnderflow, ptr, sizeof(double));
1038  ptr += sizeof(double);
1039  memcpy(&m_currentTime, ptr, sizeof(double));
1040  ptr += sizeof(double);
1041 
1042  uint32_t nodesInLevelSize;
1043  memcpy(&nodesInLevelSize, ptr, sizeof(uint32_t));
1044  ptr += sizeof(uint32_t);
1045 
1046  for (uint32_t cLevel = 0; cLevel < nodesInLevelSize; ++cLevel)
1047  {
1048  uint32_t u32I;
1049  memcpy(&u32I, ptr, sizeof(uint32_t));
1050  ptr += sizeof(uint32_t);
1051  m_stats.m_nodesInLevel.push_back(u32I);
1052  }
1053 
1054  delete[] header;
1055 }
1056 
1057 void SpatialIndex::MVRTree::MVRTree::insertData_impl(uint32_t dataLength, uint8_t* pData, TimeRegion& mbr, id_type id)
1058 {
1059  assert(mbr.getDimension() == m_dimension);
1060  assert(m_currentTime <= mbr.m_startTime);
1061 
1062  std::stack<id_type> pathBuffer;
1063  m_currentTime = mbr.m_startTime;
1064 
1065  NodePtr root = readNode(m_roots[m_roots.size() - 1].m_id);
1066  NodePtr l = root->chooseSubtree(mbr, 0, pathBuffer);
1067 
1068  if (l.get() == root.get())
1069  {
1070  assert(root.unique());
1071  root.relinquish();
1072  }
1073  l->insertData(dataLength, pData, mbr, id, pathBuffer, m_infiniteRegion, -1, false);
1074 
1075  ++(m_stats.m_u64Data);
1076  ++(m_stats.m_u64TotalData);
1077 }
1078 
1079 void SpatialIndex::MVRTree::MVRTree::insertData_impl(uint32_t dataLength, uint8_t* pData, TimeRegion& mbr, id_type id, uint32_t level)
1080 {
1081  assert(mbr.getDimension() == m_dimension);
1082 
1083  std::stack<id_type> pathBuffer;
1084 
1085  NodePtr root = readNode(m_roots[m_roots.size() - 1].m_id);
1086  NodePtr l = root->chooseSubtree(mbr, level, pathBuffer);
1087 
1088  assert(l->m_level == level);
1089 
1090  if (l.get() == root.get())
1091  {
1092  assert(root.unique());
1093  root.relinquish();
1094  }
1095  l->insertData(dataLength, pData, mbr, id, pathBuffer, m_infiniteRegion, -1, false);
1096 }
1097 
1098 bool SpatialIndex::MVRTree::MVRTree::deleteData_impl(const TimeRegion& mbr, id_type id)
1099 {
1100  assert(mbr.m_dimension == m_dimension);
1101 
1102  m_currentTime = mbr.m_endTime;
1103 
1104  std::stack<id_type> pathBuffer;
1105  NodePtr root = readNode(m_roots[m_roots.size() - 1].m_id);
1106  NodePtr l = root->findLeaf(mbr, id, pathBuffer);
1107 
1108  if (l.get() == root.get())
1109  {
1110  assert(root.unique());
1111  root.relinquish();
1112  }
1113 
1114  if (l.get() != nullptr)
1115  {
1116  l->deleteData(id, mbr.m_endTime, pathBuffer);
1117  --(m_stats.m_u64Data);
1118  return true;
1119  }
1120 
1121  return false;
1122 }
1123 
1124 SpatialIndex::id_type SpatialIndex::MVRTree::MVRTree::writeNode(Node* n)
1125 {
1126  uint8_t* buffer;
1127  uint32_t dataLength;
1128  n->storeToByteArray(&buffer, dataLength);
1129 
1130  id_type page;
1131  if (n->m_identifier < 0) page = StorageManager::NewPage;
1132  else page = n->m_identifier;
1133 
1134  try
1135  {
1136  m_pStorageManager->storeByteArray(page, dataLength, buffer);
1137  delete[] buffer;
1138  }
1139  catch (InvalidPageException& e)
1140  {
1141  delete[] buffer;
1142  std::cerr << e.what() << std::endl;
1143  //std::cerr << *this << std::endl;
1144  throw Tools::IllegalStateException("writeNode: failed with Tools::InvalidPageException");
1145  }
1146 
1147  if (n->m_identifier < 0)
1148  {
1149  n->m_identifier = page;
1150  ++(m_stats.m_u32Nodes);
1151  }
1152 
1153  ++(m_stats.m_u64Writes);
1154 
1155  for (size_t cIndex = 0; cIndex < m_writeNodeCommands.size(); ++cIndex)
1156  {
1157  m_writeNodeCommands[cIndex]->execute(*n);
1158  }
1159 
1160  return page;
1161 }
1162 
1163 SpatialIndex::MVRTree::NodePtr SpatialIndex::MVRTree::MVRTree::readNode(id_type id)
1164 {
1165  uint32_t dataLength;
1166  uint8_t* buffer;
1167 
1168  try
1169  {
1170  m_pStorageManager->loadByteArray(id, dataLength, &buffer);
1171  }
1172  catch (InvalidPageException& e)
1173  {
1174  std::cerr << e.what() << std::endl;
1175  //std::cerr << *this << std::endl;
1176  throw Tools::IllegalStateException("readNode: failed with Tools::InvalidPageException");
1177  }
1178 
1179  try
1180  {
1181  uint32_t nodeType;
1182  memcpy(&nodeType, buffer, sizeof(uint32_t));
1183 
1184  NodePtr n;
1185 
1186  if (nodeType == PersistentIndex) n = m_indexPool.acquire();
1187  else if (nodeType == PersistentLeaf) n = m_leafPool.acquire();
1188  else throw Tools::IllegalStateException("readNode: failed reading the correct node type information");
1189 
1190  if (n.get() == nullptr)
1191  {
1192  if (nodeType == PersistentIndex) n = NodePtr(new Index(this, -1, 0), &m_indexPool);
1193  else if (nodeType == PersistentLeaf) n = NodePtr(new Leaf(this, -1), &m_leafPool);
1194  }
1195 
1196  //n->m_pTree = this;
1197  n->m_identifier = id;
1198  n->loadFromByteArray(buffer);
1199 
1200  ++(m_stats.m_u64Reads);
1201 
1202  for (size_t cIndex = 0; cIndex < m_readNodeCommands.size(); ++cIndex)
1203  {
1204  m_readNodeCommands[cIndex]->execute(*n);
1205  }
1206 
1207  delete[] buffer;
1208  return n;
1209  }
1210  catch (...)
1211  {
1212  delete[] buffer;
1213  throw;
1214  }
1215 }
1216 
1217 void SpatialIndex::MVRTree::MVRTree::deleteNode(Node* n)
1218 {
1219  try
1220  {
1221  m_pStorageManager->deleteByteArray(n->m_identifier);
1222  }
1223  catch (InvalidPageException& e)
1224  {
1225  std::cerr << e.what() << std::endl;
1226  //std::cerr << *this << std::endl;
1227  throw Tools::IllegalStateException("deleteNode: failed with Tools::InvalidPageException");
1228  }
1229 
1230  --(m_stats.m_u32Nodes);
1231 
1232  for (size_t cIndex = 0; cIndex < m_deleteNodeCommands.size(); ++cIndex)
1233  {
1234  m_deleteNodeCommands[cIndex]->execute(*n);
1235  }
1236 }
1237 
1238 void SpatialIndex::MVRTree::MVRTree::rangeQuery(RangeQueryType type, const IShape& query, IVisitor& v)
1239 {
1240  // any shape that implements IInterval and IShape, can be used here.
1241  // FIXME: I am not using ITimeShape yet, even though I should.
1242 
1243  const Tools::IInterval* ti = dynamic_cast<const Tools::IInterval*>(&query);
1244  if (ti == nullptr) throw Tools::IllegalArgumentException("rangeQuery: Shape does not support the Tools::IInterval interface.");
1245 
1246  std::set<id_type> visitedNodes;
1247  std::set<id_type> visitedData;
1248  std::stack<NodePtr> st;
1249  std::vector<id_type> ids;
1250  findRootIdentifiers(*ti, ids);
1251 
1252  for (size_t cRoot = 0; cRoot < ids.size(); ++cRoot)
1253  {
1254  NodePtr root = readNode(ids[cRoot]);
1255  if (root->m_children > 0 && query.intersectsShape(root->m_nodeMBR)) st.push(root);
1256  }
1257 
1258  while (! st.empty())
1259  {
1260  NodePtr n = st.top(); st.pop();
1261  visitedNodes.insert(n->m_identifier);
1262 
1263  if (n->m_level == 0)
1264  {
1265  v.visitNode(*n);
1266 
1267  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1268  {
1269  if (visitedData.find(n->m_pIdentifier[cChild]) != visitedData.end()) continue;
1270 
1271  bool b;
1272  if (type == ContainmentQuery) b = (n->m_ptrMBR[cChild])->intersectsInterval(*ti) && query.containsShape(*(n->m_ptrMBR[cChild]));
1273  else b = (n->m_ptrMBR[cChild])->intersectsInterval(*ti) && query.intersectsShape(*(n->m_ptrMBR[cChild]));
1274 
1275  if (b)
1276  {
1277  visitedData.insert(n->m_pIdentifier[cChild]);
1278  Data data = Data(n->m_pDataLength[cChild], n->m_pData[cChild], *(n->m_ptrMBR[cChild]), n->m_pIdentifier[cChild]);
1279  v.visitData(data);
1280  ++(m_stats.m_u64QueryResults);
1281  }
1282  }
1283  }
1284  else
1285  {
1286  v.visitNode(*n);
1287 
1288  for (uint32_t cChild = 0; cChild < n->m_children; ++cChild)
1289  {
1290  if (
1291  visitedNodes.find(n->m_pIdentifier[cChild]) == visitedNodes.end() &&
1292  n->m_ptrMBR[cChild]->intersectsInterval(*ti) &&
1293  query.intersectsShape(*(n->m_ptrMBR[cChild])))
1294  st.push(readNode(n->m_pIdentifier[cChild]));
1295  }
1296  }
1297  }
1298 }
1299 
1300 void SpatialIndex::MVRTree::MVRTree::findRootIdentifiers(const Tools::IInterval& ti, std::vector<id_type>& ids)
1301 {
1302  ids.clear();
1303 
1304  for (size_t cRoot = 0; cRoot < m_roots.size(); ++cRoot)
1305  {
1306  RootEntry& e = m_roots[cRoot];
1307  if (ti.intersectsInterval(Tools::IT_RIGHTOPEN, e.m_startTime, e.m_endTime)) ids.push_back(e.m_id);
1308  }
1309 }
1310 
1311 std::string SpatialIndex::MVRTree::MVRTree::printRootInfo() const
1312 {
1313  std::ostringstream s;
1314 
1315  for (size_t cRoot = 0; cRoot < m_roots.size(); ++cRoot)
1316  {
1317  const RootEntry& e = m_roots[cRoot];
1318 
1319  s << "Root " << cRoot << ": Start " << e.m_startTime << ", End " << e.m_endTime << std::endl;
1320  }
1321 
1322  return s.str();
1323 }
1324 
1325 std::ostream& SpatialIndex::MVRTree::operator<<(std::ostream& os, const MVRTree& t)
1326 {
1327  os << "Dimension: " << t.m_dimension << std::endl
1328  << "Fill factor: " << t.m_fillFactor << std::endl
1329  << "Index capacity: " << t.m_indexCapacity << std::endl
1330  << "Leaf capacity: " << t.m_leafCapacity << std::endl
1331  << "Tight MBRs: " << ((t.m_bTightMBRs) ? "enabled" : "disabled") << std::endl;
1332 
1333  if (t.m_treeVariant == RV_RSTAR)
1334  {
1335  os << "Near minimum overlap factor: " << t.m_nearMinimumOverlapFactor << std::endl
1336  << "Reinsert factor: " << t.m_reinsertFactor << std::endl
1337  << "Split distribution factor: " << t.m_splitDistributionFactor << std::endl
1338  << "Strong version overflow: " << t.m_strongVersionOverflow << std::endl
1339  //<< "Strong version underflow: " << t.m_strongVersionUnderflow << std::endl
1340  << "Weak version underflow: " << t.m_versionUnderflow << std::endl;
1341  }
1342 
1343  // it is difficult to count utilization
1344  //os << "Utilization: " << 100 * t.m_stats.m_totalData / (t.m_stats.getNumberOfNodesInLevel(0) * t.m_leafCapacity) << "%" << std::endl
1345 
1346  os << t.m_stats;
1347  os << t.printRootInfo();
1348 
1349  return os;
1350 }
virtual void getNextEntry(const IEntry &previouslyFetched, id_type &nextEntryToFetch, bool &bFetchNextEntry)=0
virtual uint32_t getDimension() const =0
virtual void getMBR(Region &out) const =0
void getShape(IShape **out) const override
Definition: MVRTree.cc:69
void getData(uint32_t &len, uint8_t **data) const override
Definition: MVRTree.cc:74
id_type getIdentifier() const override
Definition: MVRTree.cc:64
Data(uint32_t len, uint8_t *pData, TimeRegion &r, id_type id)
Definition: MVRTree.cc:44
uint32_t getByteArraySize() override
Definition: MVRTree.cc:86
Data * clone() override
Definition: MVRTree.cc:59
void loadFromByteArray(const uint8_t *data) override
Definition: MVRTree.cc:95
void storeToByteArray(uint8_t **data, uint32_t &len) override
Definition: MVRTree.cc:116
virtual void pointLocationQuery(const Point &query, IVisitor &v)
Definition: MVRTree.cc:325
virtual void addCommand(ICommand *pCommand, CommandType ct)
Definition: MVRTree.cc:452
virtual void getIndexProperties(Tools::PropertySet &out) const
Definition: MVRTree.cc:363
virtual void queryStrategy(IQueryStrategy &qs)
Definition: MVRTree.cc:351
virtual void internalNodesQuery(const IShape &query, IVisitor &v)
Definition: MVRTree.cc:308
virtual double nearestNeighborQuery(uint32_t k, const IShape &query, IVisitor &v, INearestNeighborComparator &, double max_dist=0.0)
Definition: MVRTree.cc:334
virtual void getStatistics(IStatistics **out) const
Definition: MVRTree.cc:564
virtual void containsWhatQuery(const IShape &query, IVisitor &v)
Definition: MVRTree.cc:313
virtual void selfJoinQuery(const IShape &s, IVisitor &v)
Definition: MVRTree.cc:346
virtual bool deleteData(const IShape &shape, id_type id)
Definition: MVRTree.cc:285
MVRTree(IStorageManager &, Tools::PropertySet &)
Definition: MVRTree.cc:203
virtual void insertData(uint32_t len, const uint8_t *pData, const IShape &shape, id_type id)
Definition: MVRTree.cc:254
virtual void intersectsWithQuery(const IShape &query, IVisitor &v)
Definition: MVRTree.cc:319
virtual bool isIndexValid()
Definition: MVRTree.cc:468
void loadFromByteArray(const uint8_t *data) override
Definition: mvrtree/Node.cc:66
void storeToByteArray(uint8_t **data, uint32_t &len) override
uint32_t m_dimension
Definition: Point.h:79
double * m_pHigh
Definition: Region.h:101
uint32_t m_dimension
Definition: Region.h:99
double * m_pLow
Definition: Region.h:100
void makeDimension(uint32_t dimension) override
Definition: TimeRegion.cc:389
bool intersectsInterval(const Tools::IInterval &ti) const override
virtual double getLowerBound() const =0
virtual double getUpperBound() const =0
virtual bool intersectsInterval(const IInterval &) const =0
bool unique() const noexcept
Definition: PoolPointer.h:56
X * get() const noexcept
Definition: PoolPointer.h:55
void relinquish() noexcept
Definition: PoolPointer.h:57
void setProperty(std::string property, Variant const &v)
Definition: Tools.cc:354
Variant getProperty(std::string property) const
Definition: Tools.cc:346
int64_t llVal
Definition: Tools.h:283
uint32_t ulVal
Definition: Tools.h:289
bool blVal
Definition: Tools.h:291
union Tools::Variant::@0 m_val
int32_t lVal
Definition: Tools.h:282
double dblVal
Definition: Tools.h:286
VariantType m_varType
Definition: Tools.h:277
SIDX_DLL ISpatialIndex * createNewMVRTree(IStorageManager &in, double fillFactor, uint32_t indexCapacity, uint32_t leafCapacity, uint32_t dimension, MVRTreeVariant rv, id_type &out_indexIdentifier)
Definition: MVRTree.cc:150
SIDX_DLL ISpatialIndex * returnMVRTree(IStorageManager &ind, Tools::PropertySet &in)
Definition: MVRTree.cc:144
Tools::PoolPointer< Node > NodePtr
Definition: mvrtree/Node.h:40
SIDX_DLL ISpatialIndex * loadMVRTree(IStorageManager &in, id_type indexIdentifier)
Definition: MVRTree.cc:191
std::ostream & operator<<(std::ostream &os, const MVRTree &t)
Definition: MVRTree.cc:1325
int64_t id_type
Definition: SpatialIndex.h:41
@ IT_RIGHTOPEN
Definition: Tools.h:82
@ VT_BOOL
Definition: Tools.h:100
@ VT_EMPTY
Definition: Tools.h:103
@ VT_LONGLONG
Definition: Tools.h:104
@ VT_LONG
Definition: Tools.h:90
@ VT_DOUBLE
Definition: Tools.h:94
@ VT_ULONG
Definition: Tools.h:97