1 /* Copyright (C) 2004 - 2009  Versant Inc.  http://www.db4o.com */
2 
3 using System;
4 using System.Collections;
5 using Db4objects.Db4o;
6 using Db4objects.Db4o.Config;
7 using Db4objects.Db4o.Ext;
8 using Db4objects.Db4o.Foundation;
9 using Db4objects.Db4o.Internal;
10 using Db4objects.Db4o.Internal.Btree;
11 using Db4objects.Db4o.Internal.Convert;
12 using Db4objects.Db4o.Internal.Events;
13 using Db4objects.Db4o.Internal.Fileheader;
14 using Db4objects.Db4o.Internal.Freespace;
15 using Db4objects.Db4o.Internal.Ids;
16 using Db4objects.Db4o.Internal.Qlin;
17 using Db4objects.Db4o.Internal.Query.Processor;
18 using Db4objects.Db4o.Internal.Query.Result;
19 using Db4objects.Db4o.Internal.References;
20 using Db4objects.Db4o.Internal.Slots;
21 using Db4objects.Db4o.Qlin;
22 using Sharpen;
23 using Sharpen.Lang;
24 
25 namespace Db4objects.Db4o.Internal
26 {
27 	/// <exclude></exclude>
28 	public abstract class LocalObjectContainer : ExternalObjectContainer, IInternalObjectContainer
29 		, IEmbeddedObjectContainer
30 	{
31 		protected FileHeader _fileHeader;
32 
33 		private readonly Collection4 _dirtyClassMetadata = new Collection4();
34 
35 		private IFreespaceManager _freespaceManager;
36 
37 		private bool i_isServer = false;
38 
39 		private Lock4 _semaphoresLock = new Lock4();
40 
41 		private Hashtable4 _semaphores;
42 
43 		private int _blockEndAddress;
44 
45 		private Db4objects.Db4o.Internal.SystemData _systemData;
46 
47 		private IIdSystem _idSystem;
48 
49 		private readonly byte[] _pointerBuffer = new byte[Const4.PointerLength];
50 
51 		protected readonly ByteArrayBuffer _pointerIo = new ByteArrayBuffer(Const4.PointerLength
52 			);
53 
LocalObjectContainer(IConfiguration config)54 		internal LocalObjectContainer(IConfiguration config) : base(config)
55 		{
56 		}
57 
NewTransaction(Transaction parentTransaction, IReferenceSystem referenceSystem, bool isSystemTransaction)58 		public override Transaction NewTransaction(Transaction parentTransaction, IReferenceSystem
59 			 referenceSystem, bool isSystemTransaction)
60 		{
61 			ITransactionalIdSystem systemIdSystem = null;
62 			if (!isSystemTransaction)
63 			{
64 				systemIdSystem = SystemTransaction().IdSystem();
65 			}
66 			IClosure4 idSystem = new _IClosure4_58(this);
67 			ITransactionalIdSystem transactionalIdSystem = NewTransactionalIdSystem(systemIdSystem
68 				, idSystem);
69 			return new LocalTransaction(this, parentTransaction, transactionalIdSystem, referenceSystem
70 				);
71 		}
72 
73 		private sealed class _IClosure4_58 : IClosure4
74 		{
_IClosure4_58(LocalObjectContainer _enclosing)75 			public _IClosure4_58(LocalObjectContainer _enclosing)
76 			{
77 				this._enclosing = _enclosing;
78 			}
79 
Run()80 			public object Run()
81 			{
82 				return this._enclosing.IdSystem();
83 			}
84 
85 			private readonly LocalObjectContainer _enclosing;
86 		}
87 
NewTransactionalIdSystem(ITransactionalIdSystem systemIdSystem, IClosure4 idSystem)88 		public virtual ITransactionalIdSystem NewTransactionalIdSystem(ITransactionalIdSystem
89 			 systemIdSystem, IClosure4 idSystem)
90 		{
91 			return new TransactionalIdSystemImpl(new _IClosure4_69(this), idSystem, (TransactionalIdSystemImpl
92 				)systemIdSystem);
93 		}
94 
95 		private sealed class _IClosure4_69 : IClosure4
96 		{
_IClosure4_69(LocalObjectContainer _enclosing)97 			public _IClosure4_69(LocalObjectContainer _enclosing)
98 			{
99 				this._enclosing = _enclosing;
100 			}
101 
Run()102 			public object Run()
103 			{
104 				return this._enclosing.FreespaceManager();
105 			}
106 
107 			private readonly LocalObjectContainer _enclosing;
108 		}
109 
FreespaceManager()110 		public virtual IFreespaceManager FreespaceManager()
111 		{
112 			return _freespaceManager;
113 		}
114 
BlockSizeReadFromFile(int size)115 		public virtual void BlockSizeReadFromFile(int size)
116 		{
117 			BlockSize(size);
118 			SetRegularEndAddress(FileLength());
119 		}
120 
SetRegularEndAddress(long address)121 		public virtual void SetRegularEndAddress(long address)
122 		{
123 			_blockEndAddress = _blockConverter.BytesToBlocks(address);
124 		}
125 
Close2()126 		protected sealed override void Close2()
127 		{
128 			try
129 			{
130 				if (!_config.IsReadOnly())
131 				{
132 					CommitTransaction();
133 					Shutdown();
134 				}
135 			}
136 			finally
137 			{
138 				ShutdownObjectContainer();
139 			}
140 		}
141 
Commit1(Transaction trans)142 		public override void Commit1(Transaction trans)
143 		{
144 			trans.Commit();
145 		}
146 
ConfigureNewFile()147 		internal virtual void ConfigureNewFile()
148 		{
149 			BlockSize(ConfigImpl.BlockSize());
150 			_fileHeader = FileHeader.NewCurrentFileHeader();
151 			SetRegularEndAddress(_fileHeader.Length());
152 			NewSystemData(ConfigImpl.FreespaceSystem(), ConfigImpl.IdSystemType());
153 			SystemData().ConverterVersion(Converter.Version);
154 			CreateStringIO(_systemData.StringEncoding());
155 			CreateIdSystem();
156 			InitializeClassMetadataRepository();
157 			InitalizeWeakReferenceSupport();
158 			GenerateNewIdentity();
159 			AbstractFreespaceManager blockedFreespaceManager = AbstractFreespaceManager.CreateNew
160 				(this);
161 			InstallFreespaceManager(blockedFreespaceManager);
162 			InitNewClassCollection();
163 			InitializeEssentialClasses();
164 			_fileHeader.InitNew(this);
165 			blockedFreespaceManager.Start(0);
166 		}
167 
NewSystemData(byte freespaceSystemType, byte idSystemType)168 		private void NewSystemData(byte freespaceSystemType, byte idSystemType)
169 		{
170 			_systemData = new Db4objects.Db4o.Internal.SystemData();
171 			_systemData.StringEncoding(ConfigImpl.Encoding());
172 			_systemData.FreespaceSystem(freespaceSystemType);
173 			_systemData.IdSystemType(idSystemType);
174 		}
175 
ConverterVersion()176 		public override int ConverterVersion()
177 		{
178 			return _systemData.ConverterVersion();
179 		}
180 
CurrentVersion()181 		public override long CurrentVersion()
182 		{
183 			return _timeStampIdGenerator.Last();
184 		}
185 
InitNewClassCollection()186 		internal virtual void InitNewClassCollection()
187 		{
188 			// overridden in YapObjectCarrier to do nothing
189 			ClassCollection().InitTables(1);
190 		}
191 
CreateBTreeClassIndex(int id)192 		public BTree CreateBTreeClassIndex(int id)
193 		{
194 			return new BTree(_transaction, id, new IDHandler());
195 		}
196 
NewQueryResult(Transaction trans)197 		public AbstractQueryResult NewQueryResult(Transaction trans)
198 		{
199 			return NewQueryResult(trans, Config().EvaluationMode());
200 		}
201 
NewQueryResult(Transaction trans, QueryEvaluationMode mode)202 		public sealed override AbstractQueryResult NewQueryResult(Transaction trans, QueryEvaluationMode
203 			 mode)
204 		{
205 			if (trans == null)
206 			{
207 				throw new ArgumentNullException();
208 			}
209 			if (mode == QueryEvaluationMode.Immediate)
210 			{
211 				return new IdListQueryResult(trans);
212 			}
213 			return new HybridQueryResult(trans, mode);
214 		}
215 
Delete4(Transaction transaction, ObjectReference @ref , object obj, int cascade, bool userCall)216 		public sealed override bool Delete4(Transaction transaction, ObjectReference @ref
217 			, object obj, int cascade, bool userCall)
218 		{
219 			int id = @ref.GetID();
220 			StatefulBuffer reader = ReadStatefulBufferById(transaction, id);
221 			if (reader != null)
222 			{
223 				if (obj != null)
224 				{
225 					if ((!ShowInternalClasses()) && Const4.ClassInternal.IsAssignableFrom(obj.GetType
226 						()))
227 					{
228 						return false;
229 					}
230 				}
231 				reader.SetCascadeDeletes(cascade);
232 				transaction.IdSystem().NotifySlotDeleted(id, SlotChangeFactory.UserObjects);
233 				ClassMetadata classMetadata = @ref.ClassMetadata();
234 				classMetadata.Delete(reader, obj);
235 				return true;
236 			}
237 			return false;
238 		}
239 
FileLength()240 		public abstract long FileLength();
241 
FileName()242 		public abstract string FileName();
243 
Free(Slot slot)244 		public virtual void Free(Slot slot)
245 		{
246 			if (slot.IsNull())
247 			{
248 				return;
249 			}
250 			// TODO: This should really be an IllegalArgumentException but old database files
251 			//       with index-based FreespaceManagers appear to deliver zeroed slots.
252 			// throw new IllegalArgumentException();
253 			if (_freespaceManager == null)
254 			{
255 				// Can happen on early free before freespacemanager
256 				// is up, during conversion.
257 				return;
258 			}
259 			if (DTrace.enabled)
260 			{
261 				DTrace.FileFree.LogLength(slot.Address(), slot.Length());
262 			}
263 			_freespaceManager.Free(slot);
264 		}
265 
Free(int address, int a_length)266 		public virtual void Free(int address, int a_length)
267 		{
268 			Free(new Slot(address, a_length));
269 		}
270 
GenerateNewIdentity()271 		public virtual void GenerateNewIdentity()
272 		{
273 			lock (_lock)
274 			{
275 				SetIdentity(Db4oDatabase.Generate());
276 			}
277 		}
278 
QueryAllObjects(Transaction trans)279 		public override AbstractQueryResult QueryAllObjects(Transaction trans)
280 		{
281 			return GetAll(trans, Config().EvaluationMode());
282 		}
283 
GetAll(Transaction trans, QueryEvaluationMode mode)284 		public virtual AbstractQueryResult GetAll(Transaction trans, QueryEvaluationMode
285 			mode)
286 		{
287 			AbstractQueryResult queryResult = NewQueryResult(trans, mode);
288 			queryResult.LoadFromClassIndexes(ClassCollection().Iterator());
289 			return queryResult;
290 		}
291 
AllocatePointerSlot()292 		public virtual int AllocatePointerSlot()
293 		{
294 			int id = AllocateSlot(Const4.PointerLength).Address();
295 			if (!IsValidPointer(id))
296 			{
297 				return AllocatePointerSlot();
298 			}
299 			// write a zero pointer first
300 			// to prevent delete interaction trouble
301 			WritePointer(id, Slot.Zero);
302 			if (DTrace.enabled)
303 			{
304 				DTrace.GetPointerSlot.Log(id);
305 			}
306 			return id;
307 		}
308 
IsValidPointer(int id)309 		protected virtual bool IsValidPointer(int id)
310 		{
311 			// We have to make sure that object IDs do not collide
312 			// with built-in type IDs.
313 			return !_handlers.IsSystemHandler(id);
314 		}
315 
AllocateSlot(int length)316 		public virtual Slot AllocateSlot(int length)
317 		{
318 			if (length <= 0)
319 			{
320 				throw new ArgumentException();
321 			}
322 			if (_freespaceManager != null && _freespaceManager.IsStarted())
323 			{
324 				Slot slot = _freespaceManager.AllocateSlot(length);
325 				if (slot != null)
326 				{
327 					if (DTrace.enabled)
328 					{
329 						DTrace.GetSlot.LogLength(slot.Address(), slot.Length());
330 					}
331 					return slot;
332 				}
333 				while (GrowDatabaseByConfiguredSize())
334 				{
335 					slot = _freespaceManager.AllocateSlot(length);
336 					if (slot != null)
337 					{
338 						if (DTrace.enabled)
339 						{
340 							DTrace.GetSlot.LogLength(slot.Address(), slot.Length());
341 						}
342 						return slot;
343 					}
344 				}
345 			}
346 			Slot appendedSlot = AppendBytes(length);
347 			if (DTrace.enabled)
348 			{
349 				DTrace.GetSlot.LogLength(appendedSlot.Address(), appendedSlot.Length());
350 			}
351 			return appendedSlot;
352 		}
353 
GrowDatabaseByConfiguredSize()354 		private bool GrowDatabaseByConfiguredSize()
355 		{
356 			int reservedStorageSpace = ConfigImpl.DatabaseGrowthSize();
357 			if (reservedStorageSpace <= 0)
358 			{
359 				return false;
360 			}
361 			int reservedBlocks = _blockConverter.BytesToBlocks(reservedStorageSpace);
362 			int reservedBytes = _blockConverter.BlocksToBytes(reservedBlocks);
363 			Slot slot = new Slot(_blockEndAddress, reservedBlocks);
364 			if (Debug4.xbytes && Deploy.overwrite)
365 			{
366 				OverwriteDeletedBlockedSlot(slot);
367 			}
368 			else
369 			{
370 				WriteBytes(new ByteArrayBuffer(reservedBytes), _blockEndAddress, 0);
371 			}
372 			_freespaceManager.Free(_blockConverter.ToNonBlockedLength(slot));
373 			_blockEndAddress += reservedBlocks;
374 			return true;
375 		}
376 
AppendBytes(long bytes)377 		public Slot AppendBytes(long bytes)
378 		{
379 			int blockCount = _blockConverter.BytesToBlocks(bytes);
380 			int blockedStartAddress = _blockEndAddress;
381 			int blockedEndAddress = _blockEndAddress + blockCount;
382 			CheckBlockedAddress(blockedEndAddress);
383 			_blockEndAddress = blockedEndAddress;
384 			Slot slot = new Slot(blockedStartAddress, blockCount);
385 			if (Debug4.xbytes && Deploy.overwrite)
386 			{
387 				OverwriteDeletedBlockedSlot(slot);
388 			}
389 			return _blockConverter.ToNonBlockedLength(slot);
390 		}
391 
CheckBlockedAddress(int blockedAddress)392 		private void CheckBlockedAddress(int blockedAddress)
393 		{
394 			if (blockedAddress < 0)
395 			{
396 				SwitchToReadOnlyMode();
397 				throw new DatabaseMaximumSizeReachedException();
398 			}
399 		}
400 
SwitchToReadOnlyMode()401 		private void SwitchToReadOnlyMode()
402 		{
403 			_config.ReadOnly(true);
404 		}
405 
406 		// When a file gets opened, it uses the file size to determine where
407 		// new slots can be appended. If this method would not be called, the
408 		// freespace system could already contain a slot that points beyond
409 		// the end of the file and this space could be allocated and used twice,
410 		// for instance if a slot was allocated and freed without ever being
411 		// written to file.
EnsureLastSlotWritten()412 		internal virtual void EnsureLastSlotWritten()
413 		{
414 			if (_blockEndAddress > _blockConverter.BytesToBlocks(FileLength()))
415 			{
416 				StatefulBuffer writer = CreateStatefulBuffer(SystemTransaction(), _blockEndAddress
417 					 - 1, BlockSize());
418 				writer.Write();
419 			}
420 		}
421 
Identity()422 		public override Db4oDatabase Identity()
423 		{
424 			return _systemData.Identity();
425 		}
426 
SetIdentity(Db4oDatabase identity)427 		public virtual void SetIdentity(Db4oDatabase identity)
428 		{
429 			lock (Lock())
430 			{
431 				_systemData.Identity(identity);
432 				// The dirty TimeStampIdGenerator triggers writing of
433 				// the variable part of the systemdata. We need to
434 				// make it dirty here, so the new identity is persisted:
435 				_timeStampIdGenerator.Generate();
436 				_fileHeader.WriteVariablePart(this);
437 			}
438 		}
439 
IsServer()440 		internal override bool IsServer()
441 		{
442 			return i_isServer;
443 		}
444 
IdForNewUserObject(Transaction trans)445 		public sealed override int IdForNewUserObject(Transaction trans)
446 		{
447 			return trans.IdSystem().NewId(SlotChangeFactory.UserObjects);
448 		}
449 
RaiseCommitTimestamp(long minimumVersion)450 		public override void RaiseCommitTimestamp(long minimumVersion)
451 		{
452 			lock (Lock())
453 			{
454 				_timeStampIdGenerator.SetMinimumNext(minimumVersion);
455 			}
456 		}
457 
ReadStatefulBufferById(Transaction a_ta, int a_id)458 		public override StatefulBuffer ReadStatefulBufferById(Transaction a_ta, int a_id)
459 		{
460 			return ReadStatefulBufferById(a_ta, a_id, false);
461 		}
462 
ReadSlotBuffers(Transaction transaction, int[] ids)463 		public override ByteArrayBuffer[] ReadSlotBuffers(Transaction transaction, int[]
464 			ids)
465 		{
466 			ByteArrayBuffer[] buffers = new ByteArrayBuffer[ids.Length];
467 			for (int i = 0; i < ids.Length; ++i)
468 			{
469 				if (ids[i] == 0)
470 				{
471 					buffers[i] = null;
472 				}
473 				else
474 				{
475 					buffers[i] = ReadBufferById(transaction, ids[i]);
476 				}
477 			}
478 			return buffers;
479 		}
480 
ReadBufferById(Transaction trans, int id)481 		public override ByteArrayBuffer ReadBufferById(Transaction trans, int id)
482 		{
483 			return ReadBufferById(trans, id, false);
484 		}
485 
ReadBufferById(Transaction trans, int id, bool lastCommitted)486 		public sealed override ByteArrayBuffer ReadBufferById(Transaction trans, int id,
487 			bool lastCommitted)
488 		{
489 			if (id <= 0)
490 			{
491 				throw new ArgumentException();
492 			}
493 			Slot slot = lastCommitted ? trans.IdSystem().CommittedSlot(id) : trans.IdSystem()
494 				.CurrentSlot(id);
495 			if (DTrace.enabled)
496 			{
497 				DTrace.SlotRead.LogLength(id, slot);
498 			}
499 			return ReadBufferBySlot(slot);
500 		}
501 
ReadStatefulBufferById(Transaction trans, int id, bool lastCommitted)502 		public override StatefulBuffer ReadStatefulBufferById(Transaction trans, int id,
503 			bool lastCommitted)
504 		{
505 			if (id <= 0)
506 			{
507 				throw new ArgumentException();
508 			}
509 			Slot slot = lastCommitted ? trans.IdSystem().CommittedSlot(id) : trans.IdSystem()
510 				.CurrentSlot(id);
511 			if (DTrace.enabled)
512 			{
513 				DTrace.SlotRead.LogLength(id, slot);
514 			}
515 			return ReadStatefulBufferBySlot(trans, id, slot);
516 		}
517 
ReadBufferBySlot(Slot slot)518 		public virtual ByteArrayBuffer ReadBufferBySlot(Slot slot)
519 		{
520 			if (Slot.IsNull(slot))
521 			{
522 				return null;
523 			}
524 			if (DTrace.enabled)
525 			{
526 				DTrace.ReadSlot.LogLength(slot.Address(), slot.Length());
527 			}
528 			ByteArrayBuffer buffer = new ByteArrayBuffer(slot.Length());
529 			buffer.ReadEncrypt(this, slot.Address());
530 			return buffer;
531 		}
532 
ReadStatefulBufferBySlot(Transaction trans, int id, Slot slot)533 		public virtual StatefulBuffer ReadStatefulBufferBySlot(Transaction trans, int id,
534 			Slot slot)
535 		{
536 			if (Slot.IsNull(slot))
537 			{
538 				return null;
539 			}
540 			if (DTrace.enabled)
541 			{
542 				DTrace.ReadSlot.LogLength(slot.Address(), slot.Length());
543 			}
544 			StatefulBuffer buffer = CreateStatefulBuffer(trans, slot.Address(), slot.Length()
545 				);
546 			buffer.SetID(id);
547 			buffer.ReadEncrypt(this, slot.Address());
548 			return buffer;
549 		}
550 
DoFinalize()551 		protected override bool DoFinalize()
552 		{
553 			return _fileHeader != null;
554 		}
555 
556 		/// <exception cref="Db4objects.Db4o.Ext.OldFormatException"></exception>
ReadThis()557 		internal virtual void ReadThis()
558 		{
559 			NewSystemData(AbstractFreespaceManager.FmLegacyRam, StandardIdSystemFactory.Legacy
560 				);
561 			BlockSizeReadFromFile(1);
562 			_fileHeader = FileHeader.Read(this);
563 			if (Config().GenerateCommitTimestamps().IsUnspecified())
564 			{
565 				Config().GenerateCommitTimestamps(_systemData.IdToTimestampIndexId() != 0);
566 			}
567 			CreateStringIO(_systemData.StringEncoding());
568 			CreateIdSystem();
569 			InitializeClassMetadataRepository();
570 			InitalizeWeakReferenceSupport();
571 			SetNextTimeStampId(SystemData().LastTimeStampID());
572 			ClassCollection().SetID(_systemData.ClassCollectionID());
573 			ClassCollection().Read(SystemTransaction());
574 			Converter.Convert(new ConversionStage.ClassCollectionAvailableStage(this));
575 			_fileHeader.ReadIdentity(this);
576 			if (_config.IsReadOnly())
577 			{
578 				return;
579 			}
580 			if (!ConfigImpl.CommitRecoveryDisabled())
581 			{
582 				_fileHeader.CompleteInterruptedTransaction(this);
583 			}
584 			IFreespaceManager blockedFreespaceManager = AbstractFreespaceManager.CreateNew(this
585 				, _systemData.FreespaceSystem());
586 			InstallFreespaceManager(blockedFreespaceManager);
587 			blockedFreespaceManager.Read(this, _systemData.InMemoryFreespaceSlot());
588 			blockedFreespaceManager.Start(_systemData.BTreeFreespaceId());
589 			_fileHeader = _fileHeader.Convert(this);
590 			if (FreespaceMigrationRequired(blockedFreespaceManager))
591 			{
592 				MigrateFreespace(blockedFreespaceManager);
593 			}
594 			WriteHeader(true, false);
595 			if (Converter.Convert(new ConversionStage.SystemUpStage(this)))
596 			{
597 				_systemData.ConverterVersion(Converter.Version);
598 				_fileHeader.WriteVariablePart(this);
599 				Transaction.Commit();
600 			}
601 		}
602 
InstallFreespaceManager(IFreespaceManager blockedFreespaceManager)603 		private void InstallFreespaceManager(IFreespaceManager blockedFreespaceManager)
604 		{
605 			_freespaceManager = BlockSize() == 1 ? blockedFreespaceManager : new BlockAwareFreespaceManager
606 				(blockedFreespaceManager, _blockConverter);
607 		}
608 
CreateIdSystem()609 		protected virtual void CreateIdSystem()
610 		{
611 			_idSystem = StandardIdSystemFactory.NewInstance(this);
612 		}
613 
FreespaceMigrationRequired(IFreespaceManager freespaceManager)614 		private bool FreespaceMigrationRequired(IFreespaceManager freespaceManager)
615 		{
616 			if (freespaceManager == null)
617 			{
618 				return false;
619 			}
620 			byte readSystem = _systemData.FreespaceSystem();
621 			byte configuredSystem = ConfigImpl.FreespaceSystem();
622 			if (freespaceManager.SystemType() == configuredSystem)
623 			{
624 				return false;
625 			}
626 			if (configuredSystem != 0)
627 			{
628 				return true;
629 			}
630 			return AbstractFreespaceManager.MigrationRequired(readSystem);
631 		}
632 
MigrateFreespace(IFreespaceManager oldFreespaceManager)633 		private void MigrateFreespace(IFreespaceManager oldFreespaceManager)
634 		{
635 			IFreespaceManager newFreespaceManager = AbstractFreespaceManager.CreateNew(this,
636 				ConfigImpl.FreespaceSystem());
637 			newFreespaceManager.Start(0);
638 			SystemData().FreespaceSystem(ConfigImpl.FreespaceSystem());
639 			InstallFreespaceManager(newFreespaceManager);
640 			AbstractFreespaceManager.Migrate(oldFreespaceManager, newFreespaceManager);
641 			_fileHeader.WriteVariablePart(this);
642 		}
643 
ReleaseSemaphore(string name)644 		public sealed override void ReleaseSemaphore(string name)
645 		{
646 			ReleaseSemaphore(null, name);
647 		}
648 
ReleaseSemaphore(Transaction trans, string name)649 		public sealed override void ReleaseSemaphore(Transaction trans, string name)
650 		{
651 			lock (_lock)
652 			{
653 				if (_semaphores == null)
654 				{
655 					return;
656 				}
657 			}
658 			_semaphoresLock.Run(new _IClosure4_574(this, trans, name));
659 		}
660 
661 		private sealed class _IClosure4_574 : IClosure4
662 		{
_IClosure4_574(LocalObjectContainer _enclosing, Transaction trans, string name)663 			public _IClosure4_574(LocalObjectContainer _enclosing, Transaction trans, string
664 				name)
665 			{
666 				this._enclosing = _enclosing;
667 				this.trans = trans;
668 				this.name = name;
669 			}
670 
Run()671 			public object Run()
672 			{
673 				Transaction transaction = this._enclosing.CheckTransaction(trans);
674 				if (this._enclosing._semaphores != null && transaction == this._enclosing._semaphores
675 					.Get(name))
676 				{
677 					this._enclosing._semaphores.Remove(name);
678 				}
679 				this._enclosing._semaphoresLock.Awake();
680 				return null;
681 			}
682 
683 			private readonly LocalObjectContainer _enclosing;
684 
685 			private readonly Transaction trans;
686 
687 			private readonly string name;
688 		}
689 
ReleaseSemaphores(Transaction trans)690 		public override void ReleaseSemaphores(Transaction trans)
691 		{
692 			if (_semaphores != null)
693 			{
694 				Hashtable4 semaphores = _semaphores;
695 				_semaphoresLock.Run(new _IClosure4_588(this, semaphores, trans));
696 			}
697 		}
698 
699 		private sealed class _IClosure4_588 : IClosure4
700 		{
_IClosure4_588(LocalObjectContainer _enclosing, Hashtable4 semaphores, Transaction trans)701 			public _IClosure4_588(LocalObjectContainer _enclosing, Hashtable4 semaphores, Transaction
702 				 trans)
703 			{
704 				this._enclosing = _enclosing;
705 				this.semaphores = semaphores;
706 				this.trans = trans;
707 			}
708 
Run()709 			public object Run()
710 			{
711 				semaphores.ForEachKeyForIdentity(new _IVisitor4_589(semaphores), trans);
712 				this._enclosing._semaphoresLock.Awake();
713 				return null;
714 			}
715 
716 			private sealed class _IVisitor4_589 : IVisitor4
717 			{
_IVisitor4_589(Hashtable4 semaphores)718 				public _IVisitor4_589(Hashtable4 semaphores)
719 				{
720 					this.semaphores = semaphores;
721 				}
722 
Visit(object a_object)723 				public void Visit(object a_object)
724 				{
725 					semaphores.Remove(a_object);
726 				}
727 
728 				private readonly Hashtable4 semaphores;
729 			}
730 
731 			private readonly LocalObjectContainer _enclosing;
732 
733 			private readonly Hashtable4 semaphores;
734 
735 			private readonly Transaction trans;
736 		}
737 
Rollback1(Transaction trans)738 		public sealed override void Rollback1(Transaction trans)
739 		{
740 			trans.Rollback();
741 		}
742 
SetDirtyInSystemTransaction(PersistentBase a_object)743 		public sealed override void SetDirtyInSystemTransaction(PersistentBase a_object)
744 		{
745 			a_object.SetStateDirty();
746 			a_object.CacheDirty(_dirtyClassMetadata);
747 		}
748 
SetSemaphore(string name, int timeout)749 		public sealed override bool SetSemaphore(string name, int timeout)
750 		{
751 			return SetSemaphore(null, name, timeout);
752 		}
753 
SetSemaphore(Transaction trans, string name, int timeout )754 		public sealed override bool SetSemaphore(Transaction trans, string name, int timeout
755 			)
756 		{
757 			if (name == null)
758 			{
759 				throw new ArgumentNullException();
760 			}
761 			lock (_lock)
762 			{
763 				if (_semaphores == null)
764 				{
765 					_semaphores = new Hashtable4(10);
766 				}
767 			}
768 			BooleanByRef acquired = new BooleanByRef();
769 			_semaphoresLock.Run(new _IClosure4_625(this, trans, name, acquired, timeout));
770 			return acquired.value;
771 		}
772 
773 		private sealed class _IClosure4_625 : IClosure4
774 		{
_IClosure4_625(LocalObjectContainer _enclosing, Transaction trans, string name, BooleanByRef acquired, int timeout)775 			public _IClosure4_625(LocalObjectContainer _enclosing, Transaction trans, string
776 				name, BooleanByRef acquired, int timeout)
777 			{
778 				this._enclosing = _enclosing;
779 				this.trans = trans;
780 				this.name = name;
781 				this.acquired = acquired;
782 				this.timeout = timeout;
783 			}
784 
Run()785 			public object Run()
786 			{
787 				try
788 				{
789 					Transaction transaction = this._enclosing.CheckTransaction(trans);
790 					object candidateTransaction = this._enclosing._semaphores.Get(name);
791 					if (trans == candidateTransaction)
792 					{
793 						acquired.value = true;
794 						return null;
795 					}
796 					if (candidateTransaction == null)
797 					{
798 						this._enclosing._semaphores.Put(name, transaction);
799 						acquired.value = true;
800 						return null;
801 					}
802 					long endtime = Runtime.CurrentTimeMillis() + timeout;
803 					long waitTime = timeout;
804 					while (waitTime > 0)
805 					{
806 						this._enclosing._semaphoresLock.Awake();
807 						this._enclosing._semaphoresLock.Snooze(waitTime);
808 						if (this._enclosing.ClassCollection() == null)
809 						{
810 							acquired.value = false;
811 							return null;
812 						}
813 						candidateTransaction = this._enclosing._semaphores.Get(name);
814 						if (candidateTransaction == null)
815 						{
816 							this._enclosing._semaphores.Put(name, transaction);
817 							acquired.value = true;
818 							return null;
819 						}
820 						waitTime = endtime - Runtime.CurrentTimeMillis();
821 					}
822 					acquired.value = false;
823 					return null;
824 				}
825 				finally
826 				{
827 					this._enclosing._semaphoresLock.Awake();
828 				}
829 			}
830 
831 			private readonly LocalObjectContainer _enclosing;
832 
833 			private readonly Transaction trans;
834 
835 			private readonly string name;
836 
837 			private readonly BooleanByRef acquired;
838 
839 			private readonly int timeout;
840 		}
841 
SetServer(bool flag)842 		public virtual void SetServer(bool flag)
843 		{
844 			i_isServer = flag;
845 		}
846 
SyncFiles()847 		public abstract void SyncFiles();
848 
SyncFiles(IRunnable runnable)849 		public abstract void SyncFiles(IRunnable runnable);
850 
DefaultToString()851 		protected override string DefaultToString()
852 		{
853 			return FileName();
854 		}
855 
Shutdown()856 		public override void Shutdown()
857 		{
858 			WriteHeader(false, true);
859 		}
860 
CommitTransaction()861 		public void CommitTransaction()
862 		{
863 			_transaction.Commit();
864 		}
865 
WriteBytes(ByteArrayBuffer buffer, int blockedAddress, int addressOffset )866 		public abstract void WriteBytes(ByteArrayBuffer buffer, int blockedAddress, int addressOffset
867 			);
868 
WriteDirtyClassMetadata()869 		public sealed override void WriteDirtyClassMetadata()
870 		{
871 			WriteCachedDirty();
872 		}
873 
WriteCachedDirty()874 		private void WriteCachedDirty()
875 		{
876 			IEnumerator i = _dirtyClassMetadata.GetEnumerator();
877 			while (i.MoveNext())
878 			{
879 				PersistentBase dirty = (PersistentBase)i.Current;
880 				dirty.Write(SystemTransaction());
881 				dirty.NotCachedDirty();
882 			}
883 			_dirtyClassMetadata.Clear();
884 		}
885 
WriteEncrypt(ByteArrayBuffer buffer, int address, int addressOffset)886 		public void WriteEncrypt(ByteArrayBuffer buffer, int address, int addressOffset)
887 		{
888 			_handlers.Encrypt(buffer);
889 			WriteBytes(buffer, address, addressOffset);
890 			_handlers.Decrypt(buffer);
891 		}
892 
WriteHeader(bool startFileLockingThread, bool shuttingDown)893 		public virtual void WriteHeader(bool startFileLockingThread, bool shuttingDown)
894 		{
895 			if (shuttingDown)
896 			{
897 				_freespaceManager.Write(this);
898 				_freespaceManager = null;
899 			}
900 			StatefulBuffer writer = CreateStatefulBuffer(SystemTransaction(), 0, _fileHeader.
901 				Length());
902 			_fileHeader.WriteFixedPart(this, startFileLockingThread, shuttingDown, writer, BlockSize
903 				());
904 			if (shuttingDown)
905 			{
906 				EnsureLastSlotWritten();
907 			}
908 			SyncFiles();
909 		}
910 
WriteNew(Transaction trans, Pointer4 pointer, ClassMetadata classMetadata, ByteArrayBuffer buffer)911 		public sealed override void WriteNew(Transaction trans, Pointer4 pointer, ClassMetadata
912 			 classMetadata, ByteArrayBuffer buffer)
913 		{
914 			WriteEncrypt(buffer, pointer.Address(), 0);
915 			if (classMetadata == null)
916 			{
917 				return;
918 			}
919 			classMetadata.AddToIndex(trans, pointer.Id());
920 		}
921 
922 		// This is a reroute of writeBytes to write the free blocks
923 		// unchecked.
OverwriteDeletedBytes(int address, int length)924 		public abstract void OverwriteDeletedBytes(int address, int length);
925 
OverwriteDeletedBlockedSlot(Slot slot)926 		public virtual void OverwriteDeletedBlockedSlot(Slot slot)
927 		{
928 			OverwriteDeletedBytes(slot.Address(), _blockConverter.BlocksToBytes(slot.Length()
929 				));
930 		}
931 
WriteTransactionPointer(int pointer)932 		public void WriteTransactionPointer(int pointer)
933 		{
934 			_fileHeader.WriteTransactionPointer(SystemTransaction(), pointer);
935 		}
936 
AllocateSlotForUserObjectUpdate(Transaction trans, int id, int length )937 		public Slot AllocateSlotForUserObjectUpdate(Transaction trans, int id, int length
938 			)
939 		{
940 			Slot slot = AllocateSlot(length);
941 			trans.IdSystem().NotifySlotUpdated(id, slot, SlotChangeFactory.UserObjects);
942 			return slot;
943 		}
944 
AllocateSlotForNewUserObject(Transaction trans, int id, int length)945 		public Slot AllocateSlotForNewUserObject(Transaction trans, int id, int length)
946 		{
947 			Slot slot = AllocateSlot(length);
948 			trans.IdSystem().NotifySlotCreated(id, slot, SlotChangeFactory.UserObjects);
949 			return slot;
950 		}
951 
WriteUpdate(Transaction trans, Pointer4 pointer, ClassMetadata classMetadata, ArrayType arrayType, ByteArrayBuffer buffer)952 		public sealed override void WriteUpdate(Transaction trans, Pointer4 pointer, ClassMetadata
953 			 classMetadata, ArrayType arrayType, ByteArrayBuffer buffer)
954 		{
955 			int address = pointer.Address();
956 			if (address == 0)
957 			{
958 				address = AllocateSlotForUserObjectUpdate(trans, pointer.Id(), pointer.Length()).
959 					Address();
960 			}
961 			WriteEncrypt(buffer, address, 0);
962 		}
963 
SetNextTimeStampId(long val)964 		public virtual void SetNextTimeStampId(long val)
965 		{
966 			_timeStampIdGenerator.SetMinimumNext(val);
967 		}
968 
SystemInfo()969 		public override ISystemInfo SystemInfo()
970 		{
971 			return new SystemInfoFileImpl(this);
972 		}
973 
GetFileHeader()974 		public virtual FileHeader GetFileHeader()
975 		{
976 			return _fileHeader;
977 		}
978 
InstallDebugFreespaceManager(IFreespaceManager manager)979 		public virtual void InstallDebugFreespaceManager(IFreespaceManager manager)
980 		{
981 			_freespaceManager = manager;
982 		}
983 
SystemData()984 		public virtual Db4objects.Db4o.Internal.SystemData SystemData()
985 		{
986 			return _systemData;
987 		}
988 
GetIDsForClass(Transaction trans, ClassMetadata clazz)989 		public override long[] GetIDsForClass(Transaction trans, ClassMetadata clazz)
990 		{
991 			IntArrayList ids = new IntArrayList();
992 			clazz.Index().TraverseAll(trans, new _IVisitor4_792(ids));
993 			return ids.AsLong();
994 		}
995 
996 		private sealed class _IVisitor4_792 : IVisitor4
997 		{
_IVisitor4_792(IntArrayList ids)998 			public _IVisitor4_792(IntArrayList ids)
999 			{
1000 				this.ids = ids;
1001 			}
1002 
Visit(object obj)1003 			public void Visit(object obj)
1004 			{
1005 				ids.Add(((int)obj));
1006 			}
1007 
1008 			private readonly IntArrayList ids;
1009 		}
1010 
ClassOnlyQuery(QQueryBase query, ClassMetadata clazz )1011 		public override IQueryResult ClassOnlyQuery(QQueryBase query, ClassMetadata clazz
1012 			)
1013 		{
1014 			if (!clazz.HasClassIndex())
1015 			{
1016 				return new IdListQueryResult(query.Transaction());
1017 			}
1018 			AbstractQueryResult queryResult = NewQueryResult(query.Transaction());
1019 			queryResult.LoadFromClassIndex(clazz);
1020 			return queryResult;
1021 		}
1022 
ExecuteQuery(QQuery query)1023 		public override IQueryResult ExecuteQuery(QQuery query)
1024 		{
1025 			AbstractQueryResult queryResult = NewQueryResult(query.Transaction());
1026 			queryResult.LoadFromQuery(query);
1027 			return queryResult;
1028 		}
1029 
LocalSystemTransaction()1030 		public virtual LocalTransaction LocalSystemTransaction()
1031 		{
1032 			return (LocalTransaction)SystemTransaction();
1033 		}
1034 
InstanceCount(ClassMetadata clazz, Transaction trans)1035 		public override int InstanceCount(ClassMetadata clazz, Transaction trans)
1036 		{
1037 			lock (Lock())
1038 			{
1039 				return clazz.IndexEntryCount(trans);
1040 			}
1041 		}
1042 
OpenSession()1043 		public override IObjectContainer OpenSession()
1044 		{
1045 			lock (Lock())
1046 			{
1047 				return new ObjectContainerSession(this);
1048 			}
1049 		}
1050 
IsDeleted(Transaction trans, int id)1051 		public override bool IsDeleted(Transaction trans, int id)
1052 		{
1053 			return trans.IdSystem().IsDeleted(id);
1054 		}
1055 
WritePointer(int id, Slot slot)1056 		public virtual void WritePointer(int id, Slot slot)
1057 		{
1058 			if (DTrace.enabled)
1059 			{
1060 				DTrace.WritePointer.Log(id);
1061 				DTrace.WritePointer.LogLength(slot);
1062 			}
1063 			_pointerIo.Seek(0);
1064 			_pointerIo.WriteInt(slot.Address());
1065 			_pointerIo.WriteInt(slot.Length());
1066 			WriteBytes(_pointerIo, id, 0);
1067 		}
1068 
DebugReadPointerSlot(int id)1069 		public virtual Slot DebugReadPointerSlot(int id)
1070 		{
1071 			return null;
1072 		}
1073 
ReadPointerSlot(int id)1074 		public Slot ReadPointerSlot(int id)
1075 		{
1076 			if (!IsValidId(id))
1077 			{
1078 				throw new InvalidIDException(id);
1079 			}
1080 			ReadBytes(_pointerBuffer, id, Const4.PointerLength);
1081 			int address = (_pointerBuffer[3] & 255) | (_pointerBuffer[2] & 255) << 8 | (_pointerBuffer
1082 				[1] & 255) << 16 | _pointerBuffer[0] << 24;
1083 			int length = (_pointerBuffer[7] & 255) | (_pointerBuffer[6] & 255) << 8 | (_pointerBuffer
1084 				[5] & 255) << 16 | _pointerBuffer[4] << 24;
1085 			if (!IsValidSlot(address, length))
1086 			{
1087 				throw new InvalidSlotException(address, length, id);
1088 			}
1089 			return new Slot(address, length);
1090 		}
1091 
IsValidId(int id)1092 		private bool IsValidId(int id)
1093 		{
1094 			return FileLength() >= id;
1095 		}
1096 
IsValidSlot(int address, int length)1097 		private bool IsValidSlot(int address, int length)
1098 		{
1099 			// just in case overflow
1100 			long fileLength = FileLength();
1101 			bool validAddress = fileLength >= address;
1102 			bool validLength = fileLength >= length;
1103 			bool validSlot = fileLength >= (address + length);
1104 			return validAddress && validLength && validSlot;
1105 		}
1106 
CloseIdSystem()1107 		protected override void CloseIdSystem()
1108 		{
1109 			if (_idSystem != null)
1110 			{
1111 				_idSystem.Close();
1112 			}
1113 		}
1114 
IdSystem()1115 		public virtual IIdSystem IdSystem()
1116 		{
1117 			return _idSystem;
1118 		}
1119 
CommitHook()1120 		public virtual IRunnable CommitHook()
1121 		{
1122 			_systemData.LastTimeStampID(_timeStampIdGenerator.Last());
1123 			return _fileHeader.Commit(false);
1124 		}
1125 
AllocateSafeSlot(int length)1126 		public Slot AllocateSafeSlot(int length)
1127 		{
1128 			Slot reusedSlot = FreespaceManager().AllocateSafeSlot(length);
1129 			if (reusedSlot != null)
1130 			{
1131 				return reusedSlot;
1132 			}
1133 			return AppendBytes(length);
1134 		}
1135 
NewEventRegistry()1136 		public override EventRegistryImpl NewEventRegistry()
1137 		{
1138 			return new EventRegistryImpl();
1139 		}
1140 
From(Type clazz)1141 		public virtual IQLin From(Type clazz)
1142 		{
1143 			return new QLinRoot(Query(), clazz);
1144 		}
1145 	}
1146 }
1147