Lumiera 0.pre.04~rc.1
»edit your freedom«
Loading...
Searching...
No Matches
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)
5 2011, Hermann Vosseler <Ichthyostega@web.de>
6
7  **Lumiera** is free software; you can redistribute it and/or modify it
8  under the terms of the GNU General Public License as published by the
9  Free Software Foundation; either version 2 of the License, or (at your
10  option) any later version. See the file COPYING for further details.
11
12*/
13
44#ifndef STEAM_ENGINE_BUFFR_METADATA_H
45#define STEAM_ENGINE_BUFFR_METADATA_H
46
47
48#include "lib/error.hpp"
49#include "lib/symbol.hpp"
50#include "lib/hash-value.h"
51#include "lib/util-foreach.hpp"
52#include "include/logging.h"
53#include "steam/streamtype.hpp"
56#include "lib/nocopy.hpp"
57
58#include <unordered_map>
59
60
61namespace steam {
62namespace engine {
63
64 using lib::HashVal;
65 using lib::Literal;
66 using util::for_each;
67
68 namespace error = lumiera::error;
69
70 namespace metadata {
72
73 class Key;
74 class Entry;
75 }
76 class BufferMetadata;
77
78
79
80
93
94
95
96
97
98
99 namespace { // internal constants to mark the default case
100
101 inline bool
102 nontrivial (TypeHandler const& toVerify)
103 {
104 return TypeHandler::RAW != toVerify;
105 }
106
107 inline bool
108 nontrivial (LocalTag const& toVerify)
109 {
110 return LocalTag::UNKNOWN != toVerify;
111 }
112 }
113
114
115
116 /* === Metadata Implementation === */
117
118 namespace metadata {
119
120 namespace { // details of hash calculation
121 template<typename VAL>
122 HashVal
123 chainedHash(HashVal accumulatedHash, VAL changedValue)
124 {
125 boost::hash_combine (accumulatedHash, changedValue);
126 return accumulatedHash;
127 }
128 }
129
130
137 class Key
138 {
139 HashVal parent_;
140 HashVal hashID_;
141
142 protected:
146
147
148 public:
155 Key (HashVal familyID, size_t storageSize)
156 : parent_(familyID)
157 , hashID_(chainedHash (familyID, storageSize))
160 , specifics_(LocalTag::UNKNOWN)
161 { }
162
163 // standard copy operations permitted
164
169 Key (Key const& parent, size_t differingStorageSize)
170 : parent_(parent.hashID_)
171 , hashID_(chainedHash (parent_, differingStorageSize))
172 , storageSize_(differingStorageSize) // differing from parent
174 , specifics_(parent.specifics_)
175 { }
176
177
182 Key (Key const& parent, TypeHandler const& differingTypeHandlerFunctions)
183 : parent_(parent.hashID_)
184 , hashID_(chainedHash (parent_, differingTypeHandlerFunctions))
185 , storageSize_(parent.storageSize_)
186 , instanceFunc_(differingTypeHandlerFunctions) // differing from parent
187 , specifics_(parent.specifics_)
188 { }
189
190
195 Key (Key const& parent, LocalTag anotherTypeSpecificInternalTag)
196 : parent_(parent.hashID_)
197 , hashID_(chainedHash (parent_, anotherTypeSpecificInternalTag))
198 , storageSize_(parent.storageSize_)
200 , specifics_(anotherTypeSpecificInternalTag) // differing from parent
201 { }
202
203
210 static Key
211 forEntry (Key const& parent, const Buff* bufferAddr, LocalTag const& localTag =LocalTag::UNKNOWN)
212 {
213 Key newKey{parent}; // copy of parent as baseline
214 if (nontrivial(localTag))
215 {
216 if (nontrivial(parent.specifics_))
217 throw error::Logic{"Implementation defined local key should not be overridden. "
218 "Underlying buffer type already defines a nontrivial LocalTag"};
219 newKey.parent_ = HashVal(parent);
220 newKey.hashID_ = chainedHash(newKey.hashID_, localTag);
221 newKey.specifics_ = localTag;
222 }
223 if (bufferAddr)
224 {
225 newKey.parent_ = HashVal(parent);
226 newKey.hashID_ = chainedHash(newKey.hashID_, bufferAddr);
227 }
228 return newKey;
229 }
230
231 void
233 {
234 if (nontrivial(this->instanceFunc_))
235 throw error::Logic ("unable to supersede an already attached TypeHandler"
236 , LERR_(LIFECYCLE));
238 }
239
240
241 LocalTag const& localTag() const { return specifics_;}
242 size_t storageSize() const { return storageSize_; }
243
244 HashVal parentKey() const { return parent_;}
245 operator HashVal() const { return hashID_;}
246 };
247
248
263 class Entry
264 : public Key
265 {
268
269 protected:
270 Entry (Key const& parent
271 ,Buff* bufferPtr =nullptr
272 ,LocalTag const& specialTag =LocalTag::UNKNOWN
273 )
274 : Key{Key::forEntry (parent, bufferPtr, specialTag)}
275 , state_{bufferPtr? LOCKED:NIL}
276 , buffer_{bufferPtr}
277 { }
278
281
282 // standard copy operations permitted
283
284 public:
287 bool
288 isLocked() const
289 {
290 ASSERT (!buffer_ or (NIL != state_ and FREE != state_));
291 return bool(buffer_);
292 }
293
297 bool
298 isTypeKey() const
299 {
300 return NIL == state_ and not buffer_;
301 }
302
303
305 state() const
306 {
307 return state_;
308 }
309
310 Buff*
312 {
315
316 ENSURE (buffer_);
317 return buffer_;
318 }
319
321 Entry&
322 mark (BufferState newState)
323 {
325
326 if ( (state_ == FREE and newState == LOCKED)
327 or (state_ == LOCKED and newState == EMITTED)
328 or (state_ == LOCKED and newState == BLOCKED)
329 or (state_ == LOCKED and newState == FREE)
330 or (state_ == EMITTED and newState == BLOCKED)
331 or (state_ == EMITTED and newState == FREE)
332 or (state_ == BLOCKED and newState == FREE))
333 {
334 // allowed transition
335 if (newState == FREE)
337 if (newState == LOCKED)
339 state_ = newState;
340 return *this;
341 }
342
343 throw error::Fatal ("Invalid buffer state transition.");
344 }
345
346 Entry&
347 lock (Buff* newBuffer)
348 {
350 buffer_ = newBuffer;
351 return mark (LOCKED);
352 }
353
354 Entry&
355 invalidate (bool invokeDtor =true)
356 {
357 if (buffer_ and invokeDtor)
359 buffer_ = nullptr;
360 state_ = FREE;
361 return *this;
362 }
363
364
365 protected:
369 void
376
380 void
388
389 private:
390 void
392 {
393 if (NIL == state_)
394 throw error::Fatal ("Buffer metadata entry with state==NIL encountered."
395 "State transition logic broken (programming error)"
396 , LERR_(LIFECYCLE));
397 }
398
399 void
401 {
402 if (FREE == state_)
403 throw error::Logic ("Buffer is inaccessible (marked as free). "
404 "Need a new buffer pointer in order to lock an entry. "
405 "You should invoke markLocked(buffer) prior to access."
406 , LERR_(LIFECYCLE));
407 }
408
409 void
411 {
412 if (FREE != state_)
413 throw error::Logic ("Buffer already in use"
414 , LERR_(LIFECYCLE));
415 REQUIRE (!buffer_, "Buffer marked as free, "
416 "but buffer pointer is set.");
417 }
418
419 void
421 {
422 if (!buffer_)
423 throw error::Fatal ("Need concrete buffer for any further operations");
424 }
425 };
426
427
428
438 class Table
439 {
440 using MetadataStore = std::unordered_map<HashVal,Entry>;
441
443
444 public:
446
451 Entry*
452 fetch (HashVal hashID)
453 {
454 MetadataStore::iterator pos = entries_.find (hashID);
455 if (pos != entries_.end())
456 return &(pos->second);
457 else
458 return NULL;
459 }
460
461 const Entry*
462 fetch (HashVal hashID) const
463 {
464 MetadataStore::const_iterator pos = entries_.find (hashID);
465 if (pos != entries_.end())
466 return &(pos->second);
467 else
468 return NULL;
469 }
470
479 Entry&
480 store (Entry const& newEntry)
481 {
482 REQUIRE (!fetch (newEntry), "duplicate buffer metadata entry");
483 MetadataStore::iterator pos = entries_.emplace (HashVal(newEntry), newEntry)
484 .first;
485
486 ENSURE (pos != entries_.end());
487 return pos->second;
488 }
489
490 void
491 remove (HashVal hashID)
492 {
493 uint cnt = entries_.erase (hashID);
494 ENSURE (cnt, "entry to remove didn't exist");
495 }
496
497 private:
498 void
500 try
501 {
502 for_each (entries_, verify_is_free);
503 }
504 ERROR_LOG_AND_IGNORE (engine,"Shutdown of BufferProvider metadata store")
505
506 static void
507 verify_is_free (std::pair<HashVal, Entry> const& e)
508 {
509 WARN_IF (e.second.isLocked(), engine,
510 "Buffer still in use while shutting down BufferProvider? ");
511 }
512 };
513
514 }//namespace metadata
515
516
517
518
519
520 /* ===== Buffer Metadata Frontend ===== */
521
537 {
539 HashVal family_;
540
543
544 public:
547
555 BufferMetadata (Literal implementationID)
556 : id_(implementationID)
557 , family_(hash_value(id_))
558 { }
559
570 Key
571 key ( size_t storageSize
572 , TypeHandler instanceFunc =TypeHandler::RAW
573 , LocalTag specifics =LocalTag::UNKNOWN)
574 {
575 REQUIRE (storageSize);
576 Key typeKey = trackKey (family_, storageSize);
577
578 if (nontrivial(instanceFunc))
579 typeKey = trackKey (typeKey, instanceFunc);
580
581 if (nontrivial(specifics))
582 typeKey = trackKey (typeKey, specifics);
583
584 return typeKey;
585 }
586
588 Key
589 key (Key const& parentKey, TypeHandler const& instanceFunc)
590 {
591 return trackKey (parentKey, instanceFunc);
592 }
593
596 Key
597 key (Key const& parentKey, LocalTag specifics)
598 {
599 return trackKey (parentKey, specifics);
600 }
601
606 Key const&
607 key (Key const& parentKey, metadata::Buff* concreteBuffer, LocalTag const& specifics =LocalTag::UNKNOWN)
608 {
609 Key derivedKey = Key::forEntry (parentKey, concreteBuffer, specifics);
610 Entry* existing = table_.fetch (derivedKey);
611
612 return existing? *existing
613 : markLocked (parentKey,concreteBuffer,specifics);
614 }
615
640 Entry&
641 lock (Key const& parentKey
642 ,metadata::Buff* concreteBuffer
643 ,LocalTag const& specifics =LocalTag::UNKNOWN
644 ,bool onlyNew =false)
645 {
646 if (!concreteBuffer)
647 throw error::Invalid{"Attempt to lock a slot for a NULL buffer"
648 , LERR_(BOTTOM_VALUE)};
649
650 Entry newEntry{parentKey, concreteBuffer, specifics};
651 Entry* existing = table_.fetch (newEntry);
652
653 if (existing and onlyNew)
654 throw error::Logic{"Attempt to lock a slot for a new buffer, "
655 "while actually the old buffer is still locked"
656 , LERR_(LIFECYCLE)};
657 if (existing and existing->isLocked())
658 throw error::Logic{"Attempt to re-lock a buffer still in use"
659 , LERR_(LIFECYCLE)};
660
661 if (not existing)
662 return store_as_locked (newEntry); // actual creation
663 else
664 return existing->lock (concreteBuffer);
665 }
666
675 Entry&
676 get (HashVal hashID)
677 {
678 Entry* entry = table_.fetch (hashID);
679 if (!entry)
680 throw error::Invalid ("Attempt to access an unknown buffer metadata entry");
681
682 return *entry;
683 }
684
685 bool
686 isKnown (HashVal key) const
687 {
688 return bool(table_.fetch (key));
689 }
690
691 bool
692 isLocked (HashVal key) const
693 {
694 const Entry* entry = table_.fetch (key);
695 return entry
696 and entry->isLocked();
697 }
698
699
700
701 /* == memory management operations == */
702
713 Entry&
714 markLocked (Key const& parentKey, metadata::Buff* buffer, LocalTag const& specifics =LocalTag::UNKNOWN)
715 {
716 if (!buffer)
717 throw error::Fatal{"Attempt to lock for a NULL buffer. Allocation floundered?"
718 , LERR_(BOTTOM_VALUE)};
719
720 return this->lock (parentKey, buffer, specifics, true); // force creation of a new entry
721 }
722
726 void
727 release (HashVal key)
728 {
729 Entry* entry = table_.fetch (key);
730 if (!entry) return;
731
732 ASSERT (entry and (key == HashVal(*entry)));
733 release (*entry);
734 }
735
736 void
737 release (Entry const& entry)
738 {
739 if (FREE != entry.state())
740 throw error::Logic{"Attempt to release a buffer still in use"
741 , LERR_(LIFECYCLE)};
742
743 table_.remove (HashVal(entry));
744 }
745
746
747
748 private:
749
750 template<typename PAR, typename DEF>
751 Key
752 trackKey (PAR parent, DEF specialisation)
753 {
754 Key newKey{parent, specialisation};
755 maybeStore (newKey);
756 return newKey;
757 }
758
759 void
761 {
762 if (isKnown (key)) return;
763 table_.store (Entry{key, nullptr});
764 }
765
773 Entry&
774 store_as_locked (Entry const& metadata)
775 {
776 REQUIRE (metadata.isLocked());
777 Entry& newEntry = table_.store (metadata);
778 try
779 {
780 newEntry.invokeEmbeddedCtor();
781 ENSURE (LOCKED == newEntry.state());
782 ENSURE (newEntry.access());
783 }
784 catch(...)
785 {
786 newEntry.mark(FREE);
787 throw;
788 }
789 return newEntry;
790 }
791 };
792
793
794
795
796}} // namespace steam::engine
797#endif /*STEAM_ENGINE_BUFFR_METADATA_H*/
A marker data type used in metadata / buffer management of the render engine.
Inline string literal.
Definition symbol.hpp:78
Derived specific exceptions within Lumiera's exception hierarchy.
Definition error.hpp:193
placeholder type for the contents of a data buffer.
Registry for managing buffer metadata.
bool isLocked(HashVal key) const
Entry & store_as_locked(Entry const &metadata)
store a fully populated entry immediately starting with locked state
Entry & markLocked(Key const &parentKey, metadata::Buff *buffer, LocalTag const &specifics=LocalTag::UNKNOWN)
combine the type (Key) with a concrete buffer, thereby marking this buffer as locked.
Entry & lock(Key const &parentKey, metadata::Buff *concreteBuffer, LocalTag const &specifics=LocalTag::UNKNOWN, bool onlyNew=false)
core operation to access or create a concrete buffer metadata entry.
Key const & key(Key const &parentKey, metadata::Buff *concreteBuffer, LocalTag const &specifics=LocalTag::UNKNOWN)
shortcut to access the Key part of a (probably new) Entry describing a concrete buffer at the given a...
void release(Entry const &entry)
bool isKnown(HashVal key) const
Entry & get(HashVal hashID)
access the metadata record registered with the given hash key.
Key key(Key const &parentKey, LocalTag specifics)
create a sub-type, using a different private-ID (implementation defined)
BufferMetadata(Literal implementationID)
establish a metadata registry.
void release(HashVal key)
purge the bare metadata Entry from the metadata tables.
Key key(Key const &parentKey, TypeHandler const &instanceFunc)
create a sub-type, using a different type/handler functor
Key trackKey(PAR parent, DEF specialisation)
Key key(size_t storageSize, TypeHandler instanceFunc=TypeHandler::RAW, LocalTag specifics=LocalTag::UNKNOWN)
combine the distinguishing properties into a single type key, which will be known/remembered from tha...
an opaque mark to be used by the BufferProvider implementation.
static const LocalTag UNKNOWN
Marker when no distinct local key is given.
A complete metadata Entry, based on a Key.
bool isTypeKey() const
is this Entry just an (abstract) placeholder for a type?
Entry & mark(BufferState newState)
Buffer state machine.
bool isLocked() const
is this Entry currently associated to a concrete buffer? Is this buffer in use?
Entry(Key const &parent, Buff *bufferPtr=nullptr, LocalTag const &specialTag=LocalTag::UNKNOWN)
Entry & invalidate(bool invokeDtor=true)
Entry & lock(Buff *newBuffer)
Description of a Buffer-"type".
Key(Key const &parent, LocalTag anotherTypeSpecificInternalTag)
create a derived buffer type description.
Key(HashVal familyID, size_t storageSize)
build a standard basic key describing a kind of Buffer.
void useTypeHandlerFrom(Key const &ref)
static Key forEntry(Key const &parent, const Buff *bufferAddr, LocalTag const &localTag=LocalTag::UNKNOWN)
build derived Key for a concrete buffer Entry
Key(Key const &parent, size_t differingStorageSize)
create a derived buffer type description.
Key(Key const &parent, TypeHandler const &differingTypeHandlerFunctions)
create a derived buffer type description.
LocalTag const & localTag() const
(Hash)Table to store and manage buffer metadata.
Entry & store(Entry const &newEntry)
store a copy of the given new metadata entry.
std::unordered_map< HashVal, Entry > MetadataStore
Entry * fetch(HashVal hashID)
fetch metadata record, if any
static void verify_is_free(std::pair< HashVal, Entry > const &e)
const Entry * fetch(HashVal hashID) const
Any copy and copy construction prohibited.
Definition nocopy.hpp:38
Lumiera error handling (C++ interface).
#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:267
#define LERR_(_NAME_)
Definition error.hpp:45
Hash value types and utilities.
unsigned int uint
Definition integral.hpp:29
return NULL
Definition llist.h:586
This header is for including and configuring NoBug.
size_t HashVal
a STL compatible hash value
Definition hash-value.h:52
LumieraError< LERR_(FATAL), Logic > Fatal
Definition error.hpp:208
LumieraError< LERR_(LOGIC)> Logic
Definition error.hpp:207
LumieraError< LERR_(INVALID)> Invalid
Definition error.hpp:211
STL namespace.
HashVal chainedHash(HashVal accumulatedHash, VAL changedValue)
BufferState
Buffer states usable within BufferProvider and stored within the metadata.
@ BLOCKED
allocated buffer blocked by protocol failure
@ NIL
abstract entry, not yet allocated
@ LOCKED
allocated buffer actively in use
@ FREE
allocated buffer, no longer in use
@ EMITTED
allocated buffer, returned from client
Steam-Layer implementation namespace root.
disable_if< can_IterForEach< Container >, FUN > for_each(Container const &coll, FUN doIt)
operate on all elements of a STL container.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
Framework for classification of media streams.
A pair of functors to maintain a datastructure within a buffer.
static const TypeHandler RAW
Marker for the default case: raw buffer without type handling.
Marker types to indicate a literal string and a Symbol.
Helper holding a pair of type-build-up and destruction functors.
Perform operations "for each element" of a collection.