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));
        }
Beispiel #2
0
        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));
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
        /// <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);
        }
Beispiel #5
0
        /// <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);
            }
        }