1 /* Copyright (C) 2004 - 2009 Versant Inc. http://www.db4o.com */ 2 3 using System; 4 using Db4objects.Db4o; 5 using Db4objects.Db4o.Ext; 6 using Db4objects.Db4o.Foundation; 7 using Db4objects.Db4o.Internal; 8 using Db4objects.Db4o.Internal.Freespace; 9 using Db4objects.Db4o.Internal.Ids; 10 using Db4objects.Db4o.Internal.Slots; 11 using Sharpen.Lang; 12 13 namespace Db4objects.Db4o.Internal.Ids 14 { 15 /// <exclude></exclude> 16 public class InMemoryIdSystem : IStackableIdSystem 17 { 18 private readonly LocalObjectContainer _container; 19 20 private IdSlotTree _ids; 21 22 private Slot _slot; 23 24 private readonly SequentialIdGenerator _idGenerator; 25 26 private int _childId; 27 28 /// <summary>for testing purposes only.</summary> 29 /// <remarks>for testing purposes only.</remarks> InMemoryIdSystem(LocalObjectContainer container, int maxValidId)30 public InMemoryIdSystem(LocalObjectContainer container, int maxValidId) 31 { 32 _container = container; 33 _idGenerator = new SequentialIdGenerator(new _IFunction4_32(this, maxValidId), _container 34 .Handlers.LowestValidId(), maxValidId); 35 } 36 37 private sealed class _IFunction4_32 : IFunction4 38 { _IFunction4_32(InMemoryIdSystem _enclosing, int maxValidId)39 public _IFunction4_32(InMemoryIdSystem _enclosing, int maxValidId) 40 { 41 this._enclosing = _enclosing; 42 this.maxValidId = maxValidId; 43 } 44 Apply(object start)45 public object Apply(object start) 46 { 47 return this._enclosing.FindFreeId((((int)start)), maxValidId); 48 } 49 50 private readonly InMemoryIdSystem _enclosing; 51 52 private readonly int maxValidId; 53 } 54 InMemoryIdSystem(LocalObjectContainer container)55 public InMemoryIdSystem(LocalObjectContainer container) : this(container, int.MaxValue 56 ) 57 { 58 ReadThis(); 59 } 60 ReadThis()61 private void ReadThis() 62 { 63 SystemData systemData = _container.SystemData(); 64 _slot = systemData.IdSystemSlot(); 65 if (!Slot.IsNull(_slot)) 66 { 67 ByteArrayBuffer buffer = _container.ReadBufferBySlot(_slot); 68 _childId = buffer.ReadInt(); 69 _idGenerator.Read(buffer); 70 _ids = (IdSlotTree)new TreeReader(buffer, new IdSlotTree(0, null)).Read(); 71 } 72 } 73 Close()74 public virtual void Close() 75 { 76 } 77 78 // do nothing Commit(IVisitable slotChanges, FreespaceCommitter freespaceCommitter )79 public virtual void Commit(IVisitable slotChanges, FreespaceCommitter freespaceCommitter 80 ) 81 { 82 Slot oldSlot = _slot; 83 Slot reservedSlot = AllocateSlot(false, EstimatedSlotLength(EstimateMappingCount( 84 slotChanges))); 85 // No more operations against the FreespaceManager. 86 // Time to free old slots. 87 freespaceCommitter.Commit(); 88 slotChanges.Accept(new _IVisitor4_69(this)); 89 WriteThis(reservedSlot); 90 FreeSlot(oldSlot); 91 } 92 93 private sealed class _IVisitor4_69 : IVisitor4 94 { _IVisitor4_69(InMemoryIdSystem _enclosing)95 public _IVisitor4_69(InMemoryIdSystem _enclosing) 96 { 97 this._enclosing = _enclosing; 98 } 99 Visit(object slotChange)100 public void Visit(object slotChange) 101 { 102 if (!((SlotChange)slotChange).SlotModified()) 103 { 104 return; 105 } 106 if (((SlotChange)slotChange).RemoveId()) 107 { 108 this._enclosing._ids = (IdSlotTree)Tree.RemoveLike(this._enclosing._ids, new TreeInt 109 (((TreeInt)slotChange)._key)); 110 return; 111 } 112 if (DTrace.enabled) 113 { 114 DTrace.SlotCommitted.LogLength(((TreeInt)slotChange)._key, ((SlotChange)slotChange 115 ).NewSlot()); 116 } 117 this._enclosing._ids = ((IdSlotTree)Tree.Add(this._enclosing._ids, new IdSlotTree 118 (((TreeInt)slotChange)._key, ((SlotChange)slotChange).NewSlot()))); 119 } 120 121 private readonly InMemoryIdSystem _enclosing; 122 } 123 AllocateSlot(bool appendToFile, int slotLength)124 private Slot AllocateSlot(bool appendToFile, int slotLength) 125 { 126 if (!appendToFile) 127 { 128 Slot slot = _container.FreespaceManager().AllocateSafeSlot(slotLength); 129 if (slot != null) 130 { 131 return slot; 132 } 133 } 134 return _container.AppendBytes(slotLength); 135 } 136 EstimateMappingCount(IVisitable slotChanges)137 private int EstimateMappingCount(IVisitable slotChanges) 138 { 139 IntByRef count = new IntByRef(); 140 count.value = _ids == null ? 0 : _ids.Size(); 141 slotChanges.Accept(new _IVisitor4_103(count)); 142 return count.value; 143 } 144 145 private sealed class _IVisitor4_103 : IVisitor4 146 { _IVisitor4_103(IntByRef count)147 public _IVisitor4_103(IntByRef count) 148 { 149 this.count = count; 150 } 151 Visit(object slotChange)152 public void Visit(object slotChange) 153 { 154 if (!((SlotChange)slotChange).SlotModified() || ((SlotChange)slotChange).RemoveId 155 ()) 156 { 157 return; 158 } 159 count.value++; 160 } 161 162 private readonly IntByRef count; 163 } 164 WriteThis(Slot reservedSlot)165 private void WriteThis(Slot reservedSlot) 166 { 167 // We need a little dance here to keep filling free slots 168 // with X bytes. The FreespaceManager would do it immediately 169 // upon the free call, but then our CrashSimulatingTestCase 170 // fails because we have the Xses in the file before flushing. 171 Slot xByteSlot = null; 172 int slotLength = SlotLength(); 173 if (reservedSlot.Length() >= slotLength) 174 { 175 _slot = reservedSlot; 176 reservedSlot = null; 177 } 178 else 179 { 180 _slot = AllocateSlot(true, slotLength); 181 } 182 ByteArrayBuffer buffer = new ByteArrayBuffer(_slot.Length()); 183 buffer.WriteInt(_childId); 184 _idGenerator.Write(buffer); 185 TreeInt.Write(buffer, _ids); 186 _container.WriteBytes(buffer, _slot.Address(), 0); 187 _container.SystemData().IdSystemSlot(_slot); 188 IRunnable commitHook = _container.CommitHook(); 189 _container.SyncFiles(commitHook); 190 FreeSlot(reservedSlot); 191 } 192 FreeSlot(Slot slot)193 private void FreeSlot(Slot slot) 194 { 195 if (Slot.IsNull(slot)) 196 { 197 return; 198 } 199 IFreespaceManager freespaceManager = _container.FreespaceManager(); 200 if (freespaceManager == null) 201 { 202 return; 203 } 204 freespaceManager.FreeSafeSlot(slot); 205 } 206 SlotLength()207 private int SlotLength() 208 { 209 return TreeInt.MarshalledLength(_ids) + _idGenerator.MarshalledLength() + Const4. 210 IdLength; 211 } 212 EstimatedSlotLength(int estimatedCount)213 private int EstimatedSlotLength(int estimatedCount) 214 { 215 IdSlotTree template = _ids; 216 if (template == null) 217 { 218 template = new IdSlotTree(0, new Slot(0, 0)); 219 } 220 return template.MarshalledLength(estimatedCount) + _idGenerator.MarshalledLength( 221 ) + Const4.IdLength; 222 } 223 CommittedSlot(int id)224 public virtual Slot CommittedSlot(int id) 225 { 226 IdSlotTree idSlotMapping = (IdSlotTree)Tree.Find(_ids, new TreeInt(id)); 227 if (idSlotMapping == null) 228 { 229 throw new InvalidIDException(id); 230 } 231 return idSlotMapping.Slot(); 232 } 233 CompleteInterruptedTransaction(int address, int length)234 public virtual void CompleteInterruptedTransaction(int address, int length) 235 { 236 } 237 238 // do nothing NewId()239 public virtual int NewId() 240 { 241 int id = _idGenerator.NewId(); 242 _ids = ((IdSlotTree)Tree.Add(_ids, new IdSlotTree(id, Slot.Zero))); 243 return id; 244 } 245 FindFreeId(int start, int end)246 private int FindFreeId(int start, int end) 247 { 248 if (_ids == null) 249 { 250 return start; 251 } 252 IntByRef lastId = new IntByRef(); 253 IntByRef freeId = new IntByRef(); 254 Tree.Traverse(_ids, new TreeInt(start), new _ICancellableVisitor4_204(lastId, start 255 , freeId)); 256 if (freeId.value > 0) 257 { 258 return freeId.value; 259 } 260 if (lastId.value < end) 261 { 262 return Math.Max(start, lastId.value + 1); 263 } 264 return 0; 265 } 266 267 private sealed class _ICancellableVisitor4_204 : ICancellableVisitor4 268 { _ICancellableVisitor4_204(IntByRef lastId, int start, IntByRef freeId)269 public _ICancellableVisitor4_204(IntByRef lastId, int start, IntByRef freeId) 270 { 271 this.lastId = lastId; 272 this.start = start; 273 this.freeId = freeId; 274 } 275 Visit(object node)276 public bool Visit(object node) 277 { 278 int id = ((TreeInt)node)._key; 279 if (lastId.value == 0) 280 { 281 if (id > start) 282 { 283 freeId.value = start; 284 return false; 285 } 286 lastId.value = id; 287 return true; 288 } 289 if (id > lastId.value + 1) 290 { 291 freeId.value = lastId.value + 1; 292 return false; 293 } 294 lastId.value = id; 295 return true; 296 } 297 298 private readonly IntByRef lastId; 299 300 private readonly int start; 301 302 private readonly IntByRef freeId; 303 } 304 ReturnUnusedIds(IVisitable visitable)305 public virtual void ReturnUnusedIds(IVisitable visitable) 306 { 307 visitable.Accept(new _IVisitor4_233(this)); 308 } 309 310 private sealed class _IVisitor4_233 : IVisitor4 311 { _IVisitor4_233(InMemoryIdSystem _enclosing)312 public _IVisitor4_233(InMemoryIdSystem _enclosing) 313 { 314 this._enclosing = _enclosing; 315 } 316 Visit(object obj)317 public void Visit(object obj) 318 { 319 this._enclosing._ids = (IdSlotTree)Tree.RemoveLike(this._enclosing._ids, new TreeInt 320 ((((int)obj)))); 321 } 322 323 private readonly InMemoryIdSystem _enclosing; 324 } 325 ChildId()326 public virtual int ChildId() 327 { 328 return _childId; 329 } 330 ChildId(int id)331 public virtual void ChildId(int id) 332 { 333 _childId = id; 334 } 335 } 336 } 337