LSSTApplications  1.1.2+25,10.0+13,10.0+132,10.0+133,10.0+224,10.0+41,10.0+8,10.0-1-g0f53050+14,10.0-1-g4b7b172+19,10.0-1-g61a5bae+98,10.0-1-g7408a83+3,10.0-1-gc1e0f5a+19,10.0-1-gdb4482e+14,10.0-11-g3947115+2,10.0-12-g8719d8b+2,10.0-15-ga3f480f+1,10.0-2-g4f67435,10.0-2-gcb4bc6c+26,10.0-28-gf7f57a9+1,10.0-3-g1bbe32c+14,10.0-3-g5b46d21,10.0-4-g027f45f+5,10.0-4-g86f66b5+2,10.0-4-gc4fccf3+24,10.0-40-g4349866+2,10.0-5-g766159b,10.0-5-gca2295e+25,10.0-6-g462a451+1
LSSTDataManagementBasePackage
ChunkManagerImpl.cc
Go to the documentation of this file.
1 // -*- lsst-c++ -*-
2 
3 /*
4  * LSST Data Management System
5  * Copyright 2008, 2009, 2010 LSST Corporation.
6  *
7  * This product includes software developed by the
8  * LSST Project (http://www.lsst.org/).
9  *
10  * This program is free software: you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation, either version 3 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the LSST License Statement and
21  * the GNU General Public License along with this program. If not,
22  * see <http://www.lsstcorp.org/LegalNotices/>.
23  */
24 
25 
33 #ifndef LSST_AP_CHUNK_MANAGER_IMPL_CC
34 #define LSST_AP_CHUNK_MANAGER_IMPL_CC
35 
36 #include <iostream>
37 
38 #include "boost/format.hpp"
39 
40 #include "lsst/pex/exceptions.h"
41 
42 #include "Chunk.cc"
43 #include "ChunkManagerImpl.h"
44 #include "SpatialUtil.h"
45 
46 
47 namespace lsst { namespace ap { namespace detail {
48 
49 // -- HashedSet ----------------
50 
55 inline int hash(boost::uint32_t key) {
56  key = (~key) + (key << 15); // key = (key << 15) - key - 1;
57  key = key ^ (key >> 12);
58  key = key + (key << 2);
59  key = key ^ (key >> 4);
60  key = key * 2057; // key = (key + (key << 3)) + (key << 11);
61  key = key ^ (key >> 16);
62  return static_cast<int>(key);
63 }
64 
65 inline int hash(int key) {
66  return hash(static_cast<boost::uint32_t>(key));
67 }
68 
69 
70 template <typename EntryT, int NumEntries>
72  _free(0), _size(0)
73 {
74  for (int i = 0; i < 2*NumEntries; ++i) {
75  _hashTable[i] = -1;
76  }
77  // initialize linked list of free entries (embedded in the entries themselves)
78  for (int i = 0; i < NumEntries - 1; ++i) {
79  _entries[i].setId(-1);
80  _entries[i].setNextInChain(i + 1);
81  }
82  _entries[NumEntries - 1].setNextInChain(-1);
83 }
84 
85 
92 template <typename EntryT, int NumEntries>
93 EntryT const * HashedSet<EntryT, NumEntries>::doFind(int const id) const {
94  int i = _hashTable[hash(id) & (2*NumEntries - 1)];
95  while (i >= 0) {
96  if (id == _entries[i].getId()) {
97  return &_entries[i];
98  }
99  i = _entries[i].getNextInChain();
100  }
101  return 0;
102 }
103 
104 
114 template <typename EntryT, int NumEntries>
116 
117  // check that there is space for another entry
118  if (_free < 0) {
119  return 0;
120  }
121 
122  int const bucket = hash(id) & (2*NumEntries - 1);
123 
124  int i = _hashTable[bucket];
125  int last = -1;
126 
127  while (i >= 0) {
128  if (id == _entries[i].getId()) {
129  return 0; // already have an entry with the given id
130  }
131  last = i;
132  i = _entries[i].getNextInChain();
133  }
134 
135  // take an entry off the free list
136  int const c = _free;
137  _free = _entries[c].getNextInChain();
138 
139  if (last < 0) {
140  _hashTable[bucket] = c;
141  } else {
142  // hash collision - chain to the end of the bucket
143  _entries[last].setNextInChain(c);
144  }
145 
146  // basic entry initialization, then return
147  new (&_entries[c]) EntryT();
148  _entries[c].setId(id);
149  _entries[c].setNextInChain(-1);
150  ++_size;
151  return &_entries[c];
152 }
153 
154 
165 template <typename EntryT, int NumEntries>
166 std::pair<EntryT *, bool> HashedSet<EntryT, NumEntries>::findOrInsert(int const id) {
167 
168  int const bucket = hash(id) & (2*NumEntries - 1);
169 
170  int i = _hashTable[bucket];
171  int last = -1;
172 
173  while (i >= 0) {
174  if (id == _entries[i].getId()) {
175  return std::pair<EntryT *, bool>(&_entries[i], false); // found an entry with the given id
176  }
177  last = i;
178  i = _entries[i].getNextInChain();
179  }
180 
181  // check that there is a free chunk, if so use it
182  int const c = _free;
183  if (c < 0) {
184  return std::pair<EntryT *, bool>(0, true);
185  }
186  _free = _entries[c].getNextInChain();
187 
188  if (last < 0) {
189  _hashTable[bucket] = c;
190  } else {
191  // hash collision - chain to the end of the bucket
192  _entries[last].setNextInChain(c);
193  }
194 
195  // basic chunk initialization, then return
196  new (&_entries[c]) EntryT();
197  _entries[c].setId(id);
198  _entries[c].setNextInChain(-1);
199  ++_size;
200  return std::pair<EntryT *, bool>(&_entries[c], true);
201 }
202 
203 
210 template <typename EntryT, int NumEntries>
212 
213  int const bucket = hash(id) & (2*NumEntries - 1);
214 
215  int i = _hashTable[bucket];
216  int last = -1;
217 
218  while (i >= 0) {
219  if (id == _entries[i].getId()) {
220  // found entry to erase, unlink it from the chain for its bucket
221  if (last < 0) {
222  _hashTable[bucket] = _entries[i].getNextInChain();
223  } else {
224  _entries[last].setNextInChain(_entries[i].getNextInChain());
225  }
226  // append the entry to the free list
227  _entries[i].setId(-1);
228  _entries[i].setNextInChain(_free);
229  _free = i;
230  --_size;
231  return true;
232  }
233  last = i;
234  i = _entries[i].getNextInChain();
235  }
236  return false;
237 }
238 
239 
240 // -- BlockAllocator ----------------
241 
251 template <typename MutexT, typename DataT, typename TraitsT>
253  unsigned char const * const reference,
254  std::size_t const offset
255 ) :
256  _mutex(),
257  _allocator(),
258  _offset(static_cast<std::size_t>((reference + offset) - reinterpret_cast<unsigned char * >(this)))
259 {
260  _allocator.reset();
261 }
262 
263 
273 template <typename MutexT, typename DataT, typename TraitsT>
275  int i[1];
276  ScopedLock<MutexT> lock(_mutex);
277  if (!_allocator.set(i, 1)) {
278  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError, "no free blocks remain");
279  }
280  return _offset + i[0]*BLOCK_SIZE;
281 }
282 
283 
296 template <typename MutexT, typename DataT, typename TraitsT>
298  std::size_t * const blockOffsets,
299  int const n
300 ) {
301  if (n < 0 || n > TraitsT::MAX_BLOCKS_PER_CHUNK) {
302  throw LSST_EXCEPT(lsst::pex::exceptions::RangeError,
303  "invalid number of memory blocks in allocation request");
304  }
305  int i[TraitsT::MAX_BLOCKS_PER_CHUNK];
306 
307  ScopedLock<MutexT> lock(_mutex);
308  if (!_allocator.set(i, n)) {
309  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
310  "number of free blocks too small to satisfy allocation request");
311  }
312  for (int j = 0; j < n; ++j) {
313  blockOffsets[j] = _offset + i[j]*BLOCK_SIZE;
314  }
315 }
316 
317 
326 template <typename MutexT, typename DataT, typename TraitsT>
328  std::size_t const * const blockOffsets,
329  int const n
330 ) {
331  assert(n >= 0 && n <= TraitsT::MAX_BLOCKS_PER_CHUNK &&
332  "invalid number of memory blocks in free request");
333 
334  // translate block offsets to block indexes
335  int i[TraitsT::MAX_BLOCKS_PER_CHUNK];
336  for (int j = 0; j < n; ++j) {
337  std::size_t off = blockOffsets[j] - _offset;
338  assert(off < TraitsT::NUM_BLOCKS*BLOCK_SIZE &&
339  "block was not allocated by this allocator");
340  assert(off % BLOCK_SIZE == 0 && "invalid block address");
341  i[j] = static_cast<int>(off/BLOCK_SIZE);
342  }
343 
344  // clear bit corresponding to each block to free
345  ScopedLock<MutexT> lock(_mutex);
346  _allocator.reset(i, n);
347 }
348 
349 
350 // -- VisitTracker ----------------
351 
356 bool VisitTracker::isValid(int const visitId) const {
357  Visit const * v = this->find(visitId);
358  if (v == 0) {
359  return false;
360  }
361  return !v->failed();
362 }
363 
364 void VisitTracker::print(std::ostream & os) const {
365  std::vector<int> v;
366  v.reserve(size());
367  Visit const * const e = end();
368  for (Visit const * beg = begin(); beg != e; ++beg) {
369  int const id = beg->getId();
370  if (id >= 0) {
371  v.push_back(id);
372  }
373  }
374  if (v.empty()) {
375  os << " No visits being tracked";
376  } else {
377  std::sort(v.begin(), v.end());
378  boost::format fmt(" visit %1% %|32t|: %2%\n");
379  for (std::vector<int>::const_iterator i = v.begin(); i != v.end(); ++i) {
380  Visit const * v = find(*i);
381  os << fmt % v->getId() % (v->failed() ? "failed" : "in-flight");
382  }
383  }
384  os << std::endl;
385 }
386 
387 void VisitTracker::print(int const visitId, std::ostream & os) const {
388  Visit const * v = find(visitId);
389  boost::format fmt(" visit %1% %|32t|: %2%\n");
390  fmt % visitId;
391  if (v == 0) {
392  os << fmt % "not being tracked";
393  } else {
394  os << fmt % (v->failed() ? "failed" : "in-flight");
395  }
396  os << std::endl;
397 }
398 
399 
400 // -- SubManager ----------------
401 
419 template <typename MutexT, typename DataT, typename TraitsT>
421  std::vector<Chunk> & toRead,
422  std::vector<Chunk> & toWaitFor,
423  int const visitId,
424  std::vector<int> const & chunkIds
425 ) {
426  std::vector<int>::const_iterator const end = chunkIds.end();
427  for (std::vector<int>::const_iterator i = chunkIds.begin(); i != end; ++i) {
428  std::pair<Descriptor *, bool> p(_chunks.findOrInsert(*i));
429  if (p.second) {
430  // new chunk descriptor was allocated
431  if (p.first == 0) {
432  throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
433  "too many chunks in flight");
434  }
435  p.first->_visitId = visitId;
436  p.first->_usable = false;
437  toRead.push_back(Chunk(p.first, &_allocator));
438  } else {
439  // existing chunk descriptor was found
440  assert(p.first != 0);
441  p.first->_interestedParties.enqueue(visitId);
442  toWaitFor.push_back(Chunk(p.first, &_allocator));
443  }
444  }
445 }
446 
447 
463 template <typename MutexT, typename DataT, typename TraitsT>
465  std::vector<Chunk> & toRead,
466  std::vector<Chunk> & toWaitFor,
467  int const visitId
468 ) {
469  std::size_t size = toWaitFor.size();
470  std::size_t i = 0;
471 
472  while (i < size) {
473  Chunk & c = toWaitFor[i];
474  if (c.getVisitId() != visitId) {
475  ++i;
476  } else {
477  if (!c.isUsable()) {
478  c.clear();
479  toRead.push_back(c);
480  }
481  // deletes element i in O(1) time (but changes element ordering)
482  --size;
483  if (i < size) {
484  toWaitFor[i] = toWaitFor[size];
485  }
486  toWaitFor.pop_back();
487  }
488  }
489  return toWaitFor.empty();
490 }
491 
492 
502 template <typename MutexT, typename DataT, typename TraitsT>
504  std::vector<Chunk> & chunks,
505  std::vector<int> const & chunkIds
506 ) {
507  std::vector<int>::const_iterator const end = chunkIds.end();
508  for (std::vector<int>::const_iterator i = chunkIds.begin(); i != end; ++i) {
509  Descriptor * d = _chunks.find(*i);
510  if (d != 0) {
511  chunks.push_back(Chunk(d, &_allocator));
512  }
513  }
514 }
515 
516 
530 template <typename MutexT, typename DataT, typename TraitsT>
532  int const visitId,
533  bool const rollback,
534  VisitTracker const & tracker
535 ) {
536  bool change = false;
537  Descriptor * const end = _chunks.end();
538  for (Descriptor * i = _chunks.begin(); i != end; ++i) {
539  if (i->getId() != -1 && i->_visitId == visitId) {
540  bool foundSuccessor = false;
541  while (!i->_interestedParties.empty()) {
542  int const nextVisitId = static_cast<int>(i->_interestedParties.dequeue());
543  if (tracker.isValid(nextVisitId)) {
544  i->_visitId = nextVisitId;
545  change = true;
546  foundSuccessor = true;
547  break;
548  }
549  }
550  if (foundSuccessor) {
551  Chunk c(i, &_allocator);
552  if (rollback) {
553  c.rollback();
554  } else {
555  c.commit();
556  }
557  } else {
558  // deallocate chunk
559  _allocator.free(i->_blocks, i->_numBlocks);
560  _chunks.erase(i->getId());
561  }
562  }
563  }
564  return change;
565 }
566 
567 
568 namespace {
569 
570  template <typename T> struct PtrLessThan {
571  bool operator()(T const * t1, T const * t2) { return *t1 < *t2; }
572  };
573 
574  template <typename DescriptorT>
575  bool mergePrint(DescriptorT const * d1, DescriptorT const * d2) {
576  if (d1->_visitId != d1->_visitId || d1->_usable != d2->_usable) {
577  return false;
578  }
579  if (d2->_interestedParties.empty() != d2->_interestedParties.empty()) {
580  return false;
581  }
582  return ZoneStripeChunkDecomposition::chunkToStripe(d1->_chunkId) ==
584  }
585 
586  template <typename DescriptorT>
587  void printChunks(std::ostream & os, std::vector<DescriptorT const *> const & v) {
588 
589  boost::format oneFmt (" chunk %1% in stripe %2% %|32t|: %3%%4%\n");
590  boost::format manyFmt(" chunks %1%-%2% in stripe %3% %|32t|: %4%%5%\n");
591 
592  int start = 0;
593  DescriptorT const * c = v[0];
594  int const sz = static_cast<int>(v.size());
595  for (int i = 1; i <= sz; ++i) {
596  if (i < sz && mergePrint(c, v[i])) {
597  continue;
598  }
599  if (i - start > 1) {
600  manyFmt % ZoneStripeChunkDecomposition::chunkToSequence(c->_chunkId);
601  manyFmt % ZoneStripeChunkDecomposition::chunkToSequence(v[i - 1]->_chunkId);
602  manyFmt % ZoneStripeChunkDecomposition::chunkToStripe(c->_chunkId);
603  manyFmt % (c->_usable ? " usable" : "unusable");
604  manyFmt % (c->_interestedParties.empty() ? "" : ", interesting");
605  os << manyFmt;
606  } else {
607  oneFmt % ZoneStripeChunkDecomposition::chunkToSequence(c->_chunkId);
608  oneFmt % ZoneStripeChunkDecomposition::chunkToStripe(c->_chunkId);
609  oneFmt % (c->_usable ? " usable" : "unusable");
610  oneFmt % (c->_interestedParties.empty() ? "" : ", interesting");
611  os << oneFmt;
612  }
613  if (i < sz) {
614  if (c->_visitId != v[i]->_visitId) {
615  os << " Owned by visit " << v[i]->_visitId << ":\n";
616  }
617  start = i;
618  c = v[i];
619  }
620  }
621  }
622 
623 } // end of anonymous namespace
624 
625 
626 template <typename MutexT, typename DataT, typename TraitsT>
627 void SubManager<MutexT, DataT, TraitsT>::print(std::ostream & os) const {
628  Descriptor const * const end = _chunks.end();
629  std::vector<Descriptor const *> v;
630  v.reserve(_chunks.size());
631  for (Descriptor const * beg = _chunks.begin(); beg != end; ++beg) {
632  if (beg->_chunkId != -1) {
633  v.push_back(beg);
634  }
635  }
636  std::sort(v.begin(), v.end(), PtrLessThan<Descriptor>());
637  os << " Chunks with an owner";
638  if (v.empty()) {
639  os << ": None";
640  } else {
641  os << ":\n";
642  os << " Owned by visit " << v[0]->_visitId << ":\n";
643  printChunks(os, v);
644  }
645  os << std::endl;
646 }
647 
648 
649 template <typename MutexT, typename DataT, typename TraitsT>
650 void SubManager<MutexT, DataT, TraitsT>::print(int const chunkId, std::ostream & os) const {
651  Descriptor const * c = _chunks.find(chunkId);
652  os << " [" << c->_chunkId << "] chunk " <<
653  ZoneStripeChunkDecomposition::chunkToSequence(chunkId) << " in stripe " <<
655  if (c == 0) {
656  os << ": not being tracked\n";
657  } else {
658  os << ":\n " << (c->_usable ? "usable" : "unusable") << "\n ";
659  if (c->_interestedParties.empty()) {
660  os << "un";
661  }
662  os << "interesting\n ";
663  int sz = c->_size;
664  os << sz << " entries in " << c->_nextBlock << " blocks (" <<
665  c->_numBlocks << " allocated)\n ";
666  if (sz <= c->_delta) {
667  sz = 0;
668  } else {
669  sz -= c->_delta;
670  }
671  os << sz << " entries in delta\n";
672  }
673  os << std::endl;
674 }
675 
676 
677 template <typename MutexT, typename DataT, typename TraitsT>
678 void SubManager<MutexT, DataT, TraitsT>::printVisit(int const visitId, std::ostream & os) const {
679  Descriptor const * const end = _chunks.end();
680  std::vector<Descriptor const *> v;
681  v.reserve(_chunks.size());
682  for (Descriptor const * beg = _chunks.begin(); beg != end; ++beg) {
683  if (beg->_chunkId != -1 && beg->_visitId == visitId) {
684  v.push_back(beg);
685  }
686  }
687  std::sort(v.begin(), v.end(), PtrLessThan<Descriptor>());
688  os << " Chunks belonging to visit " << visitId;
689  if (v.empty()) {
690  os << ": None";
691  } else {
692  os << ":\n";
693  printChunks(os, v);
694  }
695  os << std::endl;
696 }
697 
698 
699 // -- ChunkManagerImpl ----------------
700 
701 template <typename MutexT, typename DataT, typename TraitsT>
703  _data(reinterpret_cast<unsigned char *>(this), blocks())
704 {}
705 
706 
708 template <typename MutexT, typename DataT, typename TraitsT>
710  ScopedLock<MutexT> lock(_mutex);
711  return _visits.isValid(visitId);
712 }
713 
714 
719 template <typename MutexT, typename DataT, typename TraitsT>
721  ScopedLock<MutexT> lock(_mutex);
722  Visit * v = _visits.find(visitId);
723  if (v != 0) {
724  v->setFailed();
725  }
726 }
727 
728 
737 template <typename MutexT, typename DataT, typename TraitsT>
739  ScopedLock<MutexT> lock(_mutex);
740  if (_visits.find(visitId) != 0) {
741  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
742  (boost::format("Cannot start processing visit %1%: visit is already in flight") % visitId).str());
743  }
744  if (_visits.space() == 0) {
745  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
746  (boost::format("Cannot register visit %1%: too many visits in-flight") % visitId).str());
747  }
748  Visit * v = _visits.insert(visitId);
749  assert(v != 0);
750 }
751 
752 
772 template <typename MutexT, typename DataT, typename TraitsT>
774  std::vector<Chunk> & toRead,
775  std::vector<Chunk> & toWaitFor,
776  int const visitId,
777  std::vector<int> const & chunkIds
778 ) {
779  toRead.clear();
780  toWaitFor.clear();
781 
782  // ensure external resources necessary for success are available
783  toRead.reserve(chunkIds.size());
784  toWaitFor.reserve(chunkIds.size());
785 
786  ScopedLock<MutexT> lock(_mutex);
787  // ensure internal resources necessary for success are available
788  if (_data.space() < static_cast<int>(chunkIds.size())) {
789  throw LSST_EXCEPT(lsst::pex::exceptions::LengthError,
790  "requested additional chunks exceed chunk manager capacity");
791  }
792  if (!_visits.isValid(visitId)) {
793  throw LSST_EXCEPT(lsst::pex::exceptions::InvalidParameterError,
794  (boost::format("Cannot start processing for visit %1%: visit is not in-flight") % visitId).str());
795  }
796  // having pre-allocated/checked that there is space for everything,
797  // manager state can be modified without throwing
798  _data.createOrRegisterInterest(toRead, toWaitFor, visitId, chunkIds);
799 }
800 
801 
819 template <typename MutexT, typename DataT, typename TraitsT>
821  std::vector<Chunk> & toRead,
822  std::vector<Chunk> & toWaitFor,
823  int const visitId,
824  TimeSpec const & deadline
825 ) {
826  toRead.clear();
827  toRead.reserve(toWaitFor.size());
828 
829  ScopedLock<MutexT> lock(_mutex);
830  while (true) {
831  if (_data.checkForOwnership(toRead, toWaitFor, visitId)) {
832  break; // all chunks belong to the visit - ok to proceed
833  }
834  // wait for ownership
835  if (!_ownerCondition.wait(lock, deadline)) {
836  // TODO: this is a short-term DC3a hack, necessary because there is no way for
837  // the pipeline framework to communicate exceptions arising outside of the implementation
838  // of AP (e.g. in an IOStage) back to the pipeline itself. This results in visits that
839  // fail, but never relinquish ownership of their chunks. For now, take the draconian measure
840  // of rolling back all visits except the current one. This needs to be re-thought for DC3b!
841  rollbackAllExcept(visitId);
842  throw LSST_EXCEPT(lsst::pex::exceptions::TimeoutError,
843  (boost::format("Deadline for visit %1% expired") % visitId).str());
844  }
845  }
846 }
847 
848 
855 template <typename MutexT, typename DataT, typename TraitsT>
857  std::vector<Chunk> & chunks,
858  std::vector<int> const & chunkIds
859 ) {
860  ScopedLock<MutexT> lock(_mutex);
861  _data.getChunks(chunks, chunkIds);
862 }
863 
864 
878 template <typename MutexT, typename DataT, typename TraitsT>
880  int const visitId,
881  bool const rollback
882 ) {
883  ScopedLock<MutexT> lock(_mutex);
884  bool roll = rollback || !_visits.isValid(visitId);
885  if (!_visits.erase(visitId)) {
886  return false;
887  }
888  // relinquish chunk ownership: if any chunks change hands, notify all threads
889  // waiting on chunk ownership to check whether they can proceed
890  if (_data.relinquishOwnership(visitId, roll, _visits)) {
891  _ownerCondition.notifyAll();
892  }
893  return !roll;
894 }
895 
896 
904 template <typename MutexT, typename DataT, typename TraitsT>
906  for (Visit const * v = _visits.begin(); v != _visits.end(); ++v) {
907  int id = v->getId();
908  if (id >= 0 && id != visitId) {
909  _visits.erase(id);
910  _data.relinquishOwnership(id, true, _visits);
911  }
912  }
913 }
914 
915 
916 template <typename MutexT, typename DataT, typename TraitsT>
918  ScopedLock<MutexT> lock(_mutex);
919  _visits.print(os);
920 }
921 
922 
923 template <typename MutexT, typename DataT, typename TraitsT>
925  ScopedLock<MutexT> lock(_mutex);
926  _data.print(os);
927 }
928 
929 
930 template <typename MutexT, typename DataT, typename TraitsT>
931 void ChunkManagerImpl<MutexT, DataT, TraitsT>::printVisit(int const visitId, std::ostream & os) const {
932  ScopedLock<MutexT> lock(_mutex);
933  _visits.print(visitId, os);
934  _data.printVisit(visitId, os);
935 }
936 
937 
938 template <typename MutexT, typename DataT, typename TraitsT>
939 void ChunkManagerImpl<MutexT, DataT, TraitsT>::printChunk(int const chunkId, std::ostream & os) const {
940  ScopedLock<MutexT> lock(_mutex);
941  _data.print(chunkId, os);
942 }
943 
944 
945 }}} // end of namespace lsst::ap::detail
946 
947 #endif // LSST_AP_CHUNK_MANAGER_IMPL_CC
948 
Wraps the C library timespec struct.
Definition: Time.h:48
void rollbackAllExcept(int const visitId)
void printVisit(int const visitId, std::ostream &os) const
bool checkForOwnership(std::vector< Chunk > &toRead, std::vector< Chunk > &toWaitFor, int const visitId)
Tracks a set of visits.
bool relinquishOwnership(int const visitId, bool const rollback, VisitTracker const &tracker)
void waitForOwnership(std::vector< Chunk > &toRead, std::vector< Chunk > &toWaitFor, int const visitId, TimeSpec const &deadline)
void createOrRegisterInterest(std::vector< Chunk > &toRead, std::vector< Chunk > &toWaitFor, int const visitId, std::vector< int > const &chunkIds)
int _chunkId
Identifier for the chunk.
Definition: Chunk.h:88
int _numBlocks
Number of memory blocks allocated.
Definition: Chunk.h:98
int hash(boost::uint32_t key)
void free(std::size_t const *const blockOffsets, int const n)
int d
Definition: KDTree.cc:89
void printChunk(int const chunkId, std::ostream &os) const
Chunk manager helper classes.
void reset()
Definition: Bitset.h:123
bool isValid(int const visitId) const
bool endVisit(int const visitId, bool const rollback)
std::pair< EntryT *, bool > findOrInsert(int const id)
bool isVisitInFlight(int const visitId)
EntryT const * doFind(int const id) const
Visit * find(int const id)
Returns a pointer to the entry with the given identifier, or null if there is no such entry...
ChunkRef< Allocator, DataT, TraitsT > Chunk
void printChunks(std::ostream &os) const
Fifo< MAX_VISITS_IN_FLIGHT > _interestedParties
FIFO of visits to a FOV that overlaps the chunk.
Definition: Chunk.h:106
void printVisit(int const visitId, std::ostream &os) const
A generic descriptor containing state for different kinds of chunks.
Definition: Chunk.h:85
int _delta
Index of first entry marked IN_DELTA.
Definition: Chunk.h:102
void getChunks(std::vector< Chunk > &chunks, std::vector< int > const &chunkIds)
bool empty() const
Returns true if the Fifo is empty.
Definition: Fifo.h:66
#define LSST_EXCEPT(type,...)
Definition: Exception.h:46
BlockAllocator(unsigned char const *const ref, std::size_t const offset)
EntryT * insert(int const id)
void printVisits(std::ostream &os) const
static int chunkToSequence(int const chunkId)
Definition: SpatialUtil.h:169
static int chunkToStripe(int const chunkId)
Definition: SpatialUtil.h:164
int _size
Total number of entries.
Definition: Chunk.h:101
int _hashTable[2 *NumEntries]
Chunk class implementation.
State for a single visit to a field of view.
int _nextBlock
Index of the next block to insert into.
Definition: Chunk.h:99
void getChunks(std::vector< Chunk > &chunks, std::vector< int > const &chunkIds)
Grants access to a mutex, enforcing the RAII principle.
Definition: Mutex.h:51
int _visitId
Identifier for the visit that currently owns the chunk.
Definition: Chunk.h:89
void print(std::ostream &os) const
void startVisit(std::vector< Chunk > &toRead, std::vector< Chunk > &toWaitFor, int const visitId, std::vector< int > const &chunkIds)
void registerVisit(int const visitId)
Include files required for standard LSST Exception handling.
Class and helper functions related to spatial partitioning.
void print(std::ostream &os) const