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 <list> // use for LRU ordering
30 #include <map>  // used for cache storage
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) = default;
match(const vtkExodusIICacheKey & other,const vtkExodusIICacheKey & pattern)61   bool match(const vtkExodusIICacheKey& other, const vtkExodusIICacheKey& pattern) const
62   {
63     if (pattern.Time && this->Time != other.Time)
64       return false;
65     if (pattern.ObjectType && this->ObjectType != other.ObjectType)
66       return false;
67     if (pattern.ObjectId && this->ObjectId != other.ObjectId)
68       return false;
69     if (pattern.ArrayId && this->ArrayId != other.ArrayId)
70       return false;
71     return true;
72   }
73   bool operator<(const vtkExodusIICacheKey& other) const
74   {
75     if (this->Time < other.Time)
76       return true;
77     else if (this->Time > other.Time)
78       return false;
79     if (this->ObjectType < other.ObjectType)
80       return true;
81     else if (this->ObjectType > other.ObjectType)
82       return false;
83     if (this->ObjectId < other.ObjectId)
84       return true;
85     else if (this->ObjectId > other.ObjectId)
86       return false;
87     if (this->ArrayId < other.ArrayId)
88       return true;
89     return false;
90   }
91 };
92 
93 class vtkExodusIICacheEntry;
94 class vtkExodusIICache;
95 class vtkDataArray;
96 
97 typedef std::map<vtkExodusIICacheKey, vtkExodusIICacheEntry*> vtkExodusIICacheSet;
98 typedef std::map<vtkExodusIICacheKey, vtkExodusIICacheEntry*>::iterator vtkExodusIICacheRef;
99 typedef std::list<vtkExodusIICacheRef> vtkExodusIICacheLRU;
100 typedef std::list<vtkExodusIICacheRef>::iterator vtkExodusIICacheLRURef;
101 
102 class VTKIOEXODUS_EXPORT vtkExodusIICacheEntry
103 {
104 public:
105   vtkExodusIICacheEntry();
106   vtkExodusIICacheEntry(vtkDataArray* arr);
107   vtkExodusIICacheEntry(const vtkExodusIICacheEntry& other);
108 
109   ~vtkExodusIICacheEntry();
110 
GetValue()111   vtkDataArray* GetValue() { return this->Value; }
112 
113 protected:
114   vtkDataArray* Value;
115   vtkExodusIICacheLRURef LRUEntry;
116 
117   friend class vtkExodusIICache;
118 };
119 
120 class VTKIOEXODUS_EXPORT vtkExodusIICache : public vtkObject
121 {
122 public:
123   static vtkExodusIICache* New();
124   vtkTypeMacro(vtkExodusIICache, vtkObject);
125   void PrintSelf(ostream& os, vtkIndent indent) override;
126 
127   /// Empty the cache
128   void Clear();
129 
130   /// Set the maximum allowable cache size. This will remove cache entries if the capacity is
131   /// reduced below the current size.
132   void SetCacheCapacity(double sizeInMiB);
133 
134   /** See how much cache space is left.
135    * This is the difference between the capacity and the size of the cache.
136    * The result is in MiB.
137    */
GetSpaceLeft()138   double GetSpaceLeft() { return this->Capacity - this->Size; }
139 
140   /** Remove cache entries until the size of the cache is at or below the given size.
141    * Returns a nonzero value if deletions were required.
142    */
143   int ReduceToSize(double newSize);
144 
145   /// Insert an entry into the cache (this can remove other cache entries to make space).
146   void Insert(vtkExodusIICacheKey& key, vtkDataArray* value);
147 
148   /** Determine whether a cache entry exists. If it does, return it -- otherwise return nullptr.
149    * If a cache entry exists, it is marked as most recently used.
150    */
151   vtkDataArray*& Find(const vtkExodusIICacheKey&);
152 
153   /** Invalidate a cache entry (drop it from the cache) if the key exists.
154    * This does nothing if the cache entry does not exist.
155    * Returns 1 if the cache entry existed prior to this call and 0 otherwise.
156    */
157   int Invalidate(const vtkExodusIICacheKey& key);
158 
159   /** Invalidate all cache entries matching a specified pattern, dropping all matches from the
160    * cache. Any nonzero entry in the \a pattern forces a comparison between the corresponding value
161    * of \a key. Any cache entries satisfying all the comparisons will be dropped. If pattern is
162    * entirely zero, this will empty the entire cache. This is useful for invalidating all entries of
163    * a given object type.
164    *
165    * Returns the number of cache entries dropped.
166    * It is not an error to specify an empty range -- 0 will be returned if one is given.
167    */
168   int Invalidate(const vtkExodusIICacheKey& key, const vtkExodusIICacheKey& pattern);
169 
170 protected:
171   /// Default constructor
172   vtkExodusIICache();
173 
174   /// Destructor.
175   ~vtkExodusIICache() override;
176 
177   /// Avoid (some) FP problems
178   void RecomputeSize();
179 
180   /// The capacity of the cache (i.e., the maximum size of all arrays it contains) in MiB.
181   double Capacity;
182 
183   /// The current size of the cache (i.e., the size of the all the arrays it currently contains) in
184   /// MiB.
185   double Size;
186 
187   /** A least-recently-used (LRU) cache to hold arrays.
188    * During RequestData the cache may contain more than its maximum size since
189    * the user may request more data than the cache can hold. However, the cache
190    * is expunged whenever a new array is loaded. Never count on the cache holding
191    * what you request for very long.
192    */
193   vtkExodusIICacheSet Cache;
194 
195   /// The actual LRU list (indices into the cache ordered least to most recently used).
196   vtkExodusIICacheLRU LRU;
197 
198 private:
199   vtkExodusIICache(const vtkExodusIICache&) = delete;
200   void operator=(const vtkExodusIICache&) = delete;
201 };
202 #endif // vtkExodusIICache_h
203