1 #ifndef vtkExodusIICache_h
2 #define vtkExodusIICache_h
3 
4 // ============================================================================
5 // The following classes define an LRU cache for data arrays
6 // loaded by the Exodus reader. Here's how they work:
7 //
8 // The actual cache consists of two STL containers: a set of
9 // cache entries (vtkExodusIICacheEntry) and a list of
10 // cache references (vtkExodusIICacheRef). The entries in
11 // these containers are sorted for fast retrieval:
12 // 1. The cache entries are indexed by the timestep, the
13 //    object type (edge block, face set, ...), and the
14 //    object ID (if one exists). When you call Find() to
15 //    retrieve a cache entry, you provide a key containing
16 //    this information and the array is returned if it exists.
17 // 2. The list of cache references are stored in "least-recently-used"
18 //    order. The least recently referenced array is the first in
19 //    the list. Whenever you request an entry with Find(), it is
20 //    moved to the back of the list if it exists.
21 // This makes retrieving arrays O(n log n) and popping LRU
22 // entries O(1). Each cache entry stores an iterator into
23 // the list of references so that it can be located quickly for
24 // removal.
25 
26 #include "vtkIOExodusModule.h" // For export macro
27 #include "vtkObject.h"
28 
29 #include <map> // used for cache storage
30 #include <list> // use for LRU ordering
31 
32 class VTKIOEXODUS_EXPORT vtkExodusIICacheKey
33 {
34 public:
35   int Time;
36   int ObjectType;
37   int ObjectId;
38   int ArrayId;
vtkExodusIICacheKey()39   vtkExodusIICacheKey()
40   {
41     Time = -1;
42     ObjectType = -1;
43     ObjectId = -1;
44     ArrayId = -1;
45   }
vtkExodusIICacheKey(int time,int objType,int objId,int arrId)46   vtkExodusIICacheKey( int time, int objType, int objId, int arrId )
47   {
48     Time = time;
49     ObjectType = objType;
50     ObjectId = objId;
51     ArrayId = arrId;
52   }
vtkExodusIICacheKey(const vtkExodusIICacheKey & src)53   vtkExodusIICacheKey( const vtkExodusIICacheKey& src )
54   {
55     Time = src.Time;
56     ObjectType = src.ObjectType;
57     ObjectId = src.ObjectId;
58     ArrayId = src.ArrayId;
59   }
60   vtkExodusIICacheKey& operator = ( const vtkExodusIICacheKey& src )
61   {
62     Time = src.Time;
63     ObjectType = src.ObjectType;
64     ObjectId = src.ObjectId;
65     ArrayId = src.ArrayId;
66     return *this;
67   }
match(const vtkExodusIICacheKey & other,const vtkExodusIICacheKey & pattern)68   bool match( const vtkExodusIICacheKey&other, const vtkExodusIICacheKey& pattern ) const
69   {
70     if ( pattern.Time && this->Time != other.Time )
71       return false;
72     if ( pattern.ObjectType && this->ObjectType != other.ObjectType )
73       return false;
74     if ( pattern.ObjectId && this->ObjectId != other.ObjectId )
75       return false;
76     if ( pattern.ArrayId && this->ArrayId != other.ArrayId )
77       return false;
78     return true;
79   }
80   bool operator < ( const vtkExodusIICacheKey& other ) const
81   {
82     if ( this->Time < other.Time )
83       return true;
84     else if ( this->Time > other.Time )
85       return false;
86     if ( this->ObjectType < other.ObjectType )
87       return true;
88     else if ( this->ObjectType > other.ObjectType )
89       return false;
90     if ( this->ObjectId < other.ObjectId )
91       return true;
92     else if ( this->ObjectId > other.ObjectId )
93       return false;
94     if ( this->ArrayId < other.ArrayId )
95       return true;
96     return false;
97   }
98 };
99 
100 class vtkExodusIICacheEntry;
101 class vtkExodusIICache;
102 class vtkDataArray;
103 
104 typedef std::map<vtkExodusIICacheKey,vtkExodusIICacheEntry*> vtkExodusIICacheSet;
105 typedef std::map<vtkExodusIICacheKey,vtkExodusIICacheEntry*>::iterator vtkExodusIICacheRef;
106 typedef std::list<vtkExodusIICacheRef> vtkExodusIICacheLRU;
107 typedef std::list<vtkExodusIICacheRef>::iterator vtkExodusIICacheLRURef;
108 
109 class VTKIOEXODUS_EXPORT vtkExodusIICacheEntry
110 {
111 public:
112   vtkExodusIICacheEntry();
113   vtkExodusIICacheEntry( vtkDataArray* arr );
114   vtkExodusIICacheEntry( const vtkExodusIICacheEntry& other );
115 
116   ~vtkExodusIICacheEntry();
117 
GetValue()118   vtkDataArray* GetValue() { return this->Value; }
119 
120 protected:
121   vtkDataArray* Value;
122   vtkExodusIICacheLRURef LRUEntry;
123 
124   friend class vtkExodusIICache;
125 };
126 
127 class VTKIOEXODUS_EXPORT vtkExodusIICache : public vtkObject
128 {
129 public:
130   static vtkExodusIICache* New();
131   vtkTypeMacro(vtkExodusIICache,vtkObject);
132   void PrintSelf( ostream& os, vtkIndent indent ) override;
133 
134   /// Empty the cache
135   void Clear();
136 
137   /// Set the maximum allowable cache size. This will remove cache entries if the capacity is reduced below the current size.
138   void SetCacheCapacity( double sizeInMiB );
139 
140   /** See how much cache space is left.
141     * This is the difference between the capacity and the size of the cache.
142     * The result is in MiB.
143     */
GetSpaceLeft()144   double GetSpaceLeft()
145     { return this->Capacity - this->Size; }
146 
147   /** Remove cache entries until the size of the cache is at or below the given size.
148     * Returns a nonzero value if deletions were required.
149     */
150   int ReduceToSize( double newSize );
151 
152   /// Insert an entry into the cache (this can remove other cache entries to make space).
153   void Insert( vtkExodusIICacheKey& key, vtkDataArray* value );
154 
155   /** Determine whether a cache entry exists. If it does, return it -- otherwise return nullptr.
156     * If a cache entry exists, it is marked as most recently used.
157     */
158   vtkDataArray*& Find( const vtkExodusIICacheKey& );
159 
160   /** Invalidate a cache entry (drop it from the cache) if the key exists.
161     * This does nothing if the cache entry does not exist.
162     * Returns 1 if the cache entry existed prior to this call and 0 otherwise.
163     */
164   int Invalidate( const vtkExodusIICacheKey& key );
165 
166   /** Invalidate all cache entries matching a specified pattern, dropping all matches from the cache.
167     * Any nonzero entry in the \a pattern forces a comparison between the corresponding value of \a key.
168     * Any cache entries satisfying all the comparisons will be dropped.
169     * If pattern is entirely zero, this will empty the entire cache.
170     * This is useful for invalidating all entries of a given object type.
171     *
172     * Returns the number of cache entries dropped.
173     * It is not an error to specify an empty range -- 0 will be returned if one is given.
174     */
175   int Invalidate( const vtkExodusIICacheKey& key, const vtkExodusIICacheKey& pattern );
176 
177 protected:
178   /// Default constructor
179   vtkExodusIICache();
180 
181   /// Destructor.
182   ~vtkExodusIICache() override;
183 
184 
185   /// Avoid (some) FP problems
186   void RecomputeSize();
187 
188   /// The capacity of the cache (i.e., the maximum size of all arrays it contains) in MiB.
189   double Capacity;
190 
191   /// The current size of the cache (i.e., the size of the all the arrays it currently contains) in MiB.
192   double Size;
193 
194   /** A least-recently-used (LRU) cache to hold arrays.
195     * During RequestData the cache may contain more than its maximum size since
196     * the user may request more data than the cache can hold. However, the cache
197     * is expunged whenever a new array is loaded. Never count on the cache holding
198     * what you request for very long.
199     */
200   vtkExodusIICacheSet Cache;
201 
202   /// The actual LRU list (indices into the cache ordered least to most recently used).
203   vtkExodusIICacheLRU LRU;
204 
205 private:
206   vtkExodusIICache( const vtkExodusIICache& ) = delete;
207   void operator = ( const vtkExodusIICache& ) = delete;
208 };
209 #endif // vtkExodusIICache_h
210