DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
DataCellCache.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2014 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 
16 using System;
17 
18 using Deveel.Data.DbSystem;
19 using Deveel.Diagnostics;
20 
21 namespace Deveel.Data.Caching {
37  public sealed class DataCellCache {
41  private static readonly int[] PRIME_LIST = new int[]
42  {
43  3001, 4799, 13999, 15377, 21803, 24247, 35083, 40531, 43669, 44263, 47387,
44  50377, 57059, 57773, 59399, 59999, 75913, 96821, 140551, 149011, 175633,
45  176389, 183299, 205507, 209771, 223099, 240259, 258551, 263909, 270761,
46  274679, 286129, 290531, 296269, 298021, 300961, 306407, 327493, 338851,
47  351037, 365489, 366811, 376769, 385069, 410623, 430709, 433729, 434509,
48  441913, 458531, 464351, 470531, 475207, 479629, 501703, 510709, 516017,
49  522211, 528527, 536311, 539723, 557567, 593587, 596209, 597451, 608897,
50  611069, 642547, 670511, 677827, 679051, 688477, 696743, 717683, 745931,
51  757109, 760813, 763957, 766261, 781559, 785597, 788353, 804493, 813559,
52  836917, 854257, 859973, 883217, 884789, 891493, 902281, 910199, 915199,
53  930847, 939749, 940483, 958609, 963847, 974887, 983849, 984299, 996211,
54  999217, 1007519, 1013329, 1014287, 1032959, 1035829, 1043593, 1046459,
55  1076171, 1078109, 1081027, 1090303, 1095613, 1098847, 1114037, 1124429,
56  1125017, 1130191, 1159393, 1170311, 1180631, 1198609, 1200809, 1212943,
57  1213087, 1226581, 1232851, 1287109, 1289867, 1297123, 1304987, 1318661,
58  1331107, 1343161, 1345471, 1377793, 1385117, 1394681, 1410803, 1411987,
59  1445261, 1460497, 1463981, 1464391, 1481173, 1488943, 1491547, 1492807,
60  1528993, 1539961, 1545001, 1548247, 1549843, 1551001, 1553023, 1571417,
61  1579099, 1600259, 1606153, 1606541, 1639751, 1649587, 1657661, 1662653,
62  1667051, 1675273, 1678837, 1715537, 1718489, 1726343, 1746281, 1749107,
63  1775489, 1781881, 1800157, 1806859, 1809149, 1826753, 1834607, 1846561,
64  1849241, 1851991, 1855033, 1879931, 1891133, 1893737, 1899137, 1909513,
65  1916599, 1917749, 1918549, 1919347, 1925557, 1946489, 1961551, 1965389,
66  2011073, 2033077, 2039761, 2054047, 2060171, 2082503, 2084107, 2095099,
67  2096011, 2112193, 2125601, 2144977, 2150831, 2157401, 2170141, 2221829,
68  2233019, 2269027, 2270771, 2292449, 2299397, 2303867, 2309891, 2312407,
69  2344301, 2348573, 2377007, 2385113, 2386661, 2390051, 2395763, 2422999,
70  2448367, 2500529, 2508203, 2509841, 2513677, 2516197, 2518151, 2518177,
71  2542091, 2547469, 2549951, 2556991, 2563601, 2575543, 2597629, 2599577,
72  2612249, 2620003, 2626363, 2626781, 2636773, 2661557, 2674297, 2691571,
73  2718269, 2725691, 2729381, 2772199, 2774953, 2791363, 2792939, 2804293,
74  2843021, 2844911, 2851313, 2863519, 2880797, 2891821, 2897731, 2904887,
75  2910251, 2928943, 2958341, 2975389
76  };
77 
81  private readonly DCCache cache;
82 
86  private readonly SystemContext context;
87 
91  private long currentCacheSize;
92 
96  private int maxCellSize;
97 
109  internal DataCellCache(SystemContext context, ICache systemCache, int maxCacheSize, int maxCellSize, int hashSize) {
110  this.context = context;
111  this.maxCellSize = maxCellSize;
112 
113  cache = new DCCache(this, systemCache, hashSize, maxCacheSize);
114  }
115 
116  internal DataCellCache(SystemContext context, ICache systemCache, int maxCacheSize, int maxCellSize)
117  : this(context, systemCache, maxCacheSize, maxCellSize, 88547) {
118  // Good prime number hash size
119  }
120 
124  public long CurrentCacheSize {
125  get {
126  lock (this) {
127  return currentCacheSize;
128  }
129  }
130  }
131 
140  public void AlterCacheDynamics(int maxCacheSize, int maxCellSize) {
141  lock (this) {
142  this.maxCellSize = maxCellSize;
143  cache.SetCacheSize(maxCacheSize);
144  }
145  }
146 
153  private static int AmountMemory(DataObject cell) {
154  return 16 + cell.SizeOf();
155  }
156 
168  public void Set(int tableKey, int row, int column, DataObject cell) {
169  lock (this) {
170  int memoryUse = AmountMemory(cell);
171  if (memoryUse <= maxCellSize) {
172  // Generate the key
173  var key = new DCCacheKey(tableKey, (short)column, row);
174  // If there is an existing object here, remove it from the cache and
175  // update the current_cache_size.
176  var removedCell = (DataObject)cache.Remove(key);
177  if (removedCell != null) {
178  currentCacheSize -= AmountMemory(removedCell);
179  }
180  // Put the new entry in the cache
181  cache.Set(key, cell);
182  currentCacheSize += memoryUse;
183  } else {
184  // If the object is larger than the minimum object size that can be
185  // cached, remove any existing entry (possibly smaller) from the cache.
186  Remove(tableKey, row, column);
187  }
188  }
189  }
190 
201  public DataObject Get(int tableKey, int row, int column) {
202  lock (this) {
203  return (DataObject) cache.Get(new DCCacheKey(tableKey, (short) column, row));
204  }
205  }
206 
222  public DataObject Remove(int tableKey, int row, int column) {
223  lock (this) {
224  var cell = (DataObject)cache.Remove(new DCCacheKey(tableKey, (short) column, row));
225  if (cell != null)
226  currentCacheSize -= AmountMemory(cell);
227  return cell;
228  }
229  }
230 
234  public void Clear() {
235  lock (this) {
236  if (cache.NodeCount == 0 && currentCacheSize != 0) {
237  context.Logger.Error(this, "Assertion failed - if nodeCount = 0 then current_cache_size must also be 0.");
238  }
239  if (cache.NodeCount != 0) {
240  cache.Clear();
241  context.Stats.Increment(StatsDefaultKeys.DataCellCacheTotalWipes);
242  }
243  currentCacheSize = 0;
244  }
245  }
246 
251  private void ReduceCacheSize(long val) {
252  currentCacheSize -= val;
253  }
254 
255  // ---------- Primes ----------
256 
263  internal static int ClosestPrime(int value) {
264  for (int i = 0; i < PRIME_LIST.Length; ++i) {
265  if (PRIME_LIST[i] >= value) {
266  return PRIME_LIST[i];
267  }
268  }
269  // Return the last prime
270  return PRIME_LIST[PRIME_LIST.Length - 1];
271  }
272 
273  #region DCCache
274 
278  private sealed class DCCache : CacheWrapper {
279  private readonly DataCellCache cache;
280 
284  private int maxCacheSize;
285 
286  public DCCache(DataCellCache cache, ICache systemCache, int cache_hash_size, int max_cache_size)
287  : base(systemCache, cache_hash_size) {
288  this.cache = cache;
289  maxCacheSize = max_cache_size;
290  }
291 
292 
300  public void SetCacheSize(int cache_size) {
301  maxCacheSize = cache_size;
302  CheckClean();
303  }
304 
305  // ----- Overwritten from Cache -----
306 
307  protected override void CheckClean() {
308  if (cache.CurrentCacheSize >= maxCacheSize) {
309  // Update the current cache size (before we wiped).
310  cache.context.Stats.Set(StatsDefaultKeys.DataCellCacheCurrentSize, (int) cache.CurrentCacheSize);
311  Clean();
312 
313  // The number of times we've cleared away old data cell nodes.
314  cache.context.Stats.Increment(StatsDefaultKeys.DataCellCacheClean);
315  }
316  }
317 
318  protected override bool WipeMoreNodes() {
319  return (cache.CurrentCacheSize >= (int) ((maxCacheSize*100L)/115L));
320  }
321 
322  protected override void OnWipingNode(Object ob) {
323  base.OnWipingNode(ob);
324 
325  // Update our memory indicator accordingly.
326  var cell = (DataObject)ob;
327  cache.ReduceCacheSize(AmountMemory(cell));
328  }
329 
330  protected override void OnGetWalks(long totalWalks, long totalGetOps) {
331  int avg = (int) ((totalWalks*1000000L)/totalGetOps);
332  cache.context.Stats.Set("DataCellCache.avg_hash_get_mul_1000000", avg);
333  cache.context.Stats.Set("DataCellCache.current_cache_size", (int) cache.CurrentCacheSize);
334  cache.context.Stats.Set("DataCellCache.current_node_count", NodeCount);
335  }
336  }
337 
338  #endregion
339 
340  #region DCCacheKey
341 
346  private struct DCCacheKey {
347  private readonly short column;
348  private readonly int row;
349  private readonly int tableId;
350 
351  internal DCCacheKey(int tableId, short column, int row) {
352  this.tableId = tableId;
353  this.column = column;
354  this.row = row;
355  }
356 
357  public override bool Equals(Object ob) {
358  DCCacheKey destKey = (DCCacheKey)ob;
359  return row == destKey.row &&
360  column == destKey.column &&
361  tableId == destKey.tableId;
362  }
363 
364  public override int GetHashCode() {
365  // Yicks - this one is the best by far!
366  return (((int) column + tableId + (row*189977))*50021) << 4;
367  }
368  }
369 
370  #endregion
371  }
372 }
static int ClosestPrime(int value)
Returns a prime number from PRIME_LIST that is the closest prime greater or equal to the given value...
long currentCacheSize
The current size of the cache.
DCCacheKey(int tableId, short column, int row)
readonly SystemContext context
The TransactionSystem that this cache is from.
DataObject Remove(int tableKey, int row, int column)
Removes a cell from the cache.
This is the context of a database system, that handles the configurations and services used by all th...
int maxCacheSize
The maximum size that the cache can grow to in bytes.
void Set(int tableKey, int row, int column, DataObject cell)
Adds a DataObject on the cache for the given row/column of the table.
static int AmountMemory(DataObject cell)
Returns an approximation of the amount of memory taken by a given DataObject.
void Clear()
Completely wipe the cache of all entries.
DataCellCache(SystemContext context, ICache systemCache, int maxCacheSize, int maxCellSize, int hashSize)
Instantiate the DataCellCache.
override void OnGetWalks(long totalWalks, long totalGetOps)
DataObject Get(int tableKey, int row, int column)
Gets a cell from the cache.
Represents a cache for accesses to the the data cells within a Table.
Represents a dynamic object that encapsulates a defined SqlType and a compatible constant ISqlObject ...
Definition: DataObject.cs:35
readonly DCCache cache
The master cache.
int maxCellSize
The maximum size of a DataCell that is allowed to go in the cache.
void ReduceCacheSize(long val)
Evaluate the cache size by the given amount.
Struct that creates an object that hashes nicely over the cache source.
Provides a contract to access a caching system.
Definition: ICache.cs:25
void AlterCacheDynamics(int maxCacheSize, int maxCellSize)
Dynamically resizes the data cell cache so it can store more/less data.
DataCellCache(SystemContext context, ICache systemCache, int maxCacheSize, int maxCellSize)
DCCache(DataCellCache cache, ICache systemCache, int cache_hash_size, int max_cache_size)
void SetCacheSize(int cache_size)
Used to dynamically alter the size of the cache.