/// <summary> /// Initializes a new instance of the <see cref="PhysicalDatabase"/> class. /// </summary> /// <param name="journal">The journal.</param> public unsafe PhysicalDatabase(IJournal journal, Caching.BlockCache cache, JournalRecovery recovery) { this.journal = journal; this.journal.Startup(cache, recovery); // Must make sure we construct the first node if not already there ("default node"). Block block = journal.ReadService.Read(BlockType.NoCache, 0); fixed(byte *p = block.Data) { DatabaseHeader *header = (DatabaseHeader *)p; rootAddress = header->RootObjectAddress; } // We must initialize it. if (rootAddress == 0) { journal.Execute(new Operations.CreateRootObject()); block = journal.ReadService.Read(BlockType.NoCache, 0); fixed(byte *pp = block.Data) { DatabaseHeader *header = (DatabaseHeader *)pp; rootAddress = header->RootObjectAddress; } Debug.Assert(rootAddress != 0); } }
/// <summary> /// Initializes a new instance of the <see cref="JournalLog"/> class. /// </summary> /// <param name="journal">The journal.</param> /// <param name="allocator">The allocator.</param> /// <param name="frequency">The frequency.</param> public unsafe JournalLog(Allocator allocator) { this.allocator = allocator; byte[] data = allocator.Provider.Read(BlockType.NoCache, 0); fixed(byte *p = data) { DatabaseHeader *header = (DatabaseHeader *)p; this.frequency = header->JournalFrequency; } }
/// <summary> /// Initializes a new instance of the <see cref="Allocator"/> class. /// </summary> /// <param name="provider">The provider.</param> public unsafe Allocator(Caching.BlockCache provider) { this.provider = provider; byte[] data = provider.Read(BlockType.NoCache, 0); fixed(byte *p = data) { DatabaseHeader *header = (DatabaseHeader *)p; if (!header->IsValid) { throw new DatabaseException("The database header is not valid, not a valid physical database. Must reformat it."); } blockCount = header->BlockCount; } }
/// <summary> /// Formats the database with provider. /// </summary> /// <param name="provider">The provider.</param> /// <param name="databaseName">Name of the database, maximum 63 characters long.</param> /// <param name="blockCount">The block count.</param> /// <param name="journalSectorFreq">The journal frequency.</param> /// <param name="journalSize">Size of the journal.</param> /// <param name="journalFrequency">The journal frequency, meaning depends on sector frequency.</param> /// <returns></returns> public unsafe static bool Format(IProvider provider, string databaseName, ulong blockCount, uint journalFrequency) { if (databaseName == null || databaseName == string.Empty || databaseName.Length > 63) { throw new ArgumentException("Database name was either invalid or too long."); } // 1) We first enlarge the provider (must be at least that long). if (!provider.Enlarge(blockCount)) { return(false); } // 2) We create the header node. Block block = new Block(provider.BlockSize); fixed(byte *p = block.Data) { DatabaseHeader *header = (DatabaseHeader *)p; header->BlockSize = provider.BlockSize; header->BlockCount = blockCount; header->HeaderMagic1 = DatabaseHeader.Magic1; header->HeaderMagic2 = DatabaseHeader.Magic2; header->JournalFrequency = journalFrequency; header->RootObjectAddress = 0; // Copy the name. int i; for (i = 0; i < databaseName.Length; i++) { header->DatabaseName[i] = databaseName[i]; } header->DatabaseName[i] = '\0'; } // We write it. provider.Write(0, block.Data); // Make an empty (zero block). block.ZeroMemory(); // The one allocated block. Block fullBlock = new Block(provider.BlockSize); fullBlock.ZeroMemory(); BoolArray fullBlockArray = new BoolArray(fullBlock.Data); fullBlockArray[0] = true; // 3) We clear allocation blocks. for (ulong superBlock = BlockHelper.FirstSuperBlockAddress; superBlock != 0; superBlock = BlockHelper.GetNextSuperBlock(provider.BlockSize, superBlock, blockCount)) { provider.Write(superBlock, block.Data); } for (ulong allocBlock = BlockHelper.FirstSuperBlockAddress + 1; allocBlock != 0; allocBlock = BlockHelper.GetNextAllocationBlock(provider.BlockSize, allocBlock, blockCount)) { if (JournalLog.IsJournalLog(allocBlock + 1, journalFrequency, provider.BlockSize)) { // We write the allocated. provider.Write(allocBlock, fullBlock.Data); // Next block is filled with header. if (allocBlock + 1 < blockCount) { provider.Write(allocBlock + 1, block.Data); } } else { provider.Write(allocBlock, block.Data); } } return(true); }
public unsafe void Execute(uint stage, IService service) { string defaultTSType = typeof(object).FullName; // 1) We create the node common block. ulong versionAddress = service.AllocationContext.AllocateBlock(); ulong commonAddress = service.AllocationContext.AllocateBlock(); BPlusTree versionTS = new BPlusTree(service.AllocationContext.CreateEmptyBTree()); // Fill common block and write. Block commonBlock = new Block(service.BlockSize); fixed(byte *p = commonBlock.Data) { NodeCommonHeader *header = (NodeCommonHeader *)p; header->ChildrenBTree = service.AllocationContext.CreateEmptyBTree(); header->CurrentVersionAddress = versionAddress; header->CurrentVersionNumber = 0; header->HeaderMagic = NodeCommonHeader.Magic; header->ParentAddress = 0; header->VersionsBTree = versionTS.RootAddress; } service.Write(BlockType.NodeHeaderBlock, commonAddress, commonBlock); // 2) We create the node default typed stream. Block tsblock = new Block(service.BlockSize); fixed(byte *p = tsblock.Data) { TypedStreamHeader *header = (TypedStreamHeader *)p; header->ObjectsAddress = service.AllocationContext.AllocateBlock(); header->Options = StreamOptions.None; header->ObjectSize = 0; int i; for (i = 0; i < defaultTSType.Length; i++) { header->Type[i] = defaultTSType[i]; } // Null terminate it. header->Type[i] = '\0'; } ulong tsBlock = service.AllocationContext.AllocateBlock(); service.Write(BlockType.TypedStreamHeader, tsBlock, tsblock); // 3) We create the node version block. // Fill version block and write. Block versionBlock = new Block(service.BlockSize); fixed(byte *pp = versionBlock.Data) { NodeVersionHeader *header = (NodeVersionHeader *)pp; header->CreationTime = DateTime.Now; header->DefaultTypedStream = 0; header->HeaderMagic = NodeVersionHeader.Magic; header->ModifiedTime = DateTime.Now; header->NodeCommonAddress = commonAddress; header->StreamCount = 0; //< Is actually one but NodeHelper changes this. header->VersionNumber = 0; } // We must add default typed stream to block. NodeVersionHelper.AddTypedStream(tsBlock, defaultTSType, versionBlock); service.Write(BlockType.NodeHeaderBlock, versionAddress, versionBlock); // 4) We must create versions VersionTag versionTag = new VersionTag((0).GetHashCode()); versionTag.Add(0, versionAddress); byte[] versionTagData = Common.SerializeToArray(versionTag); // Write to stream. BlockStream versionTagStream = service.AllocationContext.CreateBlockStream((ulong)versionTagData.LongLength); versionTagStream.Write(versionTagData); versionTS.Add(service, new ObjectInfo((uint)(0).GetHashCode(), (ulong)versionTagData.LongLength, versionTagStream.BaseAddress)); // 5) We must write to database header. Block block = service.Read(BlockType.NoCache, 0); fixed(byte *ppp = block.Data) { DatabaseHeader *header = (DatabaseHeader *)ppp; header->RootObjectAddress = commonAddress; } // Write the header. service.Write(BlockType.NoCache, 0, block); }