1 /* Copyright (C) 2004 - 2009 Versant Inc. http://www.db4o.com */ 2 3 using System.Collections; 4 using Db4objects.Db4o; 5 using Db4objects.Db4o.Config; 6 using Db4objects.Db4o.Defragment; 7 using Db4objects.Db4o.Ext; 8 using Db4objects.Db4o.Foundation; 9 using Db4objects.Db4o.IO; 10 using Db4objects.Db4o.Internal; 11 using Db4objects.Db4o.Internal.Btree; 12 using Db4objects.Db4o.Internal.Classindex; 13 using Db4objects.Db4o.Internal.Encoding; 14 using Db4objects.Db4o.Internal.Ids; 15 using Db4objects.Db4o.Internal.Mapping; 16 using Db4objects.Db4o.Internal.Marshall; 17 using Db4objects.Db4o.Internal.Slots; 18 using Db4objects.Db4o.Typehandlers; 19 20 namespace Db4objects.Db4o.Defragment 21 { 22 /// <exclude></exclude> 23 public class DefragmentServicesImpl : IDefragmentServices 24 { 25 public abstract class DbSelector 26 { DbSelector()27 internal DbSelector() 28 { 29 } 30 Db(DefragmentServicesImpl context)31 internal abstract LocalObjectContainer Db(DefragmentServicesImpl context); 32 Transaction(DefragmentServicesImpl context)33 internal virtual Db4objects.Db4o.Internal.Transaction Transaction(DefragmentServicesImpl 34 context) 35 { 36 return Db(context).SystemTransaction(); 37 } 38 } 39 40 private sealed class _DbSelector_39 : DefragmentServicesImpl.DbSelector 41 { _DbSelector_39()42 public _DbSelector_39() 43 { 44 } 45 Db(DefragmentServicesImpl context)46 internal override LocalObjectContainer Db(DefragmentServicesImpl context) 47 { 48 return context._sourceDb; 49 } 50 } 51 52 public static readonly DefragmentServicesImpl.DbSelector Sourcedb = new _DbSelector_39 53 (); 54 55 private sealed class _DbSelector_45 : DefragmentServicesImpl.DbSelector 56 { _DbSelector_45()57 public _DbSelector_45() 58 { 59 } 60 Db(DefragmentServicesImpl context)61 internal override LocalObjectContainer Db(DefragmentServicesImpl context) 62 { 63 return context._targetDb; 64 } 65 } 66 67 public static readonly DefragmentServicesImpl.DbSelector Targetdb = new _DbSelector_45 68 (); 69 70 private readonly LocalObjectContainer _sourceDb; 71 72 private readonly LocalObjectContainer _targetDb; 73 74 private readonly IIdMapping _mapping; 75 76 private IDefragmentListener _listener; 77 78 private IQueue4 _unindexed = new NonblockingQueue(); 79 80 private DefragmentConfig _defragConfig; 81 82 /// <exception cref="System.IO.IOException"></exception> DefragmentServicesImpl(DefragmentConfig defragConfig, IDefragmentListener listener)83 public DefragmentServicesImpl(DefragmentConfig defragConfig, IDefragmentListener 84 listener) 85 { 86 _listener = listener; 87 Config4Impl originalConfig = (Config4Impl)defragConfig.Db4oConfig(); 88 IStorage storage = defragConfig.BackupStorage(); 89 if (defragConfig.ReadOnly()) 90 { 91 storage = new NonFlushingStorage(storage); 92 } 93 Config4Impl sourceConfig = PrepareConfig(originalConfig, storage, defragConfig.ReadOnly 94 ()); 95 _sourceDb = (LocalObjectContainer)Db4oFactory.OpenFile(sourceConfig, defragConfig 96 .TempPath()).Ext(); 97 _sourceDb.ShowInternalClasses(true); 98 defragConfig.Db4oConfig().BlockSize(_sourceDb.BlockSize()); 99 if (!originalConfig.GenerateCommitTimestamps().DefiniteNo()) 100 { 101 defragConfig.Db4oConfig().GenerateCommitTimestamps(_sourceDb.Config().GenerateCommitTimestamps 102 ().DefiniteYes()); 103 } 104 _targetDb = FreshTargetFile(defragConfig); 105 _mapping = defragConfig.Mapping(); 106 _mapping.Open(); 107 _defragConfig = defragConfig; 108 } 109 PrepareConfig(Config4Impl originalConfig, IStorage storage, bool readOnly)110 private Config4Impl PrepareConfig(Config4Impl originalConfig, IStorage storage, bool 111 readOnly) 112 { 113 Config4Impl sourceConfig = (Config4Impl)originalConfig.DeepClone(null); 114 sourceConfig.WeakReferences(false); 115 sourceConfig.Storage = storage; 116 sourceConfig.ReadOnly(readOnly); 117 return sourceConfig; 118 } 119 120 /// <exception cref="System.IO.IOException"></exception> FreshTempFile(string fileName, int blockSize )121 internal static LocalObjectContainer FreshTempFile(string fileName, int blockSize 122 ) 123 { 124 FileStorage storage = new FileStorage(); 125 storage.Delete(fileName); 126 IConfiguration db4oConfig = DefragmentConfig.VanillaDb4oConfig(blockSize); 127 db4oConfig.ObjectClass(typeof(IdSlotMapping)).ObjectField("_id").Indexed(true); 128 db4oConfig.Storage = storage; 129 return (LocalObjectContainer)Db4oFactory.OpenFile(db4oConfig, fileName).Ext(); 130 } 131 132 /// <exception cref="System.IO.IOException"></exception> FreshTargetFile(DefragmentConfig config)133 internal static LocalObjectContainer FreshTargetFile(DefragmentConfig config) 134 { 135 config.Db4oConfig().Storage.Delete(config.OrigPath()); 136 return (LocalObjectContainer)Db4oFactory.OpenFile(config.ClonedDb4oConfig(), config 137 .OrigPath()); 138 } 139 MappedID(int oldID, int defaultID)140 public virtual int MappedID(int oldID, int defaultID) 141 { 142 int mapped = InternalMappedID(oldID); 143 return (mapped != 0 ? mapped : defaultID); 144 } 145 146 /// <exception cref="Db4objects.Db4o.Internal.Mapping.MappingNotFoundException"></exception> StrictMappedID(int oldID)147 public virtual int StrictMappedID(int oldID) 148 { 149 int mapped = InternalMappedID(oldID); 150 if (mapped == 0) 151 { 152 throw new MappingNotFoundException(oldID); 153 } 154 return mapped; 155 } 156 MappedID(int id)157 public virtual int MappedID(int id) 158 { 159 if (id == 0) 160 { 161 return 0; 162 } 163 int mapped = InternalMappedID(id); 164 if (mapped == 0) 165 { 166 _listener.NotifyDefragmentInfo(new DefragmentInfo("No mapping found for ID " + id 167 )); 168 return Const4.InvalidObjectId; 169 } 170 return mapped; 171 } 172 173 /// <exception cref="Db4objects.Db4o.Internal.Mapping.MappingNotFoundException"></exception> InternalMappedID(int oldID)174 private int InternalMappedID(int oldID) 175 { 176 if (oldID == 0) 177 { 178 return 0; 179 } 180 int mappedId = _mapping.MappedId(oldID); 181 if (mappedId == 0 && _sourceDb.Handlers.IsSystemHandler(oldID)) 182 { 183 return oldID; 184 } 185 return mappedId; 186 } 187 MapIDs(int oldID, int newID, bool isClassID)188 public virtual void MapIDs(int oldID, int newID, bool isClassID) 189 { 190 _mapping.MapId(oldID, newID, isClassID); 191 } 192 Close()193 public virtual void Close() 194 { 195 _sourceDb.Close(); 196 _targetDb.Close(); 197 _mapping.Close(); 198 } 199 BufferByID(DefragmentServicesImpl.DbSelector selector , int id)200 public virtual ByteArrayBuffer BufferByID(DefragmentServicesImpl.DbSelector selector 201 , int id) 202 { 203 Slot slot = CommittedSlot(selector, id); 204 return BufferByAddress(selector, slot.Address(), slot.Length()); 205 } 206 CommittedSlot(DefragmentServicesImpl.DbSelector selector, int id)207 private Slot CommittedSlot(DefragmentServicesImpl.DbSelector selector, int id) 208 { 209 return selector.Db(this).IdSystem().CommittedSlot(id); 210 } 211 212 /// <exception cref="System.IO.IOException"></exception> SourceBufferByAddress(int address, int length)213 public virtual ByteArrayBuffer SourceBufferByAddress(int address, int length) 214 { 215 return BufferByAddress(Sourcedb, address, length); 216 } 217 218 /// <exception cref="System.IO.IOException"></exception> TargetBufferByAddress(int address, int length)219 public virtual ByteArrayBuffer TargetBufferByAddress(int address, int length) 220 { 221 return BufferByAddress(Targetdb, address, length); 222 } 223 BufferByAddress(DefragmentServicesImpl.DbSelector selector, int address, int length)224 public virtual ByteArrayBuffer BufferByAddress(DefragmentServicesImpl.DbSelector 225 selector, int address, int length) 226 { 227 return selector.Db(this).DecryptedBufferByAddress(address, length); 228 } 229 230 /// <exception cref="System.ArgumentException"></exception> TargetStatefulBufferByAddress(int address, int length )231 public virtual StatefulBuffer TargetStatefulBufferByAddress(int address, int length 232 ) 233 { 234 return _targetDb.ReadWriterByAddress(Targetdb.Transaction(this), address, length); 235 } 236 AllocateTargetSlot(int length)237 public virtual Slot AllocateTargetSlot(int length) 238 { 239 return _targetDb.AllocateSlot(length); 240 } 241 TargetWriteBytes(DefragmentContextImpl context, int address)242 public virtual void TargetWriteBytes(DefragmentContextImpl context, int address) 243 { 244 context.Write(_targetDb, address); 245 } 246 TargetWriteBytes(ByteArrayBuffer reader, int address)247 public virtual void TargetWriteBytes(ByteArrayBuffer reader, int address) 248 { 249 _targetDb.WriteBytes(reader, address, 0); 250 } 251 StoredClasses(DefragmentServicesImpl.DbSelector selector )252 public virtual IStoredClass[] StoredClasses(DefragmentServicesImpl.DbSelector selector 253 ) 254 { 255 LocalObjectContainer db = selector.Db(this); 256 db.ShowInternalClasses(true); 257 try 258 { 259 return db.ClassCollection().StoredClasses(); 260 } 261 finally 262 { 263 db.ShowInternalClasses(false); 264 } 265 } 266 StringIO()267 public virtual LatinStringIO StringIO() 268 { 269 return _sourceDb.StringIO(); 270 } 271 TargetCommit()272 public virtual void TargetCommit() 273 { 274 _targetDb.Commit(); 275 } 276 SourceHandler(int id)277 public virtual ITypeHandler4 SourceHandler(int id) 278 { 279 return _sourceDb.TypeHandlerForClassMetadataID(id); 280 } 281 SourceClassCollectionID()282 public virtual int SourceClassCollectionID() 283 { 284 return _sourceDb.ClassCollection().GetID(); 285 } 286 287 private Hashtable4 _classIndices = new Hashtable4(16); 288 ClassIndexID(ClassMetadata classMetadata)289 public virtual int ClassIndexID(ClassMetadata classMetadata) 290 { 291 return ClassIndex(classMetadata).Id(); 292 } 293 TraverseAll(ClassMetadata classMetadata, IVisitor4 command)294 public virtual void TraverseAll(ClassMetadata classMetadata, IVisitor4 command) 295 { 296 if (!classMetadata.HasClassIndex()) 297 { 298 return; 299 } 300 classMetadata.Index().TraverseAll(Sourcedb.Transaction(this), command); 301 } 302 TraverseAllIndexSlots(ClassMetadata classMetadata, IVisitor4 command)303 public virtual void TraverseAllIndexSlots(ClassMetadata classMetadata, IVisitor4 304 command) 305 { 306 IEnumerator slotIDIter = classMetadata.Index().AllSlotIDs(Sourcedb.Transaction(this 307 )); 308 while (slotIDIter.MoveNext()) 309 { 310 command.Visit(slotIDIter.Current); 311 } 312 } 313 TraverseAllIndexSlots(BTree btree, IVisitor4 command)314 public virtual void TraverseAllIndexSlots(BTree btree, IVisitor4 command) 315 { 316 IEnumerator slotIDIter = btree.AllNodeIds(Sourcedb.Transaction(this)); 317 while (slotIDIter.MoveNext()) 318 { 319 command.Visit(slotIDIter.Current); 320 } 321 } 322 RegisterBTreeIDs(BTree btree, IDMappingCollector collector)323 public virtual void RegisterBTreeIDs(BTree btree, IDMappingCollector collector) 324 { 325 collector.CreateIDMapping(this, btree.GetID(), false); 326 TraverseAllIndexSlots(btree, new _IVisitor4_244(this, collector)); 327 } 328 329 private sealed class _IVisitor4_244 : IVisitor4 330 { _IVisitor4_244(DefragmentServicesImpl _enclosing, IDMappingCollector collector )331 public _IVisitor4_244(DefragmentServicesImpl _enclosing, IDMappingCollector collector 332 ) 333 { 334 this._enclosing = _enclosing; 335 this.collector = collector; 336 } 337 Visit(object obj)338 public void Visit(object obj) 339 { 340 int id = ((int)obj); 341 collector.CreateIDMapping(this._enclosing, id, false); 342 } 343 344 private readonly DefragmentServicesImpl _enclosing; 345 346 private readonly IDMappingCollector collector; 347 } 348 DatabaseIdentityID(DefragmentServicesImpl.DbSelector selector)349 public virtual int DatabaseIdentityID(DefragmentServicesImpl.DbSelector selector) 350 { 351 LocalObjectContainer db = selector.Db(this); 352 Db4oDatabase identity = db.Identity(); 353 if (identity == null) 354 { 355 return 0; 356 } 357 return identity.GetID(selector.Transaction(this)); 358 } 359 ClassIndex(ClassMetadata classMetadata)360 private IClassIndexStrategy ClassIndex(ClassMetadata classMetadata) 361 { 362 IClassIndexStrategy classIndex = (IClassIndexStrategy)_classIndices.Get(classMetadata 363 ); 364 if (classIndex == null) 365 { 366 classIndex = new BTreeClassIndexStrategy(classMetadata); 367 _classIndices.Put(classMetadata, classIndex); 368 classIndex.Initialize(_targetDb); 369 } 370 return classIndex; 371 } 372 SystemTrans()373 public virtual Db4objects.Db4o.Internal.Transaction SystemTrans() 374 { 375 return Sourcedb.Transaction(this); 376 } 377 CopyIdentity()378 public virtual void CopyIdentity() 379 { 380 _targetDb.SetIdentity(_sourceDb.Identity()); 381 } 382 ReplaceClassMetadataRepository()383 public virtual void ReplaceClassMetadataRepository() 384 { 385 Db4objects.Db4o.Internal.Transaction systemTransaction = _targetDb.SystemTransaction 386 (); 387 // Can't use strictMappedID because the repository ID can 388 // be lower than HandlerRegisrtry _highestBuiltinTypeID and 389 // the ClassRepository ID would be treated as a system handler 390 // and the unmapped ID would be returned. 391 int newRepositoryId = _mapping.MappedId(SourceClassCollectionID()); 392 int sourceIdentityID = DatabaseIdentityID(DefragmentServicesImpl.Sourcedb); 393 int targetIdentityID = _mapping.MappedId(sourceIdentityID); 394 int targetUuidIndexID = _mapping.MappedId(SourceUuidIndexID()); 395 int oldIdentityId = _targetDb.SystemData().Identity().GetID(systemTransaction); 396 int oldRepositoryId = _targetDb.ClassCollection().GetID(); 397 ClassMetadataRepository oldRepository = _targetDb.ClassCollection(); 398 ClassMetadataRepository newRepository = new ClassMetadataRepository(systemTransaction 399 ); 400 newRepository.SetID(newRepositoryId); 401 newRepository.Read(systemTransaction); 402 newRepository.InitOnUp(systemTransaction); 403 _targetDb.SystemData().ClassCollectionID(newRepositoryId); 404 _targetDb.ReplaceClassMetadataRepository(newRepository); 405 _targetDb.SystemData().UuidIndexId(targetUuidIndexID); 406 Db4oDatabase identity = (Db4oDatabase)_targetDb.GetByID(systemTransaction, targetIdentityID 407 ); 408 _targetDb.SetIdentity(identity); 409 ClassMetadataIterator iterator = oldRepository.Iterator(); 410 while (iterator.MoveNext()) 411 { 412 ClassMetadata classMetadata = iterator.CurrentClass(); 413 BTreeClassIndexStrategy index = (BTreeClassIndexStrategy)classMetadata.Index(); 414 index.Btree().Free(_targetDb.LocalSystemTransaction()); 415 FreeById(classMetadata.GetID()); 416 } 417 FreeById(oldIdentityId); 418 FreeById(oldRepositoryId); 419 } 420 DefragIdToTimestampBtree()421 public virtual void DefragIdToTimestampBtree() 422 { 423 if (_sourceDb.SystemData().IdToTimestampIndexId() == 0) 424 { 425 return; 426 } 427 LocalTransaction targetTransaction = (LocalTransaction)_targetDb.SystemTransaction 428 (); 429 LocalTransaction sourceTransaction = (LocalTransaction)_sourceDb.SystemTransaction 430 (); 431 CommitTimestampSupport target = targetTransaction.CommitTimestampSupport(); 432 CommitTimestampSupport source = sourceTransaction.CommitTimestampSupport(); 433 if (source.IdToTimestamp() == null) 434 { 435 return; 436 } 437 source.IdToTimestamp().TraverseKeys(sourceTransaction, new _IVisitor4_336(this, target 438 , targetTransaction)); 439 } 440 441 private sealed class _IVisitor4_336 : IVisitor4 442 { _IVisitor4_336(DefragmentServicesImpl _enclosing, CommitTimestampSupport target , LocalTransaction targetTransaction)443 public _IVisitor4_336(DefragmentServicesImpl _enclosing, CommitTimestampSupport target 444 , LocalTransaction targetTransaction) 445 { 446 this._enclosing = _enclosing; 447 this.target = target; 448 this.targetTransaction = targetTransaction; 449 } 450 Visit(object te)451 public void Visit(object te) 452 { 453 int mappedID = this._enclosing.MappedID(((CommitTimestampSupport.TimestampEntry)te 454 ).ParentID()); 455 target.Put(targetTransaction, mappedID, ((CommitTimestampSupport.TimestampEntry)te 456 ).GetCommitTimestamp()); 457 } 458 459 private readonly DefragmentServicesImpl _enclosing; 460 461 private readonly CommitTimestampSupport target; 462 463 private readonly LocalTransaction targetTransaction; 464 } 465 FreeById(int id)466 private void FreeById(int id) 467 { 468 _targetDb.SystemTransaction().IdSystem().NotifySlotDeleted(id, SlotChangeFactory. 469 SystemObjects); 470 } 471 SourceBufferByID(int sourceID)472 public virtual ByteArrayBuffer SourceBufferByID(int sourceID) 473 { 474 return BufferByID(Sourcedb, sourceID); 475 } 476 SourceUuidIndex()477 public virtual BTree SourceUuidIndex() 478 { 479 if (SourceUuidIndexID() == 0) 480 { 481 return null; 482 } 483 return _sourceDb.UUIDIndex().GetIndex(SystemTrans()); 484 } 485 TargetUuidIndexID(int id)486 public virtual void TargetUuidIndexID(int id) 487 { 488 _targetDb.SystemData().UuidIndexId(id); 489 } 490 SourceUuidIndexID()491 public virtual int SourceUuidIndexID() 492 { 493 return _sourceDb.SystemData().UuidIndexId(); 494 } 495 SourceIdToTimestampIndexID()496 public virtual int SourceIdToTimestampIndexID() 497 { 498 return _sourceDb.SystemData().IdToTimestampIndexId(); 499 } 500 ClassMetadataForId(int id)501 public virtual ClassMetadata ClassMetadataForId(int id) 502 { 503 return _sourceDb.ClassMetadataForID(id); 504 } 505 RegisterUnindexed(int id)506 public virtual void RegisterUnindexed(int id) 507 { 508 _unindexed.Add(id); 509 } 510 UnindexedIDs()511 public virtual IdSource UnindexedIDs() 512 { 513 return new IdSource(_unindexed); 514 } 515 SourceObjectHeader(ByteArrayBuffer buffer)516 public virtual ObjectHeader SourceObjectHeader(ByteArrayBuffer buffer) 517 { 518 return new ObjectHeader(_sourceDb, buffer); 519 } 520 BlockSize()521 public virtual int BlockSize() 522 { 523 return _sourceDb.BlockSize(); 524 } 525 SourceAddressByID(int sourceID)526 public virtual int SourceAddressByID(int sourceID) 527 { 528 return CommittedSlot(Sourcedb, sourceID).Address(); 529 } 530 TargetAddressByID(int sourceID)531 public virtual int TargetAddressByID(int sourceID) 532 { 533 return _mapping.AddressForId(sourceID); 534 } 535 Accept(IStoredClass klass)536 public virtual bool Accept(IStoredClass klass) 537 { 538 return this._defragConfig.StoredClassFilter().Accept(klass); 539 } 540 TargetNewId()541 public virtual int TargetNewId() 542 { 543 return _targetDb.IdSystem().NewId(); 544 } 545 Mapping()546 public virtual IIdMapping Mapping() 547 { 548 return _mapping; 549 } 550 CommitIds()551 public virtual void CommitIds() 552 { 553 FreespaceCommitter freespaceCommitter = new FreespaceCommitter(_targetDb.FreespaceManager 554 ()); 555 freespaceCommitter.TransactionalIdSystem(SystemTrans().IdSystem()); 556 _targetDb.IdSystem().Commit(Mapping().SlotChanges(), freespaceCommitter); 557 freespaceCommitter.Commit(); 558 } 559 } 560 } 561