This month I'd like to introduce you to a handy feature in Windows® 2000 that improves the performance of accessing files: opportunistic locks, or oplocks for short. Windows 2000 supports four types of oplocks: Level 1 (an exclusive lock), Level 2 (a read-only lock), Batch, and Filter. I'll discuss all four levels, then show you how to use a Filter oplock.
Level 1 Oplocks
Say you're using Microsoft® Word to edit a document residing on a network server. Normally, Word opens the remote file and periodically performs read and write requests against the network server. As you know, accessing files over the network is significantly slower than accessing files that reside on the local machine. In Windows 2000, oplocks are used to improve this performance.
When Word, or any application, opens a remote file, the Windows 2000 network redirector on the local machine communicates a Level 1 oplock request to the server machine. If the document file is only opened by a single client, the server grants the Level 1 (exclusive) oplock to the client machine. At this point, the network redirector knows that no other process is attempting to access the document. The network redirector can now cache the document file entirely on the client machine, improving performance. Only when the document is closed does the network redirector write the final file information back to the network server and close the file.
As you can see, this sounds great, but what if another client attempts to open the same file on the server? If the server allowed this, then the new client would see the file's original contents and would not see the first client's cached file data or any changes that have been made. In addition, if the second client were reading and writing to the file, the file's contents would be completely out of sync with the first client's view of the data. This is especially true if the second client also requested a Level 1 oplock on the file and cached the file's data locally.
Level 2 Oplocks
Since these are potentially hazardous issues, the system must have a way of addressing them. Here's what happens. When the second client attempts to open the file, the server does not respond to the second client immediately and the thread on the second client is suspended. The server remembers that the first client was granted a Level 1 oplock and notifies the first client's redirector that it can no longer have the oplock. The redirector responds to the server by writing all of the file's cached data to the server so that the file on the server is up-to-date. Then, the redirector requests a Level 2 (read-only) oplock from the server. The redirector will grant this oplock to the first client and will also allow the second client to read from the file.
A Level 2 oplock allows the first client's redirector to cache the data read from the server's file. As soon as the second clientor any process, including the process currently owning the Level 2 oplockattempts to write to the file, the server can no longer honor the Level 2 oplock because the first client's cached data would become outdated. So how does the system handle this?
When the second client first attempts to write to the file, the server notifies the first client's redirector that it can no longer keep the Level 2 oplock. The redirector responds by destroying its cache and acknowledging the notification. At this point, the first client's redirector can no longer cache any part of the server's file and all access to the file requires network communication. The first client no longer has any performance benefit. Note that in this case there is no need for the server to suspend the second client while waiting for the first client to acknowledge the broken Level 2 oplock. This is because the data in the server's file is up-to-date and can simply be accessed by the second client.
Developers typically don't have a need to work with Level 1 and Level 2 oplocks directly; Microsoft has enhanced the Windows 2000 network redirector and developers can reap the benefits.
The Batch Oplock
The Batch oplock, new in Windows 2000, is the third type of opportunistic lock. It improves performance when a file is opened and closed repeatedly. For example, when you execute a batch file from the command shell, the command processor (CMD.EXE) opens and closes the file after it parses each and every line. If the batch file resides on a network server, the performance of executing the batch file can be horrible.
To improve this situation, the client machine can open the batch file and apply a Batch oplock to it. The Batch oplock is another form of exclusive lock similar to the Level 1 oplock. If the server grants the Batch oplock, the client's network redirector knows that it has exclusive access to the batch file. The command processor now reads the first line from the file and then closes the file. However, the client machine's redirector traps the client's request to close the file and does not close it on the network server. The server still thinks that the client machine has the file open, but the client application thinks that the file is closed.
If the client attempts to open the file again, the client's redirector traps that behavior and simply allows the client application to access the still-open file. The client's redirector has no reason to communicate with the server since the server never thought the file was closed. This greatly improves performance.
If a second client attempts to access the file, the server contacts the first client's redirector, notifying it that it can no longer have the Batch oplock. While waiting for a response from the first client, the second client's thread is suspended and cannot access the file. When the first client's application closes the file (if open) and the first client's redirector acknowledges the broken Batch oplock, the server wakes the second client's thread, allowing it to access the file.
The Filter Oplock
Like the Level 1 and Level 2 oplocks, it is unlikely that you will want to use the Batch oplock specifically in your application. For application developers, the Filter oplock is the most interesting. It's also new in Windows 2000. Here's how it works.
Imagine that the user is copying all the files on one machine to another machine. The content indexing service is running in the background, hidden from the user. While the files are being copied, the content indexing service decides to open one of the not-yet-copied files and index its content. When the open file is ready to be copied, the system displays the "access denied" error to the user. This poor user has absolutely no idea why this message has appeared and why the file cannot be copiedafter all, how would the user know that the content indexing service has opened the file in the background? Plus, odds are that the content indexing service has finished indexing the file by now and, if the user starts the copy over, this time it will either work or fail on a completely different file. I pity the poor user.
So that the user does not run into this problem, the content indexing service could use Filter oplocks when accessing a file. When the content indexing service decides to open a file, it also requests a Filter oplock on the file. Now, if any other application attempts to access the file in any way, the application is suspended and the system notifies the content indexing service that another process wants to access the file. The content indexing service estimates how much more of the file it needs to index. If the indexing of the file is nearly complete, the service finishes processing the file and closes it. The system then wakes up the other process, which had no idea that the file was being accessed by the content indexing service, and gives it access. If the content indexing service determines that it has a lot more processing to do on the file, it aborts this file, closes it (allowing the other process to access it), and attempts to re-index the file at a later time.
Say you're developing a shell extensionthat is, you are creating a DLL that gets loaded into Explorer.exe's address space. If you test your extension and discover a bug, then modify your source code and rebuild, you get a linker error because the previous version's DLL file is still in use by Explorer.exe. It would be great if Microsoft enhanced Explorer.exe to load the DLL using a Filter oplock. This way, when the linker attempted to modify the DLL, the system would notify Explorer.exe, which would free the DLL. The linker could then build the new version. It would be nice to see this feature added to Microsoft Internet Information Services (IIS) for handling access to ISAPI DLLs and to Microsoft Internet Explorer for ActiveX® controls. In fact, it's easy to see the advantage of using Filter oplocks in many applications.
Testing It Out
Figure 1 shows how to use a Filter oplock that does exactly what I've been discussing. This code creates a file called FilterOpLock.dat in the working directory and accesses the file. While the file is being accessed by the application, another application can attempt to access it. When this happens, the FilterOpLock code receives a notification that the Filter lock wants to be broken and presents the user with a message box. The FilterOpLock application still has the Filter oplock and the second application is suspended while this message box is displayed. Once the message box is dismissed, the FilterOpLock application closes the file, which relinquishes the Filter oplock and allows the second process to access the file.
The first time I played with oplocks it was an eye-opener. While my application had the oplock on the file, I went to a command shell and tried to execute the following line:
|