Datei: NDODLL/Cache.cs
Last Commit (10db6e2)
1 | // |
2 | // Copyright (c) 2002-2016 Mirko Matytschak |
3 | // (www.netdataobjects.de) |
4 | // |
5 | // Author: Mirko Matytschak |
6 | // |
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated |
8 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation |
9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the |
10 | // Software, and to permit persons to whom the Software is furnished to do so, subject to the following |
11 | // conditions: |
12 | |
13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions |
14 | // of the Software. |
15 | // |
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
20 | // DEALINGS IN THE SOFTWARE. |
21 | |
22 | #pragma warning disable 1591 |
23 | |
24 | using System; |
25 | using System.Linq; |
26 | using System.Collections; |
27 | using System.Collections.Generic; |
28 | using System.Data; |
29 | using System.Diagnostics; |
30 | using NDO.Mapping; |
31 | using NDO.ShortId; |
32 | |
33 | namespace NDO |
34 | { |
35 | ····/// <summary> |
36 | ····/// This is a cache of persistent objects. While the object is not part of a transaction, only a weak reference is held. |
37 | ····/// While the object is part of a transaction, a strong reference is held. |
38 | ····/// </summary> |
39 | #if !DEBUG |
40 | ····internal class Cache |
41 | #else |
42 | ····public class Cache |
43 | #endif |
44 | ····{ |
45 | ········/// <summary> |
46 | ········/// Because all entries are put in a hash table, we use a class instead of a struct (which would be boxed anyway) |
47 | ········/// </summary> |
48 | #if !DEBUG |
49 | ········internal class Entry |
50 | #else |
51 | ········public class Entry |
52 | #endif |
53 | ········{ |
54 | ············public IPersistenceCapable pc; |
55 | ············public DataRow row; |
56 | ············public List<KeyValuePair<Relation, object>> relations; |
57 | |
58 | ············public Entry( IPersistenceCapable pc, DataRow row, List<KeyValuePair<Relation, object>> relations ) |
59 | ············{ |
60 | ················this.pc = pc; |
61 | ················this.row = row; |
62 | ················this.relations = relations; |
63 | ············} |
64 | ········} |
65 | |
66 | ········private Dictionary<ObjectId, Entry> lockedObjects = new Dictionary<ObjectId, Entry>( 100 ); |
67 | ········private Dictionary<ObjectId, WeakReference<IPersistenceCapable>> objects = new Dictionary<ObjectId, WeakReference<IPersistenceCapable>>( 100 ); |
68 | |
69 | ········/// <summary> |
70 | ········/// Defaul Constructor |
71 | ········/// </summary> |
72 | ········public Cache() |
73 | ········{ |
74 | ········} |
75 | |
76 | ········public bool IsRegistered( IPersistenceCapable pc ) |
77 | ········{ |
78 | ············if (pc.NDOObjectId == null) |
79 | ················throw new InternalException( 60, "Cache.IsRegistered: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
80 | ············return objects.ContainsKey( pc.NDOObjectId ) || lockedObjects.ContainsKey( pc.NDOObjectId ); |
81 | ········} |
82 | |
83 | ········/// <summary> |
84 | ········/// Register an object |
85 | ········/// </summary> |
86 | ········/// <param name="pc">The Object</param> |
87 | ········public void Register( IPersistenceCapable pc ) |
88 | ········{ |
89 | ············if (pc.NDOObjectId == null) |
90 | ················throw new InternalException( 60, "Cache.Register: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
91 | |
92 | ············if (!pc.NDOObjectId.IsValid()) |
93 | ············{ |
94 | ················throw new ArgumentException( "Cannot register object with invalid key: " + pc ); |
95 | ············} |
96 | |
97 | ············if (objects.ContainsKey( pc.NDOObjectId ) || lockedObjects.ContainsKey( pc.NDOObjectId )) |
98 | ············{ |
99 | ················throw new ArgumentException( "Object already cached: " + pc.NDOObjectId, "pc" ); |
100 | ············} |
101 | ············if (pc.NDOObjectState != NDO.NDOObjectState.Hollow && pc.NDOObjectState != NDO.NDOObjectState.Persistent && pc.NDOObjectState != NDO.NDOObjectState.Transient) |
102 | ············{ |
103 | ················throw new ArgumentException( "Object in wrong state " + pc.NDOObjectId, "pc" ); |
104 | ············} |
105 | ············objects.Add( pc.NDOObjectId, new WeakReference<IPersistenceCapable>( pc ) ); |
106 | ········} |
107 | |
108 | ········/// <summary> |
109 | ········/// Re-Register an object in the locked cache |
110 | ········/// </summary> |
111 | ········/// <param name="pc">The Object</param> |
112 | ········/// <param name="row">The data row, which holds the original state of the object</param> |
113 | ········/// <param name="relations">A list of all relations of the object.</param>········ |
114 | ········public void RegisterLockedObject( IPersistenceCapable pc, DataRow row, List<KeyValuePair<Relation, object>> relations ) |
115 | ········{ |
116 | ············if (pc.NDOObjectId == null) |
117 | ················throw new InternalException( 60, "Cache.RegisterLockedObject: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
118 | |
119 | ············if (!pc.NDOObjectId.IsValid()) |
120 | ············{ |
121 | ················throw new ArgumentException( "Cannot register object with invalid key: " + pc ); |
122 | ············} |
123 | |
124 | ············if (lockedObjects.ContainsKey( pc.NDOObjectId )) |
125 | ············{ |
126 | ················throw new ArgumentException( "Object already cached: " + pc.NDOObjectId, "pc" ); |
127 | ············} |
128 | ············Cache.Entry e = new Entry( pc, row, relations ); |
129 | ············lockedObjects.Add( pc.NDOObjectId, e ); |
130 | ········} |
131 | |
132 | |
133 | ········/// <summary> |
134 | ········/// Put an object in the cache; remove older versions of the object if existent |
135 | ········/// </summary> |
136 | ········/// <param name="pc">The object to put into the cache</param> |
137 | ········public void UpdateCache( IPersistenceCapable pc ) |
138 | ········{ |
139 | ············ObjectId oid = pc.NDOObjectId; |
140 | ············if (lockedObjects.ContainsKey( oid )) |
141 | ················return; |
142 | ············Debug.Assert( pc.NDOObjectState == NDOObjectState.Persistent || pc.NDOObjectState == NDOObjectState.Hollow ); |
143 | ············WeakReference<IPersistenceCapable> objRef = null; |
144 | ············if (objects.TryGetValue( oid, out objRef )) |
145 | ············{ |
146 | ················objRef.SetTarget( pc ); |
147 | ············} |
148 | ············else |
149 | ············{ |
150 | ················objects.Add( pc.NDOObjectId, new WeakReference<IPersistenceCapable>( pc ) ); |
151 | ············} |
152 | ········} |
153 | |
154 | ········/// <summary> |
155 | ········/// Remove an object from the cache |
156 | ········/// </summary> |
157 | ········/// <param name="pc">The object to remove</param> |
158 | ········public void Deregister( IPersistenceCapable pc ) |
159 | ········{ |
160 | ············if (pc.NDOObjectId == null) |
161 | ················throw new InternalException( 60, "Cache.Deregister: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
162 | |
163 | ············objects.Remove( pc.NDOObjectId ); |
164 | ············lockedObjects.Remove( pc.NDOObjectId ); |
165 | ········} |
166 | |
167 | ········/// <summary> |
168 | ········/// Remove an object from the locked objects cache |
169 | ········/// </summary> |
170 | ········/// <param name="pc">The object to remove</param> |
171 | ········public void DeregisterLockedObject( IPersistenceCapable pc ) |
172 | ········{ |
173 | ············if (pc.NDOObjectId == null) |
174 | ················throw new InternalException( 60, "Cache.DeregisterLockedObject: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
175 | ············lockedObjects.Remove( pc.NDOObjectId ); |
176 | ········} |
177 | |
178 | ········/// <summary> |
179 | ········/// Unload all unused objects, i.e., those that lost their weak reference. |
180 | ········/// </summary> |
181 | ········public void Cleanup() |
182 | ········{ |
183 | ············IPersistenceCapable target; // dummy |
184 | ············List<ObjectId> unusedObjects = new List<ObjectId>(); |
185 | ············foreach (var e in objects) |
186 | ············{ |
187 | ················if (!e.Value.TryGetTarget( out target )) |
188 | ················{ |
189 | ····················unusedObjects.Add( e.Key ); |
190 | ················} |
191 | ············} |
192 | ············foreach (var key in unusedObjects) |
193 | ············{ |
194 | ················objects.Remove( key ); |
195 | ············} |
196 | ············//············Debug.WriteLine("Cache unloaded " + unusedObjects.Count + " unused objects"); |
197 | ········} |
198 | |
199 | ········/// <summary> |
200 | ········/// Unload all inactive objects. |
201 | ········/// </summary> |
202 | ········public void Unload() |
203 | ········{ |
204 | ············//············Debug.WriteLine("Cache unloaded " + objects.Count + " objects"); |
205 | ············lockedObjects.Clear(); |
206 | ············objects.Clear(); |
207 | ········} |
208 | |
209 | ········/// <summary> |
210 | ········/// Retrieve an object in the cache |
211 | ········/// </summary> |
212 | ········/// <param name="id">Object ID of the object</param> |
213 | ········/// <returns></returns> |
214 | ········public IPersistenceCapable GetObject( ObjectId id ) |
215 | ········{ |
216 | ············Entry e = null; |
217 | ············lockedObjects.TryGetValue( id, out e ); |
218 | ············IPersistenceCapable pc = e?.pc; |
219 | ············if (pc == null) |
220 | ············{ |
221 | ················WeakReference<IPersistenceCapable> objRef = null; |
222 | ················objects.TryGetValue( id, out objRef ); |
223 | ················if (objRef == null || !objRef.TryGetTarget( out pc )) |
224 | ················{ |
225 | ····················objects.Remove( id ); |
226 | ················} |
227 | ············} |
228 | ············return pc; |
229 | ········} |
230 | |
231 | ········/// <summary> |
232 | ········/// Retrieve a DataRow related to an object |
233 | ········/// </summary> |
234 | ········/// <param name="pc"></param> |
235 | ········/// <returns></returns> |
236 | ········public DataRow GetDataRow( IPersistenceCapable pc ) |
237 | ········{ |
238 | ············if (pc.NDOObjectId == null) |
239 | ················throw new InternalException( 60, "Cache.GetDataRow: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
240 | ············Entry e = null; |
241 | ············lockedObjects.TryGetValue( pc.NDOObjectId, out e ); |
242 | ············return e?.row; |
243 | ········} |
244 | |
245 | ········/// <summary> |
246 | ········/// Lock an object for use in a transaction; store the relatetd DataRow |
247 | ········/// </summary> |
248 | ········/// <param name="pc">The object to lock</param> |
249 | ········/// <param name="row">The DataRow</param> |
250 | ········/// <param name="relations">Relation info for the Object</param> |
251 | ········public void Lock( IPersistenceCapable pc, DataRow row, List<KeyValuePair<Relation, object>> relations ) |
252 | ········{ |
253 | ············if (pc.NDOObjectId == null) |
254 | ················throw new InternalException( 60, "Cache.Lock: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
255 | ············objects.Remove( pc.NDOObjectId ); |
256 | ············lockedObjects.Add( pc.NDOObjectId, new Entry( pc, row, relations ) ); |
257 | ········} |
258 | |
259 | ········Entry GetEntry(IPersistenceCapable pc) |
260 | ········{ |
261 | ············if (pc.NDOObjectId == null) |
262 | ················throw new InternalException( 60, "Cache.GetEntry: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
263 | ············Entry e = null; |
264 | ············lockedObjects.TryGetValue( pc.NDOObjectId, out e ); |
265 | ············return e; |
266 | ········} |
267 | |
268 | |
269 | ········/// <summary> |
270 | ········/// Unlock an object |
271 | ········/// </summary> |
272 | ········/// <param name="pc">The object to unlock</param> |
273 | ········public void Unlock( IPersistenceCapable pc ) |
274 | ········{ |
275 | ············Entry e = GetEntry(pc); |
276 | ············lockedObjects.Remove( pc.NDOObjectId ); |
277 | ············objects.Add( pc.NDOObjectId, new WeakReference<IPersistenceCapable>( pc ) ); |
278 | ········} |
279 | |
280 | ········/// <summary> |
281 | ········/// Returns all locked objects |
282 | ········/// </summary> |
283 | ········public ICollection<Entry> LockedObjects |
284 | ········{ |
285 | ············get { return lockedObjects.Values; } |
286 | ········} |
287 | |
288 | |
289 | ········/// <summary> |
290 | ········/// Returns all known objects |
291 | ········/// </summary> |
292 | ········public List<IPersistenceCapable> AllObjects |
293 | ········{ |
294 | ············get |
295 | ············{ |
296 | ················Cleanup(); |
297 | ················List<IPersistenceCapable> al = new List<IPersistenceCapable>( this.lockedObjects.Count + this.objects.Count ); |
298 | |
299 | ················foreach (var de in this.lockedObjects) |
300 | ················{ |
301 | ····················Cache.Entry ce = de.Value; |
302 | ····················if (ce.row.RowState != DataRowState.Deleted) |
303 | ························al.Add( ce.pc ); |
304 | ················} |
305 | |
306 | ················foreach (var de in this.objects) |
307 | ················{ |
308 | ····················var weakReference = de.Value; |
309 | ····················if (weakReference != null) |
310 | ····················{ |
311 | ························IPersistenceCapable pc; |
312 | ························if (weakReference.TryGetTarget( out pc )) |
313 | ····························al.Add( pc ); |
314 | ····················} |
315 | ················} |
316 | ················return al; |
317 | ············} |
318 | ········} |
319 | |
320 | ········/// <summary> |
321 | ········/// Check if object is locked |
322 | ········/// </summary> |
323 | ········/// <param name="pc">Object to check</param> |
324 | ········/// <returns>True if object is in the LockedObjects Collection</returns> |
325 | ········public bool IsLocked( IPersistenceCapable pc ) |
326 | ········{ |
327 | ············if (pc.NDOObjectId == null) |
328 | ················throw new InternalException( 60, "Cache.IsLocked: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
329 | ············return lockedObjects.ContainsKey( pc.NDOObjectId ); |
330 | ········} |
331 | |
332 | ········/// <summary> |
333 | ········/// Returns all objects which are not locked |
334 | ········/// </summary> |
335 | ········public IEnumerable<IPersistenceCapable> UnlockedObjects |
336 | ········{ |
337 | ············get |
338 | ············{ |
339 | ················IPersistenceCapable pc = null; |
340 | ················foreach (var wr in objects.Values) |
341 | ················{ |
342 | ····················if (wr.TryGetTarget( out pc )) |
343 | ························yield return pc; |
344 | ················} |
345 | ············} |
346 | ········} |
347 | |
348 | ········/// <summary> |
349 | ········/// Unlock all locked objects |
350 | ········/// </summary> |
351 | ········public void UnlockAll() |
352 | ········{ |
353 | ············foreach (Entry e in lockedObjects.Values) |
354 | ············{ |
355 | objects. Add( e. pc. NDOObjectId, new WeakReference<IPersistenceCapable>( e. pc ) ) ; |
356 | ················if (e.relations != null) |
357 | ················{ |
358 | ····················// support GC |
359 | ····················e.relations.Clear(); |
360 | ····················e.relations = null; |
361 | ················} |
362 | ············} |
363 | |
364 | ············lockedObjects.Clear(); |
365 | ········} |
366 | ····} |
367 | } |
368 | |
369 | #pragma warning restore 1591 |
New Commit (8c50417)
1 | // |
2 | // Copyright (c) 2002-2016 Mirko Matytschak |
3 | // (www.netdataobjects.de) |
4 | // |
5 | // Author: Mirko Matytschak |
6 | // |
7 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated |
8 | // documentation files (the "Software"), to deal in the Software without restriction, including without limitation |
9 | // the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the |
10 | // Software, and to permit persons to whom the Software is furnished to do so, subject to the following |
11 | // conditions: |
12 | |
13 | // The above copyright notice and this permission notice shall be included in all copies or substantial portions |
14 | // of the Software. |
15 | // |
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED |
17 | // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
18 | // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF |
19 | // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
20 | // DEALINGS IN THE SOFTWARE. |
21 | |
22 | #pragma warning disable 1591 |
23 | |
24 | using System; |
25 | using System.Linq; |
26 | using System.Collections; |
27 | using System.Collections.Generic; |
28 | using System.Data; |
29 | using System.Diagnostics; |
30 | using NDO.Mapping; |
31 | using NDO.ShortId; |
32 | |
33 | namespace NDO |
34 | { |
35 | ····/// <summary> |
36 | ····/// This is a cache of persistent objects. While the object is not part of a transaction, only a weak reference is held. |
37 | ····/// While the object is part of a transaction, a strong reference is held. |
38 | ····/// </summary> |
39 | #if !DEBUG |
40 | ····internal class Cache |
41 | #else |
42 | ····public class Cache |
43 | #endif |
44 | ····{ |
45 | ········/// <summary> |
46 | ········/// Because all entries are put in a hash table, we use a class instead of a struct (which would be boxed anyway) |
47 | ········/// </summary> |
48 | #if !DEBUG |
49 | ········internal class Entry |
50 | #else |
51 | ········public class Entry |
52 | #endif |
53 | ········{ |
54 | ············public IPersistenceCapable pc; |
55 | ············public DataRow row; |
56 | ············public List<KeyValuePair<Relation, object>> relations; |
57 | |
58 | ············public Entry( IPersistenceCapable pc, DataRow row, List<KeyValuePair<Relation, object>> relations ) |
59 | ············{ |
60 | ················this.pc = pc; |
61 | ················this.row = row; |
62 | ················this.relations = relations; |
63 | ············} |
64 | ········} |
65 | |
66 | ········private Dictionary<ObjectId, Entry> lockedObjects = new Dictionary<ObjectId, Entry>( 100 ); |
67 | ········private Dictionary<ObjectId, WeakReference<IPersistenceCapable>> objects = new Dictionary<ObjectId, WeakReference<IPersistenceCapable>>( 100 ); |
68 | |
69 | ········/// <summary> |
70 | ········/// Defaul Constructor |
71 | ········/// </summary> |
72 | ········public Cache() |
73 | ········{ |
74 | ········} |
75 | |
76 | ········public bool IsRegistered( IPersistenceCapable pc ) |
77 | ········{ |
78 | ············if (pc.NDOObjectId == null) |
79 | ················throw new InternalException( 60, "Cache.IsRegistered: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
80 | ············return objects.ContainsKey( pc.NDOObjectId ) || lockedObjects.ContainsKey( pc.NDOObjectId ); |
81 | ········} |
82 | |
83 | ········/// <summary> |
84 | ········/// Register an object |
85 | ········/// </summary> |
86 | ········/// <param name="pc">The Object</param> |
87 | ········public void Register( IPersistenceCapable pc ) |
88 | ········{ |
89 | ············if (pc.NDOObjectId == null) |
90 | ················throw new InternalException( 60, "Cache.Register: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
91 | |
92 | ············if (!pc.NDOObjectId.IsValid()) |
93 | ············{ |
94 | ················throw new ArgumentException( "Cannot register object with invalid key: " + pc ); |
95 | ············} |
96 | |
97 | ············if (objects.ContainsKey( pc.NDOObjectId ) || lockedObjects.ContainsKey( pc.NDOObjectId )) |
98 | ············{ |
99 | ················throw new ArgumentException( "Object already cached: " + pc.NDOObjectId, "pc" ); |
100 | ············} |
101 | ············if (pc.NDOObjectState != NDO.NDOObjectState.Hollow && pc.NDOObjectState != NDO.NDOObjectState.Persistent && pc.NDOObjectState != NDO.NDOObjectState.Transient) |
102 | ············{ |
103 | ················throw new ArgumentException( "Object in wrong state " + pc.NDOObjectId, "pc" ); |
104 | ············} |
105 | ············objects.Add( pc.NDOObjectId, new WeakReference<IPersistenceCapable>( pc ) ); |
106 | ········} |
107 | |
108 | ········/// <summary> |
109 | ········/// Re-Register an object in the locked cache |
110 | ········/// </summary> |
111 | ········/// <param name="pc">The Object</param> |
112 | ········/// <param name="row">The data row, which holds the original state of the object</param> |
113 | ········/// <param name="relations">A list of all relations of the object.</param>········ |
114 | ········public void RegisterLockedObject( IPersistenceCapable pc, DataRow row, List<KeyValuePair<Relation, object>> relations ) |
115 | ········{ |
116 | ············if (pc.NDOObjectId == null) |
117 | ················throw new InternalException( 60, "Cache.RegisterLockedObject: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
118 | |
119 | ············if (!pc.NDOObjectId.IsValid()) |
120 | ············{ |
121 | ················throw new ArgumentException( "Cannot register object with invalid key: " + pc ); |
122 | ············} |
123 | |
124 | ············if (lockedObjects.ContainsKey( pc.NDOObjectId )) |
125 | ············{ |
126 | ················throw new ArgumentException( "Object already cached: " + pc.NDOObjectId, "pc" ); |
127 | ············} |
128 | ············Cache.Entry e = new Entry( pc, row, relations ); |
129 | ············lockedObjects.Add( pc.NDOObjectId, e ); |
130 | ········} |
131 | |
132 | |
133 | ········/// <summary> |
134 | ········/// Put an object in the cache; remove older versions of the object if existent |
135 | ········/// </summary> |
136 | ········/// <param name="pc">The object to put into the cache</param> |
137 | ········public void UpdateCache( IPersistenceCapable pc ) |
138 | ········{ |
139 | ············ObjectId oid = pc.NDOObjectId; |
140 | ············if (lockedObjects.ContainsKey( oid )) |
141 | ················return; |
142 | ············Debug.Assert( pc.NDOObjectState == NDOObjectState.Persistent || pc.NDOObjectState == NDOObjectState.Hollow ); |
143 | ············WeakReference<IPersistenceCapable> objRef = null; |
144 | ············if (objects.TryGetValue( oid, out objRef )) |
145 | ············{ |
146 | ················objRef.SetTarget( pc ); |
147 | ············} |
148 | ············else |
149 | ············{ |
150 | ················objects.Add( pc.NDOObjectId, new WeakReference<IPersistenceCapable>( pc ) ); |
151 | ············} |
152 | ········} |
153 | |
154 | ········/// <summary> |
155 | ········/// Remove an object from the cache |
156 | ········/// </summary> |
157 | ········/// <param name="pc">The object to remove</param> |
158 | ········public void Deregister( IPersistenceCapable pc ) |
159 | ········{ |
160 | ············if (pc.NDOObjectId == null) |
161 | ················throw new InternalException( 60, "Cache.Deregister: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
162 | |
163 | ············objects.Remove( pc.NDOObjectId ); |
164 | ············lockedObjects.Remove( pc.NDOObjectId ); |
165 | ········} |
166 | |
167 | ········/// <summary> |
168 | ········/// Remove an object from the locked objects cache |
169 | ········/// </summary> |
170 | ········/// <param name="pc">The object to remove</param> |
171 | ········public void DeregisterLockedObject( IPersistenceCapable pc ) |
172 | ········{ |
173 | ············if (pc.NDOObjectId == null) |
174 | ················throw new InternalException( 60, "Cache.DeregisterLockedObject: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
175 | ············lockedObjects.Remove( pc.NDOObjectId ); |
176 | ········} |
177 | |
178 | ········/// <summary> |
179 | ········/// Unload all unused objects, i.e., those that lost their weak reference. |
180 | ········/// </summary> |
181 | ········public void Cleanup() |
182 | ········{ |
183 | ············IPersistenceCapable target; // dummy |
184 | ············List<ObjectId> unusedObjects = new List<ObjectId>(); |
185 | ············foreach (var e in objects) |
186 | ············{ |
187 | ················if (!e.Value.TryGetTarget( out target )) |
188 | ················{ |
189 | ····················unusedObjects.Add( e.Key ); |
190 | ················} |
191 | ············} |
192 | ············foreach (var key in unusedObjects) |
193 | ············{ |
194 | ················objects.Remove( key ); |
195 | ············} |
196 | ············//············Debug.WriteLine("Cache unloaded " + unusedObjects.Count + " unused objects"); |
197 | ········} |
198 | |
199 | ········/// <summary> |
200 | ········/// Unload all inactive objects. |
201 | ········/// </summary> |
202 | ········public void Unload() |
203 | ········{ |
204 | ············//············Debug.WriteLine("Cache unloaded " + objects.Count + " objects"); |
205 | ············lockedObjects.Clear(); |
206 | ············objects.Clear(); |
207 | ········} |
208 | |
209 | ········/// <summary> |
210 | ········/// Retrieve an object in the cache |
211 | ········/// </summary> |
212 | ········/// <param name="id">Object ID of the object</param> |
213 | ········/// <returns></returns> |
214 | ········public IPersistenceCapable GetObject( ObjectId id ) |
215 | ········{ |
216 | ············Entry e = null; |
217 | ············lockedObjects.TryGetValue( id, out e ); |
218 | ············IPersistenceCapable pc = e?.pc; |
219 | ············if (pc == null) |
220 | ············{ |
221 | ················WeakReference<IPersistenceCapable> objRef = null; |
222 | ················objects.TryGetValue( id, out objRef ); |
223 | ················if (objRef == null || !objRef.TryGetTarget( out pc )) |
224 | ················{ |
225 | ····················objects.Remove( id ); |
226 | ················} |
227 | ············} |
228 | ············return pc; |
229 | ········} |
230 | |
231 | ········/// <summary> |
232 | ········/// Retrieve a DataRow related to an object |
233 | ········/// </summary> |
234 | ········/// <param name="pc"></param> |
235 | ········/// <returns></returns> |
236 | ········public DataRow GetDataRow( IPersistenceCapable pc ) |
237 | ········{ |
238 | ············if (pc.NDOObjectId == null) |
239 | ················throw new InternalException( 60, "Cache.GetDataRow: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
240 | ············Entry e = null; |
241 | ············lockedObjects.TryGetValue( pc.NDOObjectId, out e ); |
242 | ············return e?.row; |
243 | ········} |
244 | |
245 | ········/// <summary> |
246 | ········/// Lock an object for use in a transaction; store the relatetd DataRow |
247 | ········/// </summary> |
248 | ········/// <param name="pc">The object to lock</param> |
249 | ········/// <param name="row">The DataRow</param> |
250 | ········/// <param name="relations">Relation info for the Object</param> |
251 | ········public void Lock( IPersistenceCapable pc, DataRow row, List<KeyValuePair<Relation, object>> relations ) |
252 | ········{ |
253 | ············if (pc.NDOObjectId == null) |
254 | ················throw new InternalException( 60, "Cache.Lock: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
255 | ············objects.Remove( pc.NDOObjectId ); |
256 | ············lockedObjects.Add( pc.NDOObjectId, new Entry( pc, row, relations ) ); |
257 | ········} |
258 | |
259 | ········Entry GetEntry(IPersistenceCapable pc) |
260 | ········{ |
261 | ············if (pc.NDOObjectId == null) |
262 | ················throw new InternalException( 60, "Cache.GetEntry: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
263 | ············Entry e = null; |
264 | ············lockedObjects.TryGetValue( pc.NDOObjectId, out e ); |
265 | ············return e; |
266 | ········} |
267 | |
268 | |
269 | ········/// <summary> |
270 | ········/// Unlock an object |
271 | ········/// </summary> |
272 | ········/// <param name="pc">The object to unlock</param> |
273 | ········public void Unlock( IPersistenceCapable pc ) |
274 | ········{ |
275 | ············Entry e = GetEntry(pc); |
276 | ············lockedObjects.Remove( pc.NDOObjectId ); |
277 | ············objects.Add( pc.NDOObjectId, new WeakReference<IPersistenceCapable>( pc ) ); |
278 | ········} |
279 | |
280 | ········/// <summary> |
281 | ········/// Returns all locked objects |
282 | ········/// </summary> |
283 | ········public ICollection<Entry> LockedObjects |
284 | ········{ |
285 | ············get { return lockedObjects.Values; } |
286 | ········} |
287 | |
288 | |
289 | ········/// <summary> |
290 | ········/// Returns all known objects |
291 | ········/// </summary> |
292 | ········public List<IPersistenceCapable> AllObjects |
293 | ········{ |
294 | ············get |
295 | ············{ |
296 | ················Cleanup(); |
297 | ················List<IPersistenceCapable> al = new List<IPersistenceCapable>( this.lockedObjects.Count + this.objects.Count ); |
298 | |
299 | ················foreach (var de in this.lockedObjects) |
300 | ················{ |
301 | ····················Cache.Entry ce = de.Value; |
302 | ····················if (ce.row.RowState != DataRowState.Deleted) |
303 | ························al.Add( ce.pc ); |
304 | ················} |
305 | |
306 | ················foreach (var de in this.objects) |
307 | ················{ |
308 | ····················var weakReference = de.Value; |
309 | ····················if (weakReference != null) |
310 | ····················{ |
311 | ························IPersistenceCapable pc; |
312 | ························if (weakReference.TryGetTarget( out pc )) |
313 | ····························al.Add( pc ); |
314 | ····················} |
315 | ················} |
316 | ················return al; |
317 | ············} |
318 | ········} |
319 | |
320 | ········/// <summary> |
321 | ········/// Check if object is locked |
322 | ········/// </summary> |
323 | ········/// <param name="pc">Object to check</param> |
324 | ········/// <returns>True if object is in the LockedObjects Collection</returns> |
325 | ········public bool IsLocked( IPersistenceCapable pc ) |
326 | ········{ |
327 | ············if (pc.NDOObjectId == null) |
328 | ················throw new InternalException( 60, "Cache.IsLocked: ObjectId of an object of type " + pc.GetType().FullName + " is null." ); |
329 | ············return lockedObjects.ContainsKey( pc.NDOObjectId ); |
330 | ········} |
331 | |
332 | ········/// <summary> |
333 | ········/// Returns all objects which are not locked |
334 | ········/// </summary> |
335 | ········public IEnumerable<IPersistenceCapable> UnlockedObjects |
336 | ········{ |
337 | ············get |
338 | ············{ |
339 | ················IPersistenceCapable pc = null; |
340 | ················foreach (var wr in objects.Values) |
341 | ················{ |
342 | ····················if (wr.TryGetTarget( out pc )) |
343 | ························yield return pc; |
344 | ················} |
345 | ············} |
346 | ········} |
347 | |
348 | ········/// <summary> |
349 | ········/// Unlock all locked objects |
350 | ········/// </summary> |
351 | ········public void UnlockAll() |
352 | ········{ |
353 | ············foreach (Entry e in lockedObjects.Values) |
354 | ············{ |
355 | var oid = e. pc. NDOObjectId; |
356 | ················if (!objects.ContainsKey( oid )) |
357 | ····················objects.Add( oid, new WeakReference<IPersistenceCapable>( e.pc ) ); |
358 | ················if (e.relations != null) |
359 | ················{ |
360 | ····················// support GC |
361 | ····················e.relations.Clear(); |
362 | ····················e.relations = null; |
363 | ················} |
364 | ············} |
365 | |
366 | ············lockedObjects.Clear(); |
367 | ········} |
368 | ····} |
369 | } |
370 | |
371 | #pragma warning restore 1591 |