Lumiera  0.pre.03
»edityourfreedom«
buffer-metadata.hpp
Go to the documentation of this file.
1 /*
2  BUFFER-METADATA.hpp - internal metadata for data buffer providers
3 
4  Copyright (C) Lumiera.org
5  2011, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 */
22 
53 #ifndef PROC_ENGINE_BUFFR_METADATA_H
54 #define PROC_ENGINE_BUFFR_METADATA_H
55 
56 
57 #include "lib/error.hpp"
58 #include "lib/symbol.hpp"
59 #include "lib/hash-value.h"
60 #include "lib/util-foreach.hpp"
61 #include "include/logging.h"
64 #include "lib/nocopy.hpp"
65 
66 #include <unordered_map>
67 
68 
69 namespace proc {
70 namespace engine {
71 
72  using lib::HashVal;
73  using lib::Literal;
74  using util::for_each;
75 
76  namespace error = lumiera::error;
77 
78  namespace metadata {
79  class Key;
80  class Entry;
81  }
82  class BufferMetadata;
83 
84 
85 
86 
93  { NIL,
94  FREE,
98  };
99 
100 
101 
102 
103 
104 
105  namespace { // internal constants to mark the default case
106 
107  const LocalKey UNSPECIFIC;
108  const TypeHandler RAW_BUFFER;
109 
110  inline bool
111  nontrivial (TypeHandler const& toVerify)
112  {
113  return RAW_BUFFER != toVerify;
114  }
115 
116  inline bool
117  nontrivial (LocalKey const& toVerify)
118  {
119  return UNSPECIFIC != toVerify;
120  }
121  }
122 
123 
124 
125  /* === Metadata Implementation === */
126 
127  namespace metadata {
128 
129  using error::LERR_(LIFECYCLE);
130  using error::LERR_(BOTTOM_VALUE);
131 
132  namespace { // details of hash calculation
133  template<typename VAL>
134  HashVal
135  chainedHash(HashVal accumulatedHash, VAL changedValue)
136  {
137  boost::hash_combine (accumulatedHash, changedValue);
138  return accumulatedHash;
139  }
140  }
141 
142 
149  class Key
150  {
153 
154  protected:
155  size_t storageSize_;
158 
159 
160  public:
167  Key (HashVal familyID, size_t storageSize)
168  : parent_(familyID)
169  , hashID_(chainedHash (familyID, storageSize))
170  , storageSize_(storageSize)
171  , instanceFunc_(RAW_BUFFER)
172  , specifics_(UNSPECIFIC)
173  { }
174 
175  // standard copy operations permitted
176 
181  Key (Key const& parent, size_t differingStorageSize)
182  : parent_(parent.hashID_)
183  , hashID_(chainedHash (parent_, differingStorageSize))
184  , storageSize_(differingStorageSize) // differing from parent
185  , instanceFunc_(parent.instanceFunc_)
186  , specifics_(parent.specifics_)
187  { }
188 
189 
194  Key (Key const& parent, TypeHandler const& differingTypeHandlerFunctions)
195  : parent_(parent.hashID_)
196  , hashID_(chainedHash (parent_, differingTypeHandlerFunctions))
197  , storageSize_(parent.storageSize_)
198  , instanceFunc_(differingTypeHandlerFunctions) // differing from parent
199  , specifics_(parent.specifics_)
200  { }
201 
202 
207  Key (Key const& parent, LocalKey anotherTypeSpecificInternalID)
208  : parent_(parent.hashID_)
209  , hashID_(chainedHash (parent_, anotherTypeSpecificInternalID))
210  , storageSize_(parent.storageSize_)
211  , instanceFunc_(parent.instanceFunc_)
212  , specifics_(anotherTypeSpecificInternalID) // differing from parent
213  { }
214 
215 
222  static Key
223  forEntry (Key const& parent, const void* bufferAddr, LocalKey const& implID =UNSPECIFIC)
224  {
225  Key newKey(parent);
226  if (bufferAddr)
227  {
228  newKey.parent_ = HashVal(parent);
229  newKey.hashID_ = chainedHash(parent, bufferAddr);
230  if (nontrivial(implID))
231  {
232  REQUIRE (!newKey.specifics_.isDefined(),
233  "Implementation defined local key should not be overridden. "
234  "Underlying buffer type already defines a nontrivial LocalKey");
235  newKey.specifics_ = implID;
236  } }
237  return newKey;
238  }
239 
240  void
241  useTypeHandlerFrom (Key const& ref)
242  {
243  if (nontrivial(this->instanceFunc_))
244  throw error::Logic ("unable to supersede an already attached TypeHandler"
245  , LERR_(LIFECYCLE));
246  instanceFunc_ = ref.instanceFunc_;
247  }
248 
249 
250  LocalKey const& localKey() const { return specifics_;}
251  size_t storageSize() const { return storageSize_; }
252 
253  HashVal parentKey() const { return parent_;}
254  operator HashVal() const { return hashID_;}
255  };
256 
257 
272  class Entry
273  : public Key
274  {
276  void* buffer_;
277 
278  protected:
279  Entry (Key const& parent, void* bufferPtr =0, LocalKey const& implID =UNSPECIFIC)
280  : Key (Key::forEntry (parent, bufferPtr, implID))
281  , state_(bufferPtr? LOCKED:NIL)
282  , buffer_(bufferPtr)
283  { }
284 
287 
288  // standard copy operations permitted
289 
290  public:
293  bool
294  isLocked() const
295  {
296  ASSERT (!buffer_ || (NIL != state_ && FREE != state_));
297  return bool(buffer_);
298  }
299 
303  bool
304  isTypeKey() const
305  {
306  return NIL == state_ && !buffer_;
307  }
308 
309 
311  state() const
312  {
313  return state_;
314  }
315 
316  void*
318  {
319  __must_not_be_NIL();
320  __must_not_be_FREE();
321 
322  ENSURE (buffer_);
323  return buffer_;
324  }
325 
327  Entry&
328  mark (BufferState newState)
329  {
330  __must_not_be_NIL();
331 
332  if ( (state_ == FREE && newState == LOCKED)
333  ||(state_ == LOCKED && newState == EMITTED)
334  ||(state_ == LOCKED && newState == BLOCKED)
335  ||(state_ == LOCKED && newState == FREE)
336  ||(state_ == EMITTED && newState == BLOCKED)
337  ||(state_ == EMITTED && newState == FREE)
338  ||(state_ == BLOCKED && newState == FREE))
339  {
340  // allowed transition
341  if (newState == FREE)
342  invokeEmbeddedDtor_and_clear();
343  if (newState == LOCKED)
344  invokeEmbeddedCtor();
345  state_ = newState;
346  return *this;
347  }
348 
349  throw error::Fatal ("Invalid buffer state transition.");
350  }
351 
352  Entry&
353  lock (void* newBuffer)
354  {
355  __must_be_FREE();
356  buffer_ = newBuffer;
357  return mark (LOCKED);
358  }
359 
360  Entry&
361  invalidate (bool invokeDtor =true)
362  {
363  if (buffer_ && invokeDtor)
364  invokeEmbeddedDtor_and_clear();
365  buffer_ = 0;
366  state_ = FREE;
367  return *this;
368  }
369 
370 
371  protected:
375  void
377  {
378  __buffer_required();
379  if (nontrivial (instanceFunc_))
380  instanceFunc_.createAttached (buffer_);
381  }
382 
386  void
388  {
389  __buffer_required();
390  if (nontrivial (instanceFunc_))
391  instanceFunc_.destroyAttached (buffer_);
392  buffer_ = 0;
393  }
394 
395  private:
396  void
398  {
399  if (NIL == state_)
400  throw error::Fatal ("Buffer metadata entry with state==NIL encountered."
401  "State transition logic broken (programming error)"
402  , LERR_(LIFECYCLE));
403  }
404 
405  void
407  {
408  if (FREE == state_)
409  throw error::Logic ("Buffer is inaccessible (marked as free). "
410  "Need a new buffer pointer in order to lock an entry. "
411  "You should invoke markLocked(buffer) prior to access."
412  , LERR_(LIFECYCLE));
413  }
414 
415  void
417  {
418  if (FREE != state_)
419  throw error::Logic ("Buffer already in use"
420  , LERR_(LIFECYCLE));
421  REQUIRE (!buffer_, "Buffer marked as free, "
422  "but buffer pointer is set.");
423  }
424 
425  void
427  {
428  if (!buffer_)
429  throw error::Fatal ("Need concrete buffer for any further operations");
430  }
431  };
432 
433 
434 
444  class Table
445  {
446  typedef std::unordered_map<HashVal,Entry> MetadataStore;
447 
448  MetadataStore entries_;
449 
450  public:
451  ~Table() { verify_all_buffers_freed(); }
452 
457  Entry*
458  fetch (HashVal hashID)
459  {
460  MetadataStore::iterator pos = entries_.find (hashID);
461  if (pos != entries_.end())
462  return &(pos->second);
463  else
464  return NULL;
465  }
466 
467  const Entry*
468  fetch (HashVal hashID) const
469  {
470  MetadataStore::const_iterator pos = entries_.find (hashID);
471  if (pos != entries_.end())
472  return &(pos->second);
473  else
474  return NULL;
475  }
476 
485  Entry&
486  store (Entry const& newEntry)
487  {
488  using std::make_pair;
489  REQUIRE (!fetch (newEntry), "duplicate buffer metadata entry");
490  MetadataStore::iterator pos = entries_.insert (make_pair (HashVal(newEntry), newEntry))
491  .first;
492 
493  ENSURE (pos != entries_.end());
494  return pos->second;
495  }
496 
497  void
498  remove (HashVal hashID)
499  {
500  uint cnt = entries_.erase (hashID);
501  ENSURE (cnt, "entry to remove didn't exist");
502  }
503 
504  private:
505  void
507  try
508  {
509  for_each (entries_, verify_is_free);
510  }
511  ERROR_LOG_AND_IGNORE (engine,"Shutdown of BufferProvider metadata store")
512 
513  static void
514  verify_is_free (std::pair<HashVal, Entry> const& e)
515  {
516  WARN_IF (e.second.isLocked(), engine,
517  "Buffer still in use while shutting down BufferProvider? ");
518  }
519  };
520 
521  }//namespace metadata
522 
523 
524 
525 
526 
527  /* ===== Buffer Metadata Frontend ===== */
528 
544  {
547 
550 
551  public:
554 
562  BufferMetadata (Literal implementationID)
563  : id_(implementationID)
564  , family_(hash_value(id_))
565  { }
566 
577  Key
578  key ( size_t storageSize
579  , TypeHandler instanceFunc =RAW_BUFFER
580  , LocalKey specifics =UNSPECIFIC)
581  {
582  REQUIRE (storageSize);
583  Key typeKey = trackKey (family_, storageSize);
584 
585  if (nontrivial(instanceFunc))
586  typeKey = trackKey (typeKey, instanceFunc);
587 
588  if (nontrivial(specifics))
589  typeKey = trackKey (typeKey, specifics);
590 
591  return typeKey;
592  }
593 
595  Key
596  key (Key const& parentKey, TypeHandler const& instanceFunc)
597  {
598  return trackKey (parentKey, instanceFunc);
599  }
600 
603  Key
604  key (Key const& parentKey, LocalKey specifics)
605  {
606  return trackKey (parentKey, specifics);
607  }
608 
613  Key const&
614  key (Key const& parentKey, void* concreteBuffer, LocalKey const& implID =UNSPECIFIC)
615  {
616  Key derivedKey = Key::forEntry (parentKey, concreteBuffer);
617  Entry* existing = table_.fetch (derivedKey);
618 
619  return existing? *existing
620  : markLocked (parentKey,concreteBuffer,implID);
621  }
622 
645  Entry&
646  lock (Key const& parentKey
647  ,void* concreteBuffer
648  ,LocalKey const& implID =UNSPECIFIC
649  ,bool onlyNew =false)
650  {
651  if (!concreteBuffer)
652  throw error::Invalid ("Attempt to lock a slot for a NULL buffer"
653  , error::LUMIERA_ERROR_BOTTOM_VALUE);
654 
655  Entry newEntry(parentKey, concreteBuffer, implID);
656  Entry* existing = table_.fetch (newEntry);
657 
658  if (existing && onlyNew)
659  throw error::Logic ("Attempt to lock a slot for a new buffer, "
660  "while actually the old buffer is still locked"
661  , error::LUMIERA_ERROR_LIFECYCLE );
662  if (existing && existing->isLocked())
663  throw error::Logic ("Attempt to re-lock a buffer still in use"
664  , error::LUMIERA_ERROR_LIFECYCLE );
665 
666  if (!existing)
667  return store_and_lock (newEntry); // actual creation
668  else
669  return existing->lock (concreteBuffer);
670  }
671 
680  Entry&
681  get (HashVal hashID)
682  {
683  Entry* entry = table_.fetch (hashID);
684  if (!entry)
685  throw error::Invalid ("Attempt to access an unknown buffer metadata entry");
686 
687  return *entry;
688  }
689 
690  bool
691  isKnown (HashVal key) const
692  {
693  return bool(table_.fetch (key));
694  }
695 
696  bool
697  isLocked (HashVal key) const
698  {
699  const Entry* entry = table_.fetch (key);
700  return entry
701  && entry->isLocked();
702  }
703 
704 
705 
706  /* == memory management operations == */
707 
718  Entry&
719  markLocked (Key const& parentKey, void* buffer, LocalKey const& implID =UNSPECIFIC)
720  {
721  if (!buffer)
722  throw error::Fatal ("Attempt to lock for a NULL buffer. Allocation floundered?"
723  , error::LUMIERA_ERROR_BOTTOM_VALUE);
724 
725  return this->lock(parentKey, buffer, implID, true); // force creation of a new entry
726  }
727 
731  void
733  {
734  Entry* entry = table_.fetch (key);
735  if (!entry) return;
736 
737  ASSERT (entry && (key == HashVal(*entry)));
738  release (*entry);
739  }
740 
741  void
742  release (Entry const& entry)
743  {
744  if (FREE != entry.state())
745  throw error::Logic ("Attempt to release a buffer still in use"
746  , error::LUMIERA_ERROR_LIFECYCLE);
747 
748  table_.remove (HashVal(entry));
749  }
750 
751 
752 
753  private:
754 
755  template<typename PAR, typename DEF>
756  Key
757  trackKey (PAR parent, DEF specialisation)
758  {
759  Key newKey (parent,specialisation);
760  maybeStore (newKey);
761  return newKey;
762  }
763 
764  void
765  maybeStore (Key const& key)
766  {
767  if (isKnown (key)) return;
768  table_.store (Entry (key, NULL));
769  }
770 
771  Entry&
772  store_and_lock (Entry const& metadata)
773  {
774  Entry& newEntry = table_.store (metadata);
775  try
776  {
777  newEntry.invokeEmbeddedCtor();
778  ENSURE (LOCKED == newEntry.state());
779  ENSURE (newEntry.access());
780  }
781  catch(...)
782  {
783  newEntry.mark(FREE);
784  throw;
785  }
786  return newEntry;
787  }
788  };
789 
790 
791 
792 
793 
794 }} // namespace proc::engine
795 #endif
void maybeStore(Key const &key)
A marker data type used in metadata / buffer management of the render engine.
Key key(Key const &parentKey, TypeHandler const &instanceFunc)
create a sub-type, using a different type/handler functor
abstract entry, not yet allocated
Description of a Buffer-"type".
NoUsableHashDefinition hash_value(...)
declared for metaprogramming only, never defined
Entry * fetch(HashVal hashID)
fetch metadata record, if any
LumieraError< LERR_(INVALID)> Invalid
Definition: error.hpp:216
Entry & lock(void *newBuffer)
allocated buffer, no longer in use
#define ERROR_LOG_AND_IGNORE(_FLAG_, _OP_DESCR_)
convenience shortcut for a sequence of catch blocks just logging and consuming an error...
Definition: error.hpp:272
Key trackKey(PAR parent, DEF specialisation)
Any copy and copy construction prohibited.
Definition: nocopy.hpp:46
inline string literal This is a marker type to indicate that
Definition: symbol.hpp:75
static Key forEntry(Key const &parent, const void *bufferAddr, LocalKey const &implID=UNSPECIFIC)
build derived Key for a concrete buffer Entry
A pair of functors to maintain a datastructure within a buffer.
typename meta::Strip< CON >::TypeReferred::iterator iterator
This header is for including and configuring NoBug.
Entry & lock(Key const &parentKey, void *concreteBuffer, LocalKey const &implID=UNSPECIFIC, bool onlyNew=false)
core operation to access or create a concrete buffer metadata entry.
(Hash)Table to store and manage buffer metadata.
Entry & markLocked(Key const &parentKey, void *buffer, LocalKey const &implID=UNSPECIFIC)
combine the type (Key) with a concrete buffer, thereby marking this buffer as locked.
Entry(Key const &parent, void *bufferPtr=0, LocalKey const &implID=UNSPECIFIC)
allocated buffer, returned from client
Key const & key(Key const &parentKey, void *concreteBuffer, LocalKey const &implID=UNSPECIFIC)
shortcut to access the Key part of a (probably new) Entry describing a concrete buffer at the given a...
BufferMetadata(Literal implementationID)
establish a metadata registry.
Key key(size_t storageSize, TypeHandler instanceFunc=RAW_BUFFER, LocalKey specifics=UNSPECIFIC)
combine the distinguishing properties into a single type key, which will be known/remembered from tha...
std::unordered_map< HashVal, Entry > MetadataStore
Key key(Key const &parentKey, LocalKey specifics)
create a sub-type, using a different private-ID (implementation defined)
void release(HashVal key)
purge the bare metadata Entry from the metadata tables.
static void verify_is_free(std::pair< HashVal, Entry > const &e)
Derived specific exceptions within Lumiera&#39;s exception hierarchy.
Definition: error.hpp:196
Key(Key const &parent, TypeHandler const &differingTypeHandlerFunctions)
create a derived buffer type description.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
typename meta::Strip< CON >::TypeReferred::const_iterator const_iterator
#define LERR_(_NAME_)
Definition: error.hpp:58
return NULL
Definition: llist.h:596
allocated buffer blocked by protocol failure
Entry & mark(BufferState newState)
Buffer state machine.
Registry for managing buffer metadata.
Marker types to indicate a literal string and a Symbol.
LocalKey const & localKey() const
Entry & invalidate(bool invokeDtor=true)
bool isLocked() const
is this Entry currently associated to a concrete buffer? Is this buffer in use?
bool isLocked(HashVal key) const
const Entry * fetch(HashVal hashID) const
LumieraError< LERR_(LOGIC)> Logic
Definition: error.hpp:212
an opaque ID to be used by the BufferProvider implementation.
Helper holding a pair of type-build-up and destruction functors.
Lumiera error handling (C++ interface).
Hash value types and utilities.
size_t HashVal
a STL compatible hash value
Definition: hash-value.h:56
bool isKnown(HashVal key) const
void release(Entry const &entry)
Key(Key const &parent, LocalKey anotherTypeSpecificInternalID)
create a derived buffer type description.
Key(Key const &parent, size_t differingStorageSize)
create a derived buffer type description.
Proc-Layer implementation namespace root.
Definition: id-scheme.hpp:63
bool isTypeKey() const
is this Entry just an (abstract) placeholder for a type?
Entry & store_and_lock(Entry const &metadata)
disable_if< can_IterForEach< Container >, FUN > for_each(Container const &coll, FUN doIt)
operate on all elements of a STL container.
A complete metadata Entry, based on a Key.
allocated buffer actively in use
ENSURE(r==&pq)
Perform operations "for each element" of a collection.
void useTypeHandlerFrom(Key const &ref)
Key(HashVal familyID, size_t storageSize)
build a standard basic key describing a kind of Buffer.
Entry & store(Entry const &newEntry)
store a copy of the given new metadata entry.
LumieraError< LERR_(FATAL), Logic > Fatal
Definition: error.hpp:213
BufferState
Buffer states usable within BufferProvider and stored within the metadata.