33 #ifndef LSST_AP_CHUNK_MANAGER_IMPL_CC
34 #define LSST_AP_CHUNK_MANAGER_IMPL_CC
38 #include "boost/format.hpp"
47 namespace lsst {
namespace ap {
namespace detail {
55 inline int hash(boost::uint32_t key) {
56 key = (~key) + (key << 15);
57 key = key ^ (key >> 12);
58 key = key + (key << 2);
59 key = key ^ (key >> 4);
61 key = key ^ (key >> 16);
62 return static_cast<int>(key);
66 return hash(static_cast<boost::uint32_t>(key));
70 template <
typename EntryT,
int NumEntries>
74 for (
int i = 0; i < 2*NumEntries; ++i) {
78 for (
int i = 0; i < NumEntries - 1; ++i) {
82 _entries[NumEntries - 1].setNextInChain(-1);
92 template <
typename EntryT,
int NumEntries>
94 int i = _hashTable[
hash(
id) & (2*NumEntries - 1)];
96 if (
id == _entries[i].getId()) {
99 i = _entries[i].getNextInChain();
114 template <
typename EntryT,
int NumEntries>
122 int const bucket =
hash(
id) & (2*NumEntries - 1);
124 int i = _hashTable[bucket];
128 if (
id == _entries[i].getId()) {
132 i = _entries[i].getNextInChain();
137 _free = _entries[c].getNextInChain();
140 _hashTable[bucket] = c;
143 _entries[last].setNextInChain(c);
147 new (&_entries[c]) EntryT();
148 _entries[c].setId(
id);
149 _entries[c].setNextInChain(-1);
165 template <
typename EntryT,
int NumEntries>
168 int const bucket =
hash(
id) & (2*NumEntries - 1);
170 int i = _hashTable[bucket];
174 if (
id == _entries[i].getId()) {
175 return std::pair<EntryT *, bool>(&_entries[i],
false);
178 i = _entries[i].getNextInChain();
184 return std::pair<EntryT *, bool>(0,
true);
186 _free = _entries[c].getNextInChain();
189 _hashTable[bucket] = c;
192 _entries[last].setNextInChain(c);
196 new (&_entries[c]) EntryT();
197 _entries[c].setId(
id);
198 _entries[c].setNextInChain(-1);
200 return std::pair<EntryT *, bool>(&_entries[c],
true);
210 template <
typename EntryT,
int NumEntries>
213 int const bucket =
hash(
id) & (2*NumEntries - 1);
215 int i = _hashTable[bucket];
219 if (
id == _entries[i].getId()) {
222 _hashTable[bucket] = _entries[i].getNextInChain();
224 _entries[last].setNextInChain(_entries[i].getNextInChain());
227 _entries[i].setId(-1);
228 _entries[i].setNextInChain(_free);
234 i = _entries[i].getNextInChain();
251 template <
typename MutexT,
typename DataT,
typename TraitsT>
253 unsigned char const *
const reference,
254 std::size_t
const offset
258 _offset(static_cast<std::size_t>((reference + offset) - reinterpret_cast<unsigned char * >(this)))
273 template <
typename MutexT,
typename DataT,
typename TraitsT>
277 if (!_allocator.set(i, 1)) {
278 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
"no free blocks remain");
280 return _offset + i[0]*BLOCK_SIZE;
296 template <
typename MutexT,
typename DataT,
typename TraitsT>
298 std::size_t *
const blockOffsets,
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");
305 int i[TraitsT::MAX_BLOCKS_PER_CHUNK];
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");
312 for (
int j = 0; j < n; ++j) {
313 blockOffsets[j] = _offset + i[j]*BLOCK_SIZE;
326 template <
typename MutexT,
typename DataT,
typename TraitsT>
328 std::size_t
const *
const blockOffsets,
331 assert(n >= 0 && n <= TraitsT::MAX_BLOCKS_PER_CHUNK &&
332 "invalid number of memory blocks in free request");
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);
346 _allocator.reset(i, n);
368 for (
Visit const * beg =
begin(); beg != e; ++beg) {
369 int const id = beg->getId();
375 os <<
" No visits being tracked";
377 std::sort(v.begin(), v.end());
379 for (std::vector<int>::const_iterator i = v.begin(); i != v.end(); ++i) {
381 os << fmt % v->
getId() % (v->
failed() ?
"failed" :
"in-flight");
392 os << fmt %
"not being tracked";
394 os << fmt % (v->
failed() ?
"failed" :
"in-flight");
419 template <
typename MutexT,
typename DataT,
typename TraitsT>
421 std::vector<Chunk> & toRead,
422 std::vector<Chunk> & toWaitFor,
424 std::vector<int>
const & chunkIds
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));
432 throw LSST_EXCEPT(lsst::pex::exceptions::MemoryError,
433 "too many chunks in flight");
435 p.first->_visitId = visitId;
436 p.first->_usable =
false;
437 toRead.push_back(
Chunk(p.first, &_allocator));
440 assert(p.first != 0);
441 p.first->_interestedParties.enqueue(visitId);
442 toWaitFor.push_back(
Chunk(p.first, &_allocator));
463 template <
typename MutexT,
typename DataT,
typename TraitsT>
465 std::vector<Chunk> & toRead,
466 std::vector<Chunk> & toWaitFor,
469 std::size_t size = toWaitFor.size();
473 Chunk & c = toWaitFor[i];
474 if (c.getVisitId() != visitId) {
484 toWaitFor[i] = toWaitFor[size];
486 toWaitFor.pop_back();
489 return toWaitFor.empty();
502 template <
typename MutexT,
typename DataT,
typename TraitsT>
504 std::vector<Chunk> & chunks,
505 std::vector<int>
const & chunkIds
507 std::vector<int>::const_iterator
const end = chunkIds.end();
508 for (std::vector<int>::const_iterator i = chunkIds.begin(); i != end; ++i) {
511 chunks.push_back(
Chunk(d, &_allocator));
530 template <
typename MutexT,
typename DataT,
typename TraitsT>
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)) {
546 foundSuccessor =
true;
550 if (foundSuccessor) {
551 Chunk c(i, &_allocator);
559 _allocator.free(i->_blocks, i->_numBlocks);
560 _chunks.erase(i->getId());
570 template <
typename T>
struct PtrLessThan {
571 bool operator()(T
const * t1, T
const * t2) {
return *t1 < *t2; }
574 template <
typename DescriptorT>
575 bool mergePrint(DescriptorT
const * d1, DescriptorT
const * d2) {
576 if (d1->_visitId != d1->_visitId || d1->_usable != d2->_usable) {
579 if (d2->_interestedParties.empty() != d2->_interestedParties.empty()) {
586 template <
typename DescriptorT>
587 void printChunks(std::ostream & os, std::vector<DescriptorT const *>
const & v) {
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");
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])) {
603 manyFmt % (c->_usable ?
" usable" :
"unusable");
604 manyFmt % (c->_interestedParties.empty() ?
"" :
", interesting");
609 oneFmt % (c->_usable ?
" usable" :
"unusable");
610 oneFmt % (c->_interestedParties.empty() ?
"" :
", interesting");
614 if (c->_visitId != v[i]->_visitId) {
615 os <<
" Owned by visit " << v[i]->_visitId <<
":\n";
626 template <
typename MutexT,
typename DataT,
typename TraitsT>
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) {
636 std::sort(v.begin(), v.end(), PtrLessThan<Descriptor>());
637 os <<
" Chunks with an owner";
642 os <<
" Owned by visit " << v[0]->_visitId <<
":\n";
649 template <
typename MutexT,
typename DataT,
typename TraitsT>
652 os <<
" [" << c->
_chunkId <<
"] chunk " <<
656 os <<
": not being tracked\n";
658 os <<
":\n " << (c->
_usable ?
"usable" :
"unusable") <<
"\n ";
662 os <<
"interesting\n ";
664 os << sz <<
" entries in " << c->
_nextBlock <<
" blocks (" <<
666 if (sz <= c->_delta) {
671 os << sz <<
" entries in delta\n";
677 template <
typename MutexT,
typename DataT,
typename TraitsT>
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) {
687 std::sort(v.begin(), v.end(), PtrLessThan<Descriptor>());
688 os <<
" Chunks belonging to visit " << visitId;
701 template <
typename MutexT,
typename DataT,
typename TraitsT>
703 _data(reinterpret_cast<unsigned char *>(this), blocks())
708 template <
typename MutexT,
typename DataT,
typename TraitsT>
711 return _visits.isValid(visitId);
719 template <
typename MutexT,
typename DataT,
typename TraitsT>
722 Visit * v = _visits.find(visitId);
737 template <
typename MutexT,
typename DataT,
typename TraitsT>
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());
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());
748 Visit * v = _visits.insert(visitId);
772 template <
typename MutexT,
typename DataT,
typename TraitsT>
774 std::vector<Chunk> & toRead,
775 std::vector<Chunk> & toWaitFor,
777 std::vector<int>
const & chunkIds
783 toRead.reserve(chunkIds.size());
784 toWaitFor.reserve(chunkIds.size());
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");
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());
798 _data.createOrRegisterInterest(toRead, toWaitFor, visitId, chunkIds);
819 template <
typename MutexT,
typename DataT,
typename TraitsT>
821 std::vector<Chunk> & toRead,
822 std::vector<Chunk> & toWaitFor,
827 toRead.reserve(toWaitFor.size());
831 if (_data.checkForOwnership(toRead, toWaitFor, visitId)) {
835 if (!_ownerCondition.wait(lock, deadline)) {
841 rollbackAllExcept(visitId);
842 throw LSST_EXCEPT(lsst::pex::exceptions::TimeoutError,
843 (
boost::format(
"Deadline for visit %1% expired") % visitId).str());
855 template <
typename MutexT,
typename DataT,
typename TraitsT>
857 std::vector<Chunk> & chunks,
858 std::vector<int>
const & chunkIds
861 _data.getChunks(chunks, chunkIds);
878 template <
typename MutexT,
typename DataT,
typename TraitsT>
884 bool roll = rollback || !_visits.isValid(visitId);
885 if (!_visits.erase(visitId)) {
890 if (_data.relinquishOwnership(visitId, roll, _visits)) {
891 _ownerCondition.notifyAll();
904 template <
typename MutexT,
typename DataT,
typename TraitsT>
906 for (
Visit const * v = _visits.begin(); v != _visits.end(); ++v) {
908 if (
id >= 0 &&
id != visitId) {
910 _data.relinquishOwnership(
id,
true, _visits);
916 template <
typename MutexT,
typename DataT,
typename TraitsT>
923 template <
typename MutexT,
typename DataT,
typename TraitsT>
930 template <
typename MutexT,
typename DataT,
typename TraitsT>
933 _visits.print(visitId, os);
934 _data.printVisit(visitId, os);
938 template <
typename MutexT,
typename DataT,
typename TraitsT>
941 _data.print(chunkId, os);
947 #endif // LSST_AP_CHUNK_MANAGER_IMPL_CC
Wraps the C library timespec struct.
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)
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.
int _numBlocks
Number of memory blocks allocated.
int hash(boost::uint32_t key)
void free(std::size_t const *const blockOffsets, int const n)
EntryT _entries[NumEntries]
void printChunk(int const chunkId, std::ostream &os) const
Chunk manager helper classes.
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.
void printVisit(int const visitId, std::ostream &os) const
A generic descriptor containing state for different kinds of chunks.
int _delta
Index of first entry marked IN_DELTA.
void getChunks(std::vector< Chunk > &chunks, std::vector< int > const &chunkIds)
bool empty() const
Returns true if the Fifo is empty.
#define LSST_EXCEPT(type,...)
BlockAllocator(unsigned char const *const ref, std::size_t const offset)
EntryT * insert(int const id)
void printVisits(std::ostream &os) const
void failVisit(int const visitId)
static int chunkToSequence(int const chunkId)
static int chunkToStripe(int const chunkId)
int _size
Total number of entries.
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.
void getChunks(std::vector< Chunk > &chunks, std::vector< int > const &chunkIds)
Grants access to a mutex, enforcing the RAII principle.
int _visitId
Identifier for the visit that currently owns the chunk.
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