DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
TableCellCache.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 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 
17 using System;
18 
20 
21 namespace Deveel.Data.Caching {
22  public sealed class TableCellCache : ITableCellCache, IDisposable {
23  private Cache cache;
24  private long size;
25 
26  public const int DefaultHashSize = 88547;
27 #if X64
28  public const int DefaultMaxSize = 1024*1024;
29 #else
30  public const int DefaultMaxSize = 512*512;
31 #endif
32 
33  public const int DefaultMaxCellSize = 1024*64;
34 
35  public TableCellCache(IConfiguration configuration) {
36  Configure(configuration);
37  }
38 
40  Dispose(false);
41  }
42 
43  public int MaxCellSize { get; private set; }
44 
45  public long Size {
46  get {
47  lock (this) {
48  return size;
49  }
50  }
51  }
52 
53  public void Dispose() {
54  Dispose(true);
55  GC.SuppressFinalize(this);
56  }
57 
58  private void Dispose(bool disposing) {
59  if (disposing) {
60  if (cache != null)
61  cache.Dispose();
62  }
63 
64  cache = null;
65  }
66 
67  private void ReduceCacheSize(long value) {
68  size -= value;
69  }
70 
71  private void Configure(IConfiguration config) {
72  var hashSize = DefaultHashSize;
73  var maxSize = config.GetInt32("system.tableCellCache.maxSize", DefaultMaxSize);
74  MaxCellSize = config.GetInt32("system.tableCellCache.maxCellSize", DefaultMaxCellSize);
75 
76  var baseCache = new SizeLimitedCache(maxSize);
77  cache = new Cache(this, baseCache, hashSize, maxSize);
78  }
79 
80  public void Set(CachedCell cell) {
81  var value = cell.Value;
82 
83  if (!value.IsCacheable)
84  return;
85 
86  lock (this) {
87  int memoryUse = AmountMemory(value);
88  if (memoryUse <= MaxCellSize) {
89  // Generate the key
90  var key = new CacheKey(cell.Database, cell.TableId, (int)cell.RowNumber, (short)cell.ColumnOffset);
91 
92  // If there is an existing object here, remove it from the cache and
93  // update the current_cache_size.
94  var removedCell = (DataObject)cache.Remove(key);
95  if (!Equals(removedCell, null)) {
96  size -= AmountMemory(removedCell);
97  }
98 
99  // Put the new entry in the cache
100  cache.Set(key, value);
101  size += memoryUse;
102  } else {
103  // If the object is larger than the minimum object size that can be
104  // cached, remove any existing entry (possibly smaller) from the cache.
105  Remove(cell.Database, cell.TableId, cell.RowNumber, cell.ColumnOffset);
106  }
107  }
108  }
109 
110  private void Remove(string database, int tableId, long rowNumber, int columnOffset) {
111  lock (this) {
112  var cell = cache.Remove(new CacheKey(database, tableId, (int)rowNumber, (short)columnOffset));
113  if (cell != null)
114  size -= AmountMemory((DataObject) cell);
115  }
116  }
117 
118  private static int AmountMemory(DataObject value) {
119  return 16 + value.CacheUsage;
120  }
121 
122  public bool TryGetValue(CellKey key, out DataObject value) {
123  lock (this) {
124  var database = key.Database;
125  var tableKey = key.RowId.TableId;
126  var row = key.RowId.RowNumber;
127  var columnIndex = key.ColumnOffset;
128 
129  object obj;
130  if (!cache.TryGet(new CacheKey(database, tableKey, row, (short)columnIndex), out obj)) {
131  value = null;
132  return false;
133  }
134 
135  value = (DataObject) obj;
136  return true;
137  }
138  }
139 
140  public void Remove(CellKey key) {
141  Remove(key.Database, key.RowId.TableId, key.RowId.RowNumber, key.ColumnOffset);
142  }
143 
144  public void Clear() {
145  lock (this) {
146  if (cache.NodeCount == 0 && Size != 0) {
147  // TODO: Raise an error
148  }
149  if (cache.NodeCount != 0) {
150  cache.Clear();
151  // TODO: Register the statistics
152  }
153 
154  size = 0;
155  }
156  }
157 
158 #region Cache
159 
160  class Cache : CacheAdapter {
161  private readonly TableCellCache tableCache;
162  private int hashSize;
163 
164  public Cache(TableCellCache tableCache, ICache baseCache, int hashSize, int maxSize)
165  : base(baseCache) {
166  this.tableCache = tableCache;
167  this.hashSize = hashSize;
168  }
169 
170  public void ChangeSize(int newSize) {
171  hashSize = newSize;
172  CheckClean();
173  }
174 
175  protected override void CheckClean() {
176  if (tableCache.Size >= hashSize) {
177  // TODO: Register the statistics
178 
179  Clean();
180 
181  //TODO: Register the statistics
182  }
183  }
184 
185  protected override bool WipeMoreNodes() {
186  return (tableCache.Size >= (int)((hashSize * 100L) / 115L));
187  }
188 
189  protected override void OnWipingNode(object ob) {
190  base.OnWipingNode(ob);
191 
192  // Update our memory indicator accordingly.
193  var value = (DataObject)ob;
194  tableCache.ReduceCacheSize(AmountMemory(value));
195  }
196 
197  protected override void OnGetWalks(long totalWalks, long totalGetOps) {
198  // TODO: Register the statistics ...
199  base.OnGetWalks(totalWalks, totalGetOps);
200  }
201  }
202 
203 #endregion
204 
205 #region CacheKey
206 
207  class CacheKey : IEquatable<CacheKey> {
208  private readonly string database;
209  private readonly short column;
210  private readonly int row;
211  private readonly int tableId;
212 
213  public CacheKey(string database, int tableId, int row, short column) {
214  this.database = database;
215  this.tableId = tableId;
216  this.row = row;
217  this.column = column;
218  }
219 
220  public override bool Equals(object obj) {
221  return Equals((CacheKey)obj);
222  }
223 
224  public override int GetHashCode() {
225  // Yicks - this one is the best by far!
226  return (database.GetHashCode() + (((int)column + tableId + (row * 189977)) * 50021) << 4);
227  }
228 
229  public bool Equals(CacheKey other) {
230  return database.Equals(other.database) &&
231  row == other.row &&
232  column == other.column &&
233  tableId == other.tableId;
234  }
235  }
236 
237 #endregion
238  }
239 }
override void OnGetWalks(long totalWalks, long totalGetOps)
Notifies that some statistical information about the hash map has updated.
override void Clear()
Clear the cache of all the entries.
Definition: CacheAdapter.cs:39
bool TryGetValue(CellKey key, out DataObject value)
virtual int NodeCount
Gets the number of nodes that are currently being stored in the cache.
Definition: Cache.cs:125
void Remove(string database, int tableId, long rowNumber, int columnOffset)
bool TryGet(object key, out object value)
Tries to get an object for the given key from the underlying cache system.
Definition: Cache.cs:162
TableCellCache(IConfiguration configuration)
override void OnWipingNode(object ob)
Notifies that the given object has been wiped from the cache by the clean up procedure.
CacheKey(string database, int tableId, int row, short column)
Represents a dynamic object that encapsulates a defined SqlType and a compatible constant ISqlObject ...
Definition: DataObject.cs:35
Defines the contract for the configuration node of a component within the system or of the system its...
void Configure(IConfiguration config)
bool Set(object key, object value)
Puts an object into the cache with the given key.
Definition: Cache.cs:150
Cache(TableCellCache tableCache, ICache baseCache, int hashSize, int maxSize)
Provides a contract to access a caching system.
Definition: ICache.cs:25
override void CheckClean()
This is called whenever at object is put into the cache.
override bool WipeMoreNodes()
Checks if the clean-up method should clean up more elements from the cache.
object Remove(Object key)
Removes a node for the given key from the cache.
Definition: Cache.cs:178
static int AmountMemory(DataObject value)