Previous Next

Thread: Response caching behaviour on IIS7?

Last post 11-01-2006 6:52 PM by anilr. 8 replies.

Average Rating Rate It (5)

RSS

Page 1 of 1 (9 items)

Sort Posts:

  • 10-23-2006, 6:53 PM

    • cminihan
    • Not Ranked
    • Joined on 10-23-2006, 9:54 PM
    • Oxfordshire, UK
    • Posts 5

    Response caching behaviour on IIS7?

    I'm writing a native module for IIS7 and have seen a caching effect which I would like to understand.

    Basically CMyHttpModule::OnSendResponse is called twice (for each URL) and then is not called again until the app pool is recycled. I've observed that this only occurs for static content since dynamic content (ASPX) is invoked each time a client request is processed.

    I've replicated the scenario on Vista RC2 and Longhorn 5600 so I guess it's a genuine IIS7 feature, however I really would like to know each time a request/response is handled even if the data ultimately comes from a cache.

    I've placed a DebugView log at this URL: http://www.ripcordsoftware.com/IIS7/vista32-rc2.LOG.txt. In the log you can see that the ASPX is handled 3 times while the TXT is only handled twice even though CTRL-F5 is being pressed at the client side.

    I'm developing the Vista/Longhorn port of IISxpress which is an enhanced compression plugin for IIS, so you can see that I would like to hook all responses.

    Best regards,

    Craig Minihan, IISxpress Lead Developer, www.ripcordsoftware.com

  • 10-28-2006, 6:17 AM In reply to

    • mvolo
    • Top 10 Contributor
    • Joined on 09-17-2003, 1:48 PM
    • Philadelphia, PA
    • Posts 583
    • IIS MVPs

    Re: Response caching behaviour on IIS7?

    Craig,

    IIS6 / Windows Server 2003 and above support a feature called "kernel caching", where compatible responses are stored in the kernel http driver's cache and served to subsequent requests for that resource without ever being given to IIS.  This results in amazing performance for non-dynamic content because the requests are processed without ever coming into user mode.

    The IIS static file handler will often cache the static file responses in the kernel cache, whereas ASP.NET and other dynamic application platforms have to explicitly request kernel caching through configuration.

    Many IIS features that require each request to be processed in IIS (such as authentication, custom logging, etc) will automatically disable kernel caching for responses.  If you are building a module that requires requests to always be seen in IIS, then you need to do the same - in IIS7, you need to call IHttpResponse->DisableKernelCache() method for each request to prevent the response from being kernel cached, regardless of whether the handler producing the content (such as static file handler) has requested it.

    Thanks,
    This posting is provided "AS IS" with no warranties, and confers no rights.
  • 10-30-2006, 1:29 PM In reply to

    • iiscool
    • Top 75 Contributor
    • Joined on 05-23-2006, 8:48 PM
    • Posts 44

    Re: Response caching behaviour on IIS7?

    Or you could explicitly set the "enableKernelCache" property to FALSE if you do not want to cache any (static\dynamic) kind of response to achieve the behavior you want for your native IIS7 module.

    system.webServer/caching/enableKernelCache

  • 10-31-2006, 5:19 PM In reply to

    • cminihan
    • Not Ranked
    • Joined on 10-23-2006, 9:54 PM
    • Oxfordshire, UK
    • Posts 5

    Re: Response caching behaviour on IIS7?

    Hi Mike,

    Your suggestion worked a treat I'm now getting all responses calling OnSendResponse() which is exactly what I wanted. Thanks!

    However, once one problem is solved another appears. I'm trying to handle response chunks from file (HttpDataChunkFromFileHandle) and don't seem to be able to read from the file handle supplied. Example code below:

    if (pEntityChunk->DataChunkType == HttpDataChunkFromFileHandle)
    {
     BYTE* pbyData = (BYTE*) pHttpContext->AllocateRequestMemory(dwContentLength);  

     ::SetLastError(0);

     LONG nDistanceToMoveHigh = 0;
     ::SetFilePointer(pEntityChunk->FromFileHandle.FileHandle, 0, &nDistanceToMoveHigh, FILE_BEGIN);   

     DWORD dwError = ::GetLastError();

     ::SetLastError(0);

     DWORD dwBytesRead = 0;
     ::ReadFile(pEntityChunk->FromFileHandle.FileHandle, pbyData, dwContentLength, &dwBytesRead, NULL);  

     dwError = ::GetLastError();

     // do something interesting here
    }

    I've added the Set/GetLastError() calls so that I can catch what is going wrong. The SetFilePointer() call succeeds, however the ReadFile() call doesn't. The error number is 0x57 which maps to 'The parameter is incorrect'. I've tried various other calls like GetFileSize() and GetFileType() which work as expected.

    Incidentally the value of the handle appears in Sysinternal's Process Explorer as a valid handle associated with the w3wp process, so I know it is valid.

    Thanks.

    Craig Minihan, IISxpress Lead Developer, www.ripcordsoftware.com

  • 10-31-2006, 5:31 PM In reply to

    • mvolo
    • Top 10 Contributor
    • Joined on 09-17-2003, 1:48 PM
    • Philadelphia, PA
    • Posts 583
    • IIS MVPs

    Re: Response caching behaviour on IIS7?

    Debug your call to ReadFile - I would bet you $5 that you are passing in some bad arguments.

    Actually, I take that back - I dont think I am supposed to bet money on this - but I am pretty sure thats where you problem is based on your information.

    Thanks, 
    This posting is provided "AS IS" with no warranties, and confers no rights.
  • 10-31-2006, 5:54 PM In reply to

    • cminihan
    • Not Ranked
    • Joined on 10-23-2006, 9:54 PM
    • Oxfordshire, UK
    • Posts 5

    Re: Response caching behaviour on IIS7?

    Hi Mike,

    Apart from the file handle itself the pbyData comes from AllocRequestMemory(), dwContentSize comes from pEntityChunk->FromFileHandle.ByteRange.Length.LowPart, dwBytesRead is 0 and overlapped is NULL. I can't see what could be wrong!

    BTW I have attached a debugger to the code and checked all the params before the ReadFile() call, nothing looked suspicious.

    Thanks,

    Craig Minihan, IISxpress Lead Developer, www.ripcordsoftware.com

  • 10-31-2006, 6:34 PM In reply to

    • anilr
    • Top 10 Contributor
    • Joined on 05-23-2006, 10:13 PM
    • Redmond, WA
    • Posts 1,210

    Re: Response caching behaviour on IIS7?

    The code snippet has no chance of working correctly
    a) using SetFilePointer is not good, the file handle may be used by multiple responses simultaneously
    b) need to use pOverlapped for ReadFile - you can specify offset using pOverlapped (don't forget to set a event handle in pOverlapped) - if you do not want async execution, you can use GetOverlappedResult(..., TRUE) to wait for ReadFile to complete
    c) file handle may be opened with FILE_FLAG_NO_BUFFERING (for perf reasons) - so the read buffer, read size and read offset would need to be aligned to page-size - you can use VirtualAlloc to get memory which is aligned to page-size
    Anil Ruia
    Senior Software Design Engineer
    IIS Core Server
  • 10-31-2006, 8:03 PM In reply to

    • cminihan
    • Not Ranked
    • Joined on 10-23-2006, 9:54 PM
    • Oxfordshire, UK
    • Posts 5

    Re: Response caching behaviour on IIS7?

    Bingo - thanks Anil. It doesn't surprise me that the code doesn't work - since there is no way to query the file handle for properties like overlapped it would have been guess work on my part (maybe WinDbg would have been useful here).

    I've included the 'working' code here:

    if (pEntityChunk->DataChunkType == HttpDataChunkFromFileHandle)

    {

    // get the number of bytes per sector

    DWORD dwBytesPerSector = 0;

    ::GetDiskFreeSpace(NULL, NULL, &dwBytesPerSector, NULL, NULL);

    // calculate the size of the file buffer we need for the overlapped xfer (must be a multiple of sector size)

    DWORD dwFileBlockSize = dwContentLength;

    dwFileBlockSize += dwBytesPerSector;

    dwFileBlockSize &= ~(dwBytesPerSector - 1);

    // allocate the memory block allowing for enough space for a move to a sector size boundary

    BYTE* pbyData = (BYTE*) pHttpContext->AllocateRequestMemory(dwFileBlockSize + dwBytesPerSector);

    // calculate how many bytes we are away from the sector boundary

    // pragma out the warning if required since the rounding isn't a problem here

    DWORD dwDataBlockOffset = reinterpret_cast<DWORD>(pbyData) % dwBytesPerSector;

    // move the pointer to a sector boundary

    pbyData += dwBytesPerSector;

    pbyData -= dwDataBlockOffset;

    // we are about to perform overlapped IO, so setup the OVERLAPPED struct into a default state

    OVERLAPPED overlapped;

    memset(&overlapped, 0, sizeof(overlapped));

    // we need an event handle so we can track the IO completion

    HANDLE hReadOK = ::CreateEvent(NULL, TRUE, FALSE, NULL);

    overlapped.hEvent = hReadOK;

    // ask for a file read (asyncronous)

    DWORD dwStatus = ::ReadFile(pEntityChunk->FromFileHandle.FileHandle, pbyData, dwFileBlockSize, NULL, &overlapped);

    // wait for the IO to complete (NB. don't really use this since INFINITE can block forever)

    ::WaitForSingleObject(hReadOK, INFINITE);

    // do some processing here....

    }

  • 11-01-2006, 6:52 PM In reply to

    • anilr
    • Top 10 Contributor
    • Joined on 05-23-2006, 10:13 PM
    • Redmond, WA
    • Posts 1,210

    Re: Response caching behaviour on IIS7?

    That looks ok - although if you use the real offset, that also has to be rounded down to the page size, and you have to remember to ignore the extra data that you may have actually read in the ReadFile call - to really test your code, make a Range request to a static file (so you have non-zero offset and the size does not span the whole file).  Also, using VirtualAlloc will allow you to waste less memory (although you lose the garbage-collection ability of AllocateRequestMemory).
    Anil Ruia
    Senior Software Design Engineer
    IIS Core Server
Page 1 of 1 (9 items)
Page view counter