public bool Startup(Caching.BlockCache provider, JournalRecovery recovery) { this.provider = provider; this.allocator = new Allocator(provider); this.readService = new ReadService(provider); // We issue recovery (not written by us but still valid). return(JournalLog.StartupRecovery(this)); }
public bool Startup(Caching.BlockCache provider, JournalRecovery recovery) { this.provider = provider; this.allocator = new Allocator(provider); this.readService = new ReadService(provider); this.journalLog = new JournalLog(allocator); // We issue recovery and ignore operations (certainly not written by us). return(JournalLog.StartupRecovery(this)); }
/// <summary> /// Flushes this service. /// </summary> public unsafe void Commit(Allocator allocator, JournalLog log) { freedData.Sort(); allocData.Sort(); // Upon dispose, we execute. log.RunTransaction(context.HintBlock, allocData, freedData, blocksWritten); // We can also return data to allocator. context.Dispose(); // Signal memory freed. allocator.MemoryFreed(freedData); }
/// <summary> /// Flushes this service. /// </summary> public unsafe void Dispose(Allocator allocator) { // Must sort it anyway. freedData.Sort(); List <ulong> allocs = new List <ulong>(freedData.Count + allocData.Count); allocs.AddRange(freedData); allocs.AddRange(allocData); // We sort allocations and frees. allocs.Sort(); JournalLog.WriteAllocationsDeallocs(provider, allocs); // We also end the context. context.Dispose(); // Return freed blocks. allocator.MemoryFreed(freedData); }
/// <summary> /// End the operation - called on operation log dispose. /// </summary> /// <param name="baseAddress">The key.</param> public unsafe void RunTransaction(ulong hint, List <ulong> allocations, List <ulong> deallocations, SortedList <ulong, KeyValuePair <BlockType, byte[]> > safeWrites) { int j; object key = new object(); // We compress them. List <KeyValuePair <ulong, uint> > allocationUnits = ToUnits(allocations); List <KeyValuePair <ulong, uint> > deallocationUnits = ToUnits(deallocations); // 1) Prepares the transaction. // a) Calculate number of blocks needed. uint externalBlocks = (uint)safeWrites.Count; uint logSize = (uint)(((allocationUnits.Count + deallocationUnits.Count + safeWrites.Count) * (long)sizeof(JournalLogData) + (long)allocator.BlockSize - 1) / (long)allocator.BlockSize); // No transaction needed. if (logSize == 0) { return; } // b) Allocate blocks. List <ulong> blocks = allocator.Allocate(key, hint, AllocationStrategy.JournalAllocation, externalBlocks + logSize); Logger logger = new Logger(blocks, allocator.Provider); try { // c) Write data to blocks. for (j = 0; j < allocationUnits.Count; j++) { // We write entry for each allocation. logger.Log(new JournalLogData(JournalLogKind.AllocateBlock, allocationUnits[j].Key, allocationUnits[j].Value)); } for (j = 0; j < deallocationUnits.Count; j++) { logger.Log(new JournalLogData(JournalLogKind.DeallocateBlock, deallocationUnits[j].Key, deallocationUnits[j].Value)); } for (j = 0; j < safeWrites.Count; j++) { ulong backupAddress = safeWrites.Keys[j]; byte[] data = allocator.Provider.Read(safeWrites.Values[j].Key, backupAddress); logger.Log(new JournalLogData(JournalLogKind.UpdateBlock, logger.Log(data), backupAddress)); } // Make sure we flush it. logger.Flush(); ulong journalAddress = GetNearestJournal(hint, frequency, allocator.BlockSize, allocator.BlockCount); uint journalAddressOffset = uint.MaxValue; // 2) Allocates the journal sector. lock (syncRoot) { // Find free space and write. byte[] block = allocator.Provider.Read(BlockType.JournalSectorBlock, journalAddress); fixed(byte *p = block) { ulong *data = (ulong *)p; for (uint z = 0; z < allocator.BlockSize / 8; z++) { if (z == 0) { data[z] = blocks[0]; journalAddressOffset = z; break; } } if (journalAddressOffset == uint.MaxValue) { throw new InvalidOperationException(); } } // We are in transaction now. allocator.Provider.Write(BlockType.JournalSectorBlock, journalAddress, block); } // Must be able to recover from those states. // 3) Execute operations (writes). List <ulong> all = new List <ulong>(allocations.Count + deallocations.Count); all.AddRange(allocations); all.AddRange(deallocations); // a) Write allocs and deallocs JournalLog.WriteAllocationsDeallocs(allocator.Provider, all); // b) Write to buffers. for (int z = 0; z < safeWrites.Count; z++) { allocator.Provider.Write(safeWrites.Values[z].Key, safeWrites.Keys[z], safeWrites.Values[z].Value); } // 4) Deallocate the journal sector (finished operation). lock (syncRoot) { byte[] block = allocator.Provider.Read(BlockType.JournalSectorBlock, journalAddress); fixed(byte *p = block) { ulong *data = (ulong *)p; data[journalAddressOffset] = 0; } allocator.Provider.Write(BlockType.JournalSectorBlock, journalAddress, block); } } finally { allocator.ReturnAllocations(key, blocks); } }