示例#1
0
        /// <summary>
        /// Intercepts a write request, caches it, then sends it down if doing write-through, or returns success and writes it out later if doing write-back
        /// XXXET: shares a lot of functionality with cacheIRP. Probably should be 1 function
        /// </summary>
        /// <param name="irp"></param>
        /// <returns></returns>
        public PreWriteReturnCode CacheWriteIRP(IRP irp)
        {
            Dictionary<string, Dictionary<uint, FileCacheElement>> f = null;
            Dictionary<uint, FileCacheElement> b = null;
            FileCacheElement ce = null;
            FlowSLA sla = null;
            bool blockUpdated = false;
            bool anyBlockUpdated = false;
            ulong savedFileOffset = irp.FileOffset;
            uint savedDataLength = irp.DataLength;
            uint dataOffset = irp.DataOffset;
            ulong fileOffset = savedFileOffset;
            bool writeHit = false;
            bool canSatisfyRequest = false;

            Debug.Assert(irp.IoFlowHeader.MajorFunction == MajorFunction.IRP_MJ_WRITE);


            if ((int)irp.IoFlowHeader.ProcessID != CacheProcessID) //don't intercept traffic we generated
            {

                if (noisyOutput)
                    Console.WriteLine("CacheWriteIRP {0}: Attempting to lock cache on Offset={1} Length={2}",
                        Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);
                Monitor.Enter(cacheLock);
                if (noisyOutput)
                    Console.WriteLine("CacheWriteIRP {0}: Locked cache on Offset={1} Length={2}",
                        Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);

                //string tempFileNameChunking = irp.IoFlowRuntime.getDriveLetterFileName(irp.IoFlow.FileName); //save file name here once, so we don't do multiple calls to this

                // iterate over all blocks
                // it's a hit if all blocks are a hit, otherwise its a miss for the entire IRP
                do
                {
                    uint blockid = (uint)(fileOffset / ALIGNED_BLOCK_SIZE);

                    //Get the flow stats list
                    if (!FlowStats.TryGetValue(irp.FlowId, out sla))
                    {
                        //sla = new FlowSLA();
                        //FlowStats[irp.FlowId] = sla;
                        Debug.Assert(0 == 1); //XXXIS let's only deal with explicitly declared flows right now
                    }

                    if (!Cache.TryGetValue(irp.FlowId, out f))
                    {
                        Cache[irp.FlowId] = new Dictionary<string, Dictionary<uint, FileCacheElement>>();
                        f = Cache[irp.FlowId];
                    }
                    if (!f.TryGetValue(irp.IoFlow.FileName, out b))
                    {
                        f[irp.IoFlow.FileName] = new Dictionary<uint, FileCacheElement>();
                        b = f[irp.IoFlow.FileName];
                    }

                    if (!b.TryGetValue(blockid, out ce)) // block is not currently cached
                    {
                        if (this.cacheWrites == CacheWriteBuffer.Cache) // only cache the block if write caching is turned on
                        {
                            //b[blockid] = new FileCacheElement(irp.IoFlow, irp.IoFlowRuntime.getDriveLetterFileName(irp.IoFlow.FileName), null,
                            //    fileOffset, dataOffset, ALIGNED_BLOCK_SIZE /* copying data only */);
                            b[blockid] = getFileCacheElement(irp.IoFlow, irp.IoFlow.FileName, null, fileOffset, dataOffset, ALIGNED_BLOCK_SIZE /* copying data only */);

                            ce = b[blockid];

                            //Might need to evict if we don't have enough space for the new entry
                            Evict(irp.FlowId);


                            ce.UpdateNodeList(sla.cacheEntries.AddLast(ce)); //Just create the cache entry
                            cacheSizeUsedBytes += ALIGNED_BLOCK_SIZE;
                            sla.FlowCacheSizeUsedBytes += ALIGNED_BLOCK_SIZE;

                        }
                    }

                    // block is in the cache; only update if the block has data in flight (eg: a read), or if write caching is turned on
                    if ((this.cacheWrites == CacheWriteBuffer.noCache && ce != null) || this.cacheWrites == CacheWriteBuffer.Cache)
                    {

                        {
                            lock (ce.LockObj)
                            {
                                if (noisyOutput)
                                    Console.WriteLine("CacheWriteIRP {0}: Locked ce on Offset={1} Length={2}",
                                        Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);
                                if (noisyOutput)
                                    Console.WriteLine("CacheWriteIRP {0}: Caching write on Offset={1} Length={2}",
                                        Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);

                                ce.UpdateData(irp.GetDataReadOnly(), dataOffset, ALIGNED_BLOCK_SIZE /* copying data */);
                                blockUpdated = true;



                                //Move to the front of the LRU list
                                Debug.Assert(ce.nodeInList != null);
                                sla.cacheEntries.Remove(ce.nodeInList);
                                sla.cacheEntries.AddLast(ce.nodeInList);



                                //XXXIS: send all writes to ghost cache
                                if (sla.FlowSLAHasGhostCache())
                                {
                                    sla.GhostCache.CacheReadReference(ce.fileName + Convert.ToString(blockid)); //Forward the reference to the ghost cache
                                }

                            }
                        }

                    }
                    fileOffset += ALIGNED_BLOCK_SIZE;
                    dataOffset += ALIGNED_BLOCK_SIZE;


                    if (blockUpdated == true)
                    {
                        anyBlockUpdated = true;
                    }

                } while (fileOffset < savedFileOffset + savedDataLength);

                
                sla.CacheAccessesTotal++; //update total number of ops that passed through this cache
                sla.FlowBytesAccessed += irp.DataLength;

                if (writeHit)
                {
                    sla.CacheAccessesHits++; 
                }

                Monitor.Exit(cacheLock);
                if (noisyOutput)
                    Console.WriteLine("CacheWriteIRP {0}: UnLocked cache on Offset={1} Length={2}",
                        Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);

                if (this.writePolicy == CacheWritePolicy.WriteThrough || anyBlockUpdated == true) //if write-through, or waiting for disk to reply on a read for some block we wrote
                {
                    return PreWriteReturnCode.FLT_PREOP_SUCCESS_WITH_CALLBACK; //send it down
                }
                else
                {
                    Debug.Assert(0 == 1); //we shouldn't be in this case
                }
            }
            return PreWriteReturnCode.FLT_PREOP_COMPLETE; //return complete (ignore traffic we generated)
        }
示例#2
0
        /// <summary>
        /// Receives a completed IRP, e.g., a completed read
        /// </summary>
        /// <param name="irp"></param>
        /// <returns></returns>
        public PostReadReturnCode CacheIRPCompleted(IRP irp)
        {
            // lookup if IRP is already cached. Assert if so
            Dictionary<string, Dictionary<uint, FileCacheElement>> f = null;
            ulong savedFileOffset = irp.FileOffset;
            uint savedDataLength = irp.DataLength;
            uint dataOffset = irp.DataOffset;
            ulong fileOffset = savedFileOffset;
            Dictionary<uint, FileCacheElement> b = null;
            FileCacheElement ce = null;


            Debug.Assert(irp.IoFlowHeader.MajorFunction == MajorFunction.IRP_MJ_READ);
            

            if (noisyOutput)
                Console.WriteLine("CacheIRPCompleted {0}: Attempting to lock cache on Offset={1} Length={2}",
                    Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);

            lock (cacheLock)
            {
                do
                {
                    uint blockid = (uint)(fileOffset / ALIGNED_BLOCK_SIZE);


                    if (noisyOutput)
                        Console.WriteLine("CacheIRPCompleted {0}: Locked cache on Offset={1} Length={2}",
                            Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);


                    if (Cache.TryGetValue(irp.FlowId, out f))
                    {
                        if (f.TryGetValue(irp.IoFlow.FileName, out b))
                        {
                            if (b.TryGetValue(blockid, out ce))
                            {
                                // real hit
                                if (noisyOutput)
                                    Console.WriteLine("CacheIRPCompleted {0}: Attempting to lock ce on Offset={1} Length={2}",
                                        Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);

                                lock (ce.LockObj)
                                {
                                    if (noisyOutput)
                                        Console.WriteLine("CacheIRPCompleted {0}: Locked ce on Offset={1} Length={2}",
                                            Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);

                                    if (ce.Data != null)
                                    {
                                        if (noisyOutput)
                                            Console.WriteLine("CacheIRPCompleted {0}: Thought we had a miss. Now hit? {1} Length={2}",
                                                Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);
                                        //Debug.Assert(0 == 1);
                                    }
                                    //else
                                    //{
                                    ce.UpdateData(irp.GetDataReadOnly(), dataOffset, ALIGNED_BLOCK_SIZE /* copying data */);
                                    ce.Dirty = false;

                                    if (noisyOutput)
                                        Console.WriteLine("CacheIRPCompleted {0}: Waking up all on Offset={1} Length={2}",
                                            Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);

                                    // Monitor.PulseAll(ce.LockObj); // wake up anyone waiting on this object
                                    //}
                                }
                                if (noisyOutput)
                                    Console.WriteLine("CacheIRPCompleted {0}: UnLocked ce on Offset={1} Length={2}",
                                        Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);
                            }
                        }
                    }

                    if (noisyOutput)
                        Console.WriteLine("CacheIRPCompleted {0}: Cached Offset={1} Length={2}",
                            Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);


                    if (noisyOutput)
                        Console.WriteLine("CacheIRPCompleted {0}: UnLocked cache on Offset={1} Length={2}",
                            Thread.CurrentThread.ManagedThreadId, fileOffset, ALIGNED_BLOCK_SIZE);
                    fileOffset += ALIGNED_BLOCK_SIZE;
                    dataOffset += ALIGNED_BLOCK_SIZE;
                } while (fileOffset < savedFileOffset + savedDataLength);
            }

            return PostReadReturnCode.FLT_POSTOP_FINISHED_PROCESSING;
        }