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