Chapter 6. Mailbox and Public Folder Database Management

Introduction

Exchange uses a set of databases to store mail and public folder data. At a very basic level, Exchange is simply a highly specialized database management system. Understanding how to optimize your organization’s use of Exchange databases and transaction logs will ensure that you get the best performance and reliability from your messaging infrastructure.

Storage Groups

Exchange 2000 introduced the concept of the storage group (SG): a set of databases (each one of which can contain mailbox or public folder data) that share a common set of transaction logs. The impetus behind this design is simple: you can mount or dismount individual databases, which means you can back up, restore, repair, defragment, or otherwise work with one database without affecting users whose mailboxes are in other databases. Exchange 2000 and Exchange Server 2003 Enterprise Edition servers can have up to four SGs, whether they’re standalone or clustered, with up to five databases in each SG. The Standard edition of these products allows you to create one MAPI public folder database and one mailbox database (although you can create additional non-MAPI public folder stores, and even multiple SGs, if you like). Each of these databases is limited to 16 GB in size; Enterprise Edition databases don’t have set size limits.

Exchange Server 2003 offers a special additional SG known as a recovery storage group (RSG); the RSG can be used to mount any database from any Exchange 2000 or later server in the organization. Once the database is mounted in the RSG, you can copy mailbox data out of it and into another database, making it easy to set up “life support” messaging during a disaster recovery.

The EDB Database Files

Exchange stores much of its message data in files known as EDB files, after their file extension. These files contain all of the message, folder, and attachment properties that Exchange exposes via MAPI and WebDAV; apart from the messages and mailboxes themselves, there are a large number of indices and tables that are dynamically created and updated to provide improved performance for various types of queries. Exchange has always used a custom database engine known as the Extensible Storage Engine, or ESE. ESE provides a low-level interface that the Information Store service builds on; ESE is mostly concerned with the content and arrangement of the 4 KB pages that make up the individual database files. ESE is optimized for storing MAPI messages, which have an interesting quirk: the set of properties stored for two different messages may be very different, making it hard to efficiently construct a relational database structure to contain them.

Among its other duties, ESE is responsible for implementing transaction logging (more on that in the next section), providing an interface for reading and writing individual database pages, and managing the process of performing backups using the ESE backup API or the Windows Server 2003 Volume Shadow Copy Service (VSS).

The Streaming Database Files

One of the biggest scalability limits in Exchange 5.5 came from Exchange using its own native storage format (the Transport Neutral Encapsulation Format, or TNEF) to store items in the store. Unfortunately, TNEF bears approximately zero resemblance to the Multipurpose Internet Mail Extensions (MIME) standard, the way mail messages are actually transported around on the Internet. That means that any time a client used SMTP to submit a message to the store, it had to be converted from MIME to TNEF. Worse yet, any time an Internet-protocol client wanted to use POP3, IMAP4, or HTTP to get a message out it had to be converted back. Worst of all, the content conversion always took place, even if it wasn’t necessary! This ate up so much CPU and I/O bandwidth that Microsoft decided to take an alternate approach for Exchange 2000.

The streaming media, or STM, file is that approach. It provides a way for the Exchange components to stream data in on-the-wire formats like MIME, without breaking it up into 4 KB chunks and storing it in an EDB file. That means that a 10 MB PowerPoint presentation or a 25 MB QuickTime movie will be stored with no content conversion and without being split up. Content will no longer be converted unless it’s absolutely necessary; when a message is received through an Internet protocol, the data is passed through to the STM file, and the native MIME streams are left intact. If another Internet protocol client attempts to read the data, it is streamed directly out of the native content store without ever being converted. If a MAPI client such as Outlook 2000 attempts to read the data that resides in the native content store, the store process converts the MIME stream into a set of MAPI properties on demand and passes the data to the Outlook client. Better yet, this on-demand conversion takes place entirely in memory unless the data are changed as part of the process (for example, if an Outlook user opens that PowerPoint presentation, edits it, and saves it again).

The store uses a very aggressive online defragmentation process to keep as much contiguous space as possible free in the STM file. Interestingly, STM files are like magnetic poles: they don’t exist by themselves. STM files are always paired with EDB files, and the two files share a set of transaction logs, are backed up together, and generally combine to act as a unit. The two are even added together to determine the store size, when calculating the 16 GB database size limit in Standard editions of Exchange.

The Transaction Logs

The fundamental idea behind logging is simple: the logs store copies of all transactions. These stored transactions can be played back later to restore a corrupted database, or even to retry a transaction that didn’t complete successfully. Logging is a mainstay of relational database engines because it provides a backup mechanism for transactions to help preserve the ACID properties of the database:

  • Atomicity means that a transaction is a complete unit unto itself. If you withdraw $100 from your bank’s ATM, you want the two separate operations of debiting your account $100 and giving you the money to be treated as one indivisible unit.

  • Consistency means that if you apply a transaction to a database in a given state, the result will always be the same.

  • Isolation means that a transaction, when applied, should only directly affect its target data; if you alter record A, then there should be no changes to record B.

  • Durability means that the transaction changes are persisted to the database, so they don’t disappear when the database is shut down.

Although Exchange treats the logs for a SG as a single entity, it’s actually a set of files, each of which is exactly 5 MB (that’s 5,242,880 bytes, for you purists) in size, even if there aren’t any transactions in it. If you see a log file that’s any other size, it’s probably corrupted. The IS maintains a log file named edb.log. When the log file fills up, the IS service renames it, using a sequential hexadecimal ID (the first file is edb00001.log, the second is edb00002.log, and so on). These renamed log files are called generations ; edb.log represents the highest, or most recent, generation. Note that just because a log file is full, doesn’t mean its transactions have been committed—all commitments happen according to a process I’ll describe in a moment.

The log files contain a number of tidbits that are useful if the logs have to be played back during server recovery, including the full path to the database files, information about which generation of log data is in the file, a signature and timestamp for the data, and a signature for the database. This header information enables the store to make sure that each log file is replayed into the correct database file, and to balk if you do something like try to restore files from one machine onto another. Of course, the log files also contain information about the transactions themselves. For each transaction, the log records the type of transaction (i.e., whether the transaction represents a change, a rollback of a previous change, or a commit of a previous change). These transactions record the low-level modifications to individual pages and tables within the database.

The logging process

Logging transactions is a good way to keep the database unsullied and consistent; however, there may be performance costs involved. A simplistic logging mechanism would just log transactions to a file, then periodically inject them into the database. The Exchange logging process is quite a bit smarter; it works like this:

  1. Something happens—a message arrives, a draft is saved—and a new database transaction is created by the information store. The transaction only reflects data that has changed; for example, if you open a draft message in your mailbox, edit it, and resave it, the transaction will contain only your changes, not the entire draft.

  2. The timestamp on the page that will be changed by the new transaction is updated.

  3. The transaction is logged to the current generation of log file for the service that owns it. Transactions are written to the log file in sequential order. Once the transaction has been logged, the calling entity assumes that it will be properly registered in the database and goes about its business.

  4. The transaction is applied to the version of the store database cached in RAM. The store never records a transaction to the cached database until the transaction has been logged.

  5. When the log file hits its maximum size, the service that owns the log file renames it and creates a new log generation. This log file will stay on disk until it’s purged during an online backup.

  6. Exchange copies the transactions from the cached copy in RAM back to the disk version of the database. This so-called “lazy commit” strategy means that at any point in time the “real” database consists of data from the database file on disk, data from the database copy in RAM, and as-yet-uncommitted transactions.

When a database is dismounted normally (say, by ESM or when the server is shut down normally), any transactions that have been made to the in-RAM copy of the database are committed to the disk version, and the checkpoint file is updated to reflect which transactions have been committed. If the service is shut down abnormally (say, by a power failure), when it restarts, it will scan its inventory of log files and play back any uncommitted transactions from the log files to the database. This means that it’s very important not to move, delete, edit, or otherwise disturb the log files until their transactions have been committed.

The checkpoint file

How does the IS track which transactions have been logged? The IS service maintains a checkpoint file named edb.chk. Whenever a transaction is committed, the checkpoint file is updated to point to that transaction. The service uses the checkpoint file at startup time; if this file is present, transactions are played back from the checkpoint to the end of the last available log file. The checkpoint file tells the store which transaction log files contain uncommitted transactions, and would be needed in case of a crash. If the checkpoint file is missing or damaged, Exchange can scan each log file and check whether its transactions have been committed, but this is much slower than using the checkpoint files.

The reserve logs

Since transaction processing depends on log files, it’s a fair question to wonder what would happen if there wasn’t enough space to start a log file. As a last-ditch defense against running out of space, the IS service maintains two reserve log files named res1.log and res2.log. When edb.log fills up and is renamed, if there’s not enough space to create a new file, the store service will use the reserve file instead. If this happens, ESE will send a remote procedure call to the service. When the service gets this special emergency message, it will flush any uncommitted transactions from memory into the reserve log files, and then shut down cleanly. The service will also log an event in the system event log; if your IS service won’t start, check the event log to make sure you have adequate free space.

Circular logging

The normal process of creating logs is appropriate for most servers, because you want a complete record of all transactions that have occurred. However, in some circumstances you might want to keep a reduced set of log data. For example, SMTP bridgehead servers have to have a mounted mailbox database in order to generate NDRs, but there’s no reason to accumulate tons of log files for that database since it won’t contain any useful data. You might also want to reduce the number of log files generated by activities that would ordinarily generate large numbers of log files, like moving mailboxes from one server to another.

Exchange has long supported an additional logging mode called circular logging in which only a limited number of log files are kept. After a log’s transactions have been committed to the information store, the log file is overwritten. This reduces the disk space required for logging, but when circular logging is enabled you can only recover the most recent full backup—you can’t play back the same range of transactions as you could without circular logging. Microsoft recommends that you leave circular logging disabled on regular servers, enabling it only when you specifically want to reduce the number of log files kept on a server.

6.1. Creating a Storage Group

Problem

You want to create a new SG on an Exchange server.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Right-click the target server, and choose New Storage Group.

  4. Type a name in the Name field.

  5. Optionally, change the location of the store database and log files to a different volume or path in the appropriate dialog boxes.

  6. Optionally, enable circular logging or zeroing out of deleted database pages.

  7. Click OK.

Using VBScript

' This code creates a new storage group on the target Exchange server 
' ------ SCRIPT CONFIGURATION ------
 strComputerName = "<serverName>" ' e.g., "batman"
 strSGName = "<storageGroupName>" ' e.g., "New Storage Group"
' ------ END CONFIGURATION ---------
  
  set theServer = CreateObject("CDOEXM.ExchangeServer")
  Set theSG = CreateObject("CDOEXM.StorageGroup")
  theServer.DataSource.Open strComputerName
  
  ' get the URL of the first SG on this particular server
  sgArray = theServer.StorageGroups
  strSGName = sgArray(0)

   ' stuff our new SG name into the URL
    strTemp = Mid(strTemp, InStr(2, strTemp, "CN"))
    strTargetSG = "LDAP://" & theServer.DirectoryServer & "/CN=" & _
     strSGName & "," & strTemp
   
   ' saving the new SG object to this URL actually creates the SG
   theSG.DataSource.SaveTo strTargetSG
   WScript.echo "Created SG " & strSGName & " successfully".

Discussion

The Enterprise version of Exchange 2000 and Exchange Server 2003 Servers supports up to four SGs, each containing five databases. The Standard edition allows zero or one public databases and zero or one mailbox databases; normally these are in the same SG. Exchange Server 2003 also allows you to create and use a recovery storage group, but the presence of an RSG doesn’t count against the four-SG limit.

Even though you can easily create multiple SGs, you probably shouldn’t do so until you have used all the database slots in the first SG on your server. Every time you add a SG, you also add an additional instance of the ESE code, which adds a significant amount of memory overhead. The one time to violate this rule is when you need to create a separate set of transaction logs; since logs belong to the SG and not the database, if you want multiple separate log sets, you’ll have to create multiple SGs.

When you do create a new SG, you’ll note that there are settings for enabling circular logging and page zeroing. I’ve already explained what circular logging is and when you should use it, but page zeroing is a different matter. When a database page is deleted from an ESE file, the page header is marked with a tombstone that indicates that the page is free, and it goes into the whitespace pool for reassignment later. Its contents remain intact, though, which means that confidential data could potentially be recovered by anyone who can get access to the database file or backup copies. In most environments, this is a low risk; however, if you turn on page zeroing, each deleted page is filled with zeroes when it’s marked as deleted. When planning for performance, keep in mind that page zeroing is a highly disk-intensive process and has a substantial performance impact.

The VBScript code uses CDOEXM to actually create the new SG. The CDOEXM StorageGroup object requires that you specify a URL at which the new SG will be created; although you can specify the complete URL, it’s easier to specify the new SG’s name and the server where you want it created, then retrieve the first named SG on the server and use its URL to construct the URL of the new object. By default, Exchange will create the SG log files in the default log path; you can move them later using the method described in Recipe 6.9. As with most other CDOEXM objects, you have to use the SaveTo method to finalize your changes.

See Also

Recipe 6.9 for moving storage group logs to another disk location, Recipe 11.11 for using recovery storage groups, MS KB 319218 (HOW TO: Add New Mailbox Stores in Exchange 2000), MS KB 821748 (HOW TO: Add New Mailbox Stores in Exchange Server 2003), MSDN: CDOEXM documentation, and MS KB 824126 (How to use Recovery Storage Groups in Exchange Server 2003)

6.2. Deleting a Storage Group

Problem

You want to delete a storage group on an Exchange server.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target storage group.

  4. Right-click the storage group and choose Delete.

  5. Click Yes in the confirmation dialog.

Using VBScript

' This code deletes the selected storage group. 
' ------ SCRIPT CONFIGURATION ------
 strComputerName = "<serverName>" ' e.g., "batman"
 strSGName = "<storageGroupName>" ' e.g., "New Storage Group"
' ------ END CONFIGURATION ---------
  
  set theServer = CreateObject("CDOEXM.ExchangeServer")
  Set theSG = CreateObject("CDOEXM.StorageGroup")
  theServer.DataSource.Open strComputerName
  
  ' examine the SGs and see if we can find ours. This code will
  ' delete any SG whose name contains strSGName, so be careful!
   For Each sg In theServer.StorageGroups
      WScript.Echo "Examining " & sg
      isIn = InStr(1, UCase(sg), UCase(strSGName))
      If (isIn<>0) Then
         wscript.echo "Deleting " & sg
         theSG.DataSource.Open "LDAP://" & theServer.DirectoryServer & "/" & sg

        ' delete the storage group
        theSG.DataSource.Delete 
        WScript.Echo "Deleted SG " & sg   
      End if
   Next

Discussion

Unlike mailbox or public databases, the SG object itself doesn’t really have any useful data in it; it’s a container that points to a set of transaction logs and databases. Accordingly, when you remove it, the corresponding directory object is removed but nothing changes on the target server’s filesystem. You can easily recreate a deleted SG, since the databases and log files are left intact (but orphaned) when you delete the SG itself.

You must first delete (or move) any mailbox or public folder stores that are housed in the SG. If you attempt to delete a SG that still contains active databases, ESM will complain; if you’re doing it from within a script, the script will fail.

See Also

Recipe 6.1 for creating storage groups, Recipe 5.6 for moving mailboxes, Recipe Recipe 6.6 for deleting databases, and MSDN CDOEXM documentation

6.3. Enumerating the Storage Groups on a Server

Problem

You want a report that shows you what storage groups exist on your server, and where their database and log files are located.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Select the target server.

  4. Right-click on a storage group and choose Properties. The General tab of the Storage Group Properties dialog box will display the system file and log file locations. Click OK to dismiss the properties dialog.

  5. Repeat step 4 for each additional storage group on the server.

Using VBScript

' This code lists all of the storage groups, and databases within them,
' on the target server. 
' ------ SCRIPT CONFIGURATION ------
 strComputerName = "<serverName>" ' e.g., "batman"
' ------ END CONFIGURATION ---------
  
  set theServer = CreateObject("CDOEXM.ExchangeServer")
  Set theSG = CreateObject("CDOEXM.StorageGroup")
  Set thePF = CreateObject("CDOEXM.PublicStoreDB")
  Set theMB = CreateObject("CDOEXM.MailboxStoreDB")

  theServer.DataSource.Open strComputerName
  
  ' examine the SGs; for each SG, list its associated stores and paths
   For Each sg In theServer.StorageGroups
      WScript.Echo "Storage group " & Chr(34) & sg & Chr(34)
      theSG.DataSource.open sg
      i = 0
      For Each mailDB In theSG.MailboxStoreDBs
        i = i+1
        WScript.Echo "  Mailbox database " & i & ": " & mailDB
        theMB.DataSource.open mailDB
        WScript.Echo "                     Name:" & theMB.name
        WScript.Echo "                     Path:" & theMB.DBPath
      Next
      i = 0
     For Each pubDB In theSG.PublicStoreDBs
        i = i+1
        WScript.Echo "       PF database " & i & ": " & pubDB
        thePF.DataSource.open pubDB
        WScript.Echo "                     Name:" & thePF.Name
        WScript.Echo "                     Path:" & thePF.DBPath
      Next
   Next

Discussion

SGs have a variety of properties available through CDOEXM, including the names (both common and distinguished) of databases in the SG and the log and database file paths for the databases. You can view and set these properties by using code like that shown in the solution; however, you won’t be able to change the log or database file locations by changing the associated properties. Instead, you’ll have to use the MoveLogFiles() and MoveSystemFiles() methods (see Recipe 6.9).

See Also

Recipes Recipe 6.1 and Recipe 6.2 for creating and deleting storage groups and Recipe 6.9 for moving databases and log files; MSDN: IStorageGroup class documentation

6.4. Creating a Mailbox Database

Problem

You wish to create one or more additional mailbox databases in an existing storage group.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target storage group.

  4. Right-click the target storage group and choose New Mailbox Store.

  5. When the Properties dialog appears, enter a name for the database.

  6. Optionally, use the Database tab to select a location for the EDB and STM files.

  7. Optionally, use the Limits and Full-Text Indexing tabs to adjust properties on the database.

  8. Click OK.

  9. ESM will display a confirmation dialog to ask if you want the store mounted or not. Click Yes to mount the store or No to leave it dismounted.

Using VBScript

' This code creates a new mailbox database in the first storage group
' of the target server and then mounts it.
' ------ SCRIPT CONFIGURATION ------
 strServerName = "<serverName>"   ' e.g., "BATMAN"    
 strMDBName = "<databaseName>"    ' e.g., "SpiffyNewDatabase"
 ' ------ END CONFIGURATION ---------

Set theServer = CreateObject("CDOEXM.ExchangeServer")
Set theMDB = CreateObject("CDOEXM.MailboxStoreDB")

' bind to the Exchange server and build the database URL
theServer.DataSource.Open strServerName
arrSG = theServer.StorageGroups
theFirstSG = arrSG(0)

strURL = "LDAP://" & theServer.DirectoryServer & "/cn=" & _  
         strMDBName & "," & theFirstSG
wscript.echo "Creating database " & Chr(34) & strMDBName & _
         Chr(34) & " on " & theFirstSG
theMDB.Name = strMDBName
theMDB.DataSource.SaveTo strURL
WScript.Echo "Database created."
theMDB.Mount
WScript.Echo "Database mounted."

Discussion

When you create a new mailbox database, Exchange generates a new, empty EDB file and fills it with the structures necessary to contain mailbox data. It also generates a matching STM file, which is empty until you start moving or creating mailboxes in the new store. By default, newly created stores aren’t mounted; ESM will ask you if you want to mount the store, while you can use the Mount method on the mailbox store interface to mount a newly created store programmatically.

The previous VBScript example uses the CDOEXM MailboxStoreDB interface to create a new database in the first SG on the server. You can easily modify the code to create databases in a named SG by specifying the URL of the SG instead of looking up the first one. If you do not wish to mount the store, simply comment out the last two lines of the VBScript example.

See Also

Recipe 6.5 for creating a public store, Recipe 6.6 for deleting a database, Recipes Recipe 6.7 and Recipe 6.8 for mounting or dismounting a database, and MSDN: IMailboxStoreDB

6.5. Creating a Public Folder Database

Problem

You want to create an additional public folder database to host your applications.

Solution

Using a graphical user interface

To create an additional public folder hierarchy, do the following:

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Folders container.

  3. Right-click the Folders container and choose New Public Folder Tree.

  4. In the Properties dialog box, name the tree and click OK.

To create an additional public folder database, do the following:

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target storage group.

  4. Right-click the target storage group, then choose New Public Folder Store. (Note that ESM will complain if you haven’t already created an additional tree for the new store, but it will open the Properties dialog anyway.)

  5. Name the public folder store, then use the Browse button to associate it with a public folder tree.

  6. Optionally, use the Database tab to select a location for the EDB and STM files.

  7. Optionally, use the Limits and Full-Text Indexing tabs to adjust properties on the database.

  8. Optionally, use the Replication tab to set the replication schedule and limits for this public folder.

  9. Click OK. ESM will display a confirmation dialog to ask if you want the store mounted or not. Click Yes to mount the store or No to leave it unmounted.

Using VBScript

' This code creates an additional public folder tree and a database within it,
' then mounts the new database
' ------ SCRIPT CONFIGURATION ------
 strServerName = "<serverName>"    ' e.g., "BATMAN"    
 strPFDBName = "<newDBName>" ' e.g., "SpiffyNewPFDatabase01"
 strPFTreeName = "<newTreeName>" ' New PF Tree
 strAdminGroup = "<yourAdminGroupName>" ' e.g., "First Administrative Group"
 strOrgName = "<yourOrgName>"        ' e.g., "First Organization"
 strDomain = "dc=contoso,dc=local"
 ' ------ END CONFIGURATION ---------

Set theServer = CreateObject("CDOEXM.ExchangeServer")
Set theNewTree = CreateObject("CDOEXM.FolderTree")
Set theDSE =  GetObject("LDAP://RootDSE")
Set thePFDB = CreateObject("CDOEXM.PublicStoreDB")

' create the public tree. You could dynamically get the AG and org
' name but for simplicity we're defining them statically
strTreeURL = "LDAP://CN=" & strPFTreeName & ",CN=Folder Hierarchies" & _
   ",CN=" & strAdminGroup & ",CN=Administrative Groups,CN=" & strOrgName & _
   ",CN=Microsoft Exchange,CN=Services,CN=Configuration," & _
   theDSE.Get("defaultnamingcontext")
theNewTree.name = strPFTreeName 
theNewTree.DataSource.SaveTo strTreeURL
thePFDB.Name = strPFDBName
thePFDB.FolderTree = strTreeURL

' Get the first SG
theServer.DataSource.Open strServerName
arrSG = theServer.StorageGroups
  theFirstSG = sg
  Exit for
Next
' Create the URL to the new PF, then create and mount it
strPFURL = "LDAP://" & theServer.DirectoryServer & "/CN=" & strPFDBName & "," & _
           theFirstSG
thePFDB.DataSource.SaveTo strPFURL
thePFDB.Mount

Discussion

Exchange 2000 and 2003 support multiple public folder hierarchies (also known as top-level hierarchies (TLHs) or public folder trees). When you initially install Exchange 2000 or Exchange Server 2003 Server’s, you automatically get a TLH that’s accessible to MAPI clients; this is where user-accessible public folders are stored. There’s a catch, though: there can be only one TLH accessible to MAPI clients. Clients that use NNTP or the WebDAV extensions to HTTP can use non-MAPI TLHs, but you must first create at least one non-MAPI TLH before you can add more than one public folder store to a SG. If you don’t have a public store at all, when you create one, it’s automatically associated with the default MAPI TLH.

Using VBScript

The code creates a public folder tree in the Exchange organization’s Folder Hierarchies object by instantiating a new CDOEXM.FolderTree object and settings its URL to the specified name, along with the rest of the standard folder hierarchies’ tree name. Once the tree is created, the script locates the first SG and uses its URL as the base to create a new public folder database in the new tree.

See Also

Recipe 9.5 for forcing replication of a public folder hierarchy, Recipe 9.6 for getting properties of a public folder tree, Recipe 9.7 for creating and removing public folders, and MS KB 255077 (HOW TO: Create a New Public Folder Tree and Store in Exchange)

6.6. Deleting a Database

Problem

You need to remove a database you no longer need.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target database, then expand the parent SG.

  4. Right-click the target database and choose Delete.

  5. ESM will display a confirmation dialog to ask if you really want to delete the selected store. Click Yes to delete the store or No to leave it alone.

  6. ESM will display a dialog reminding you to remove the database files manually from disk. Click OK to dismiss this.

Using VBScript

' This code removes the specified mailbox database from its
' parent storage group without touching the on-disk files
' ------ SCRIPT CONFIGURATION ------
 strServerName = "<serverName>"    ' e.g., "BATMAN"    
 strMDBName = "<mdbName>"
 ' ------ END CONFIGURATION ---------

Set theServer = CreateObject("CDOEXM.ExchangeServer")
' To delete a public folder database here, just change this class ref 
' to CDOEXM.PublicStoreDB
Set theMDB = CreateObject("CDOEXM.MailboxStoreDB")

' bind to the Exchange server and build the database URL
theServer.DataSource.Open strServerName
arrSG = theServer.StorageGroups
theFirstSG = arrSG(0)

strURL = "LDAP://" & theServer.DirectoryServer & "/cn=" & strMDBName & "," & theFirstSG
theMDB.Name = strMDBName
theMDB.DataSource.Open strURL
theMDB.DataSource.Delete
WScript.Echo "Database deleted."

Discussion

When you delete a database file, you’re severing its relationship with its parent SG, as well as deleting the corresponding AD object. However, neither ESM nor CDOEXM removes the actual database files from the filesystem. This is a useful protective measure, since you can easily create a new database with the same name, dismount it, and replace its files with the original database files.

Using VBScript

The code in this script only works with mailbox databases because it uses the MailboxStoreDB object from CDOEXM. To make it work with public databases, you need to modify it to use the PublicStoreDB object instead. In either case, the code for deleting a database is similar to that used for creating a database; the difference is that you must bind to the MailboxStoreDB or PublicStoreDB object and use its Delete method to remove the database object instead of just instantiating the object and then using the SaveTo method.

See Also

Recipes Recipe 6.4 and Recipe 6.5 for creating mailbox and public folder databases

6.7. Mounting a Database

Problem

You need to mount a database so users can connect to it.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target database, then expand the parent SG.

  4. Right-click the target database and select Mount Store.

  5. When the store has been remounted, ESM will display a dialog telling you so; click OK to dismiss it.

Using VBScript

' This code mounts the specified mailbox database
' ------ SCRIPT CONFIGURATION ------
 strServerName = "<SERVERNAME>"   ' e.g., "BATMAN"    
 strMDBName = "<databaseName>"        ' e.g., "Mailbox Store (SpiffyDatabaseName)"
 ' ------ END CONFIGURATION ---------

Set theServer = CreateObject("CDOEXM.ExchangeServer")
Set theMDB = CreateObject("CDOEXM.MailboxStoreDB")

theServer.DataSource.Open strServerName
arrSG = theServer.StorageGroups
theFirstSG = arrSG(0)

strURL = "LDAP://" & theServer.DirectoryServer & "/cn=" & strMDBName & "," & theFirstSG
theMDB.DataSource.Open strURL
theMDB.Mount
WScript.Echo "Database mounted."

Discussion

You must mount a database before users can connect to it, or before you attempt to back it up using the ESE backup APIs discussed in Chapter 11. When you mount a database, ESE performs a quick integrity check on the database header; after the database is mounted, if there are pending transaction logs, they will be played back. This can affect the speed of mounting the database (although, interestingly, dismounting a database always takes roughly the same amount of time, no matter how large it is). If Store.exe is able to mount the database, it will post event 9523 to the application event log.

Using VBScript

The code only works with mailbox databases because it uses the MailboxStoreDB object from CDOEXM. To make it work with public databases, you need to modify it to use the PublicStoreDB object instead.

See Also

Recipe 6.8 for dismounting databases

6.8. Dismounting a Database

Problem

You need to dismount a database so you can perform maintenance or integrity checks on it.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target database, then expand the parent SG.

  4. Right-click the target database and select Dismount Store.

  5. ESM will ask you to confirm the dismount operation; click Yes.

Using VBScript

' This code will dismount the selected mailbox database. 
' ------ SCRIPT CONFIGURATION ------
 strServerName = "<serverName>"    ' e.g., "BATMAN"
 strMDBName = "<databaseName>"        ' e.g., "Mailbox Store (BATMAN)"
 ' ------ END CONFIGURATION ---------

Set theServer = CreateObject("CDOEXM.ExchangeServer")
Set theMDB = CreateObject("CDOEXM.MailboxStoreDB")

theServer.DataSource.Open strServerName
arrSG = theServer.StorageGroups
theFirstSG = arrSG(0)

strURL = "LDAP://" & theServer.DirectoryServer & "/cn=" & strMDBName & "," & theFirstSG
theMDB.DataSource.Open strURL
theMDB.Dismount
WScript.Echo "Database dismounted."

Discussion

Dismounting a database is simple, but it’s required before you copy the database files using anything other than the Exchange backup APIs. That’s because the dismount process sets a flag in the database header that indicates that the database was cleanly dismounted; if that flag is not there, Exchange will refuse to mount the database again until the header has been repaired with eseutil’s /r mode.

Using VBScript

The code only works with mailbox databases because it uses the MailboxStoreDB object from CDOEXM. To make it work with public databases, you need to modify it to use the PublicStoreDB object instead.

See Also

Recipe 6.7 for mounting databases, and Microsoft Technet article “Top 10 Database Mounting Issues and Their Solutions” (http://www.microsoft.com/technet/prodtechnol/exchange/2003/hd.mspx)

6.9. Moving Databases and Logs to Different Disks

Problem

You want to relocate the files for a database, or the transaction logs for a storage group, from one disk volume to another.

Solution

Using a graphical user interface

To move the EDB and/or STM files in a database, do the following:

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target database, then expand the parent SG.

  4. Right-click the mailbox or public folder store whose databases you wish to move, and select Properties.

  5. Switch to the Databases tab and use the Browse button to indicate a new location for the Exchange database, the streaming database, or both.

  6. Click OK to save the new locations. You will be prompted for confirmation, reminding you that the store will be dismounted, and asking you if you wish to continue. Click Yes.

  7. Once the Exchange and streaming databases have been moved and remounted, click OK.

  8. Make certain that the new file system location has the following access rights:

Administrators

Full Control

Authenticated Users

Read and Execute, List Folder Contents, Read

Creator Owner

None

Server Operators

Modify, Read and Execute, List Folder Contents, Read, Write

System

Full Control

To move a storage group’s logs to another volume, do the following:

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target SG.

  4. Right-click the SG whose transaction logs you wish to move and select Properties.

  5. On the General tab, click the Browse button to select a different disk or folder location for that SG’s transaction logs.

  6. Make certain that the new filesystem location has the following access rights:

Administrators

Full Control

Authenticated Users

Read and Execute, List Folder Contents, Read

Creator Owner

None

Server Operators

Modify, Read and Execute, List Folder Contents, Read, Write

System

Full Control

Using VBScript

To move a database to another path, use this code:

' This code moves database files to the specified path. 
' The database is dismounted and remounted as necessary.
' ------ SCRIPT CONFIGURATION ------
 strServerName = "<serverName>"    ' e.g., "BATMAN"    
 strMDBName = "<dbName>"        ' e.g., "Mailbox Database (SpiffyDatabaseName)"
 strNewPath = "<fullPath>"     ' e.g., "c:	emp"
 ' ------ END CONFIGURATION ---------
Set theServer = CreateObject("CDOEXM.ExchangeServer")
Set theMDB = CreateObject("CDOEXM.MailboxStoreDB")

theServer.DataSource.Open strServerName
arrSG = theServer.StorageGroups
theFirstSG = arrSG(0)

strURL = "LDAP://" & theServer.DirectoryServer & "/cn=" & strMDBName & "," & theFirstSG
theMDB.DataSource.Open strURL

' dismount the database before attempting to move it
If (theMDB.Status= 0) then
    theMDB.Dismount
End If

' move the DB to the specified path, then remount it
theMDB.MoveDataFiles strNewPath & strMDBName & ".edb", strNewPath & strMDBName & ".stm"
theMDB.Mount
WScript.Echo "Database moved to " & strNewPath & " and remounted."

If you want to move transaction logs for a storage group without touching the databases, use this code:

' This code moves transaction logs for the first storage group
' to the specified location
' ------ SCRIPT CONFIGURATION ------
strServerName = "<serverName>"    ' e.g., "BATMAN"    
strNewPath = "<fullPath>"         ' e.g., "c:	emp"
' ------ END CONFIGURATION ---------
Set theServer = CreateObject("CDOEXM.ExchangeServer")
Set theSG = CreateObject("CDOEXM.StorageGroup")

theServer.DataSource.Open strServerName
arrSG = theServer.StorageGroups
theFirstSG = arrSG(0)

strURL = "LDAP://" & theServer.DirectoryServer & "/" & theFirstSG
theSG.DataSource.Open strURL

' move the log files to the specified path; this dismounts and remounts
' all of the SG's databases
theSG.MoveLogFiles strNewPath
WScript.Echo "Moved logs for SG " & theFirstSG & "to " & strNewPath

Discussion

For best performance and recoverability, you should keep your Exchange transaction logs on a different physical disk or array than the Exchange database files. This gives the ability to have up-to-date logs to play back in the event of a database drive failure, allowing administrators to restore to the point of failure. The Exchange 5.5 Performance Wizard would attempt to figure out which disks to put its database (singular) and log files on, but Exchange 2000 and later dump everything in program filesexchsrvrmdbdata. You can, and should, relocate your databases and log files to enhance performance and recoverability. However, before you can move a database, it has to be dismounted; and before you can move the log files for a storage group, you’ll have to dismount all of its databases.

The scripts for this recipe use the CDOEXM interfaces for the MailboxStoreDB and StorageGroup objects to move databases and transaction logs. In both cases, the first SG’s URL is used as the basis for constructing the URL to the target SG or database. The database moving script dismounts the database if it’s mounted when the script is run, and mounts it after the move, because you cannot move a mounted database.

See Also

MS KB 821915 (How to Move Exchange Databases and Logs in Exchange Server 2003), MS KB 257184 (XADM: How to Move Exchange Databases and Logs in Exchange 2000 Server), and Exchange Server 2003 Performance and Scalability Guide (available from the Microsoft web site at http://www.microsoft.com/technet/prodtechnol/exchange/2003/library/perfscalguide.mspx)

6.10. Determining How Much Whitespace Is in a Database

Problem

You wish to determine how much available “whitespace” exists within a given database.

Solution

Using a graphical user interface

  1. Open the Event Viewer (eventvwr.msc).

  2. Click on the Application event log.

  3. Select View Filter.

  4. In the Event ID box, type 1221 and click OK.

  5. View the most recent occurrence of event 1221 for each mailbox or public folder store.

Using a command-line interface

  1. Dismount the database (see Recipe 6.8).

  2. Run the eseutil command with the /ms switch:

    > Exchsrvrineseutil.exe /ms pathToDatabaseFile 

    where pathToDatabaseFile is the location (including filename) of the file whose whitespace information you want.

  3. The output of the file dump mode will indicate the amount of database free space in kilobytes.

  4. Remount the database (see Recipe 6.7).

Discussion

Many administrators are keen to understand how much whitespace is contained in their Exchange databases. This space includes database pages that were once allocated but have been freed. In most cases, an EDB/STM file pair will grow steadily over time, but if you’ve done something to shrink the actual amount of mail data in the file pair (such as moving mailboxes to another server or purging old mail), there may be a substantial amount of disk space allocated to the file but unused by Exchange.

The amount of whitespace is especially important to know in Exchange Server Standard Edition when the database size is approaching the 16 GB limit. Unfortunately, there is no built-in utility to determine the amount of whitespace, so the simplest way to find this information is simply to look in the Application Event Viewer logs for event 1221, an informational event that is logged each night after scheduled online maintenance. Here’s a sample from one of our servers:

Event Type:    Information
Event Source:    MSExchangeIS Public Store
Event Category:    General 
Event ID:    1221
Date:        1/4/2005
Time:        3:15:00 AM
User:        N/A
Computer:BATMAN
Description:
The database "First Storage GroupPublic Folder Store (BATMAN)" 
has 1 megabytes of free space after online defragmentation has terminated.

If you run the command-line recipe, you will notice that it’s not always the same number as that reported with event 1221; eseutil.exe provides a more accurate estimate (at the cost of having to dismount your database).

See Also

Recipe 6.16 for defragmenting the database, and MS KB 186291 (XADM: Cannot Determine Free Space Available in Exchange Database)

6.11. Finding the Low Anchor Log File

Problem

You need to determine the anchor log file (i.e., the last consistent log file) to replay logs.

Solution

Using a command-line interface

  1. Dismount the store using the technique described in Recipe 6.8.

  2. Run eseutil to determine the low anchor log file:

    > pathExchsrvrineseutil.exe /mh path	odatabase.edb | find /I "consistent"

The output from this command will list the suffix of the last consistent log file, in decimal for Exchange 2000 and in hexadecimal for Exchange Server 2003. In the following output from Exchange Server 2003, the number 0x9 when appended to the default log file prefix indicates that the low anchor log file would be E0000009.LOG. To determine the log file prefix for Exchange 2000, first convert from the decimal output to hex.

  Last Consistent: (0x9,1D25,36)  09/20/2004 04:44:00

Discussion

If you have an offline backup that you wish to recover, and you want to replay transaction logs to restore up to the point of failure, you need to identify the low anchor log file. This is the first in the series of log files that must be replayed to restore all available transactions back into the Exchange database. You must ensure that you have all log files from the low anchor log file forward to the log file that contains the point-of-failure transactions (the high anchor log file). To know which log files you need to restore from your offline backup, you’ll need to be able to find the anchor log file; once you’ve done that, you can move on to restoring the offline backup, as described in Recipe 11.12.

See Also

Recipe 6.8 for dismounting the store, and MS KB 296788 (Offline Backup and Restoration Procedures for Exchange)

6.12. Rebuilding a Database File from Logs

Problem

One of your databases has become corrupt and you want to restore it using only the transaction log files.

Solution

Using a graphical user interface

  1. Ensure that you have all log files from E0000001.LOG through the anchor log. If you don’t have every log file created since the database was created (either because you lost one or because circular logging was on), you may have difficulty restoring the complete database contents.

  2. Move or rename the EDB and STM files for the target database. Don’t delete them; you may want to be able to return to them later.

  3. Move the CHK files from the transaction log path for the SG. As with the EDB and STM files, your best bet is to keep these in case you need them.

  4. Make sure the IS service is running, either by checking the Services control panel applet or looking in the application event log for event ID 1001.

  5. Mount the target database.

  6. The store will create new EDB and STM files with the appropriate name in the specified database location.

  7. Wait for the IS to finish replaying the transaction logs.

Discussion

If you have an unbroken chain of transaction log files and PRIV1.EDB becomes corrupt, you can quickly and accurately recover the data store by dismounting the database and removing (or renaming, which is much safer) the existing CHK, EDB and STM files. When you attempt to remount the database, the IS will create new, empty EDB and STM files, then it will begin sequentially playing back log files to restore the contents of these files.

Note that the anchor log isn’t relevant here; in order for Exchange to restore the contents of the database accurately, you’ll need all of the log files. There’s no way to tell Exchange “start with log file #5 and go forward from there”; in the case of an empty EDB and STM, the anchor log file will always be the first one. Because this approach requires you to have every log file created since the database was created, it’s pretty difficult to find circumstances where it makes sense. In most cases (and assuming a reasonable level of backup planning), it will be easier to fix the database by reloading it from a backup and playing back the needed transaction logs, as described in Recipe 11.4.

See Also

Recipe 11.4 for restoring a database, MS KB 278958 (How to Use Log Files to Rebuild the Priv1.edb File), and MS KB 296843 (How to recover an Exchange 2000 Server database after error -1216)

6.13. Enumerating Connected Mailboxes in a Database

Problem

You want to find out which mailboxes are in a specific mailbox database.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target database, then expand the parent SG.

  4. Expand the mailbox database whose contents you want to see.

  5. Select the Mailboxes node in the left pane of ESM. All mailboxes will be listed in the right pane.

  6. If you want to save the list of mailboxes to disk as either an ASCII or comma-separated value file, right-click the Mailboxes folder and select Export List, then specify where you want the file saved.

Using a command-line interface

The following command lists all the mailboxes in a mailbox store:

> dsquery * forestroot -scope subtree -filter "(homeMDB=<mailboxStoreDN>")

For example:

> dsquery * forestroot -scope subtree -filter "(homeMDB=CN=First Storage Group,
    CN=InformationStore,CN=BATMAN,CN=Servers, CN=First Administrative Group, 
    CN=Administrative Groups,CN=Robichaux and Associates, CN=Microsoft
    Exchange,CN=Services,CN=Configuration,DC=robichaux,DC=net)"

However, this query runs much faster on Windows Server 2003 Active Directory domains, because Windows Server 2003 can do implict indexing of multilinked values. If you’re using Windows 2000 Active Directory, you can get the same data (in a slightly different format) with a more efficient query that retrieves it from the linked attribute list on the mailbox store object. This query form looks a little different:

> dsquery * <mailboxStoreDN> -scope subtree -attr homeMDBBL

This uses the same mailbox DN path as the previous example.

Using VBScript

' This code finds all of the storage groups on a server. For each SG,
' it lists each mailbox database and the mailboxes contained therein. 
 ' ------ SCRIPT CONFIGURATION ------
 strBase = "<LDAP://serverName>;" ' e.g., "batman.robichaux.net"
 strComputerName = "<serverName>"     ' e.g., "batman"
' ------ END CONFIGURATION ---------
 
  set theServer = CreateObject("CDOEXM.ExchangeServer")
  Set theSG = CreateObject("CDOEXM.StorageGroup")
  Set theConn = CreateObject("ADODB.Connection")
  theConn.Open "Provider=ADsDSOObject;"
 
  theServer.DataSource.Open strComputerName
 
  ' examine the SGs; for each SG, iterate through its databases and
  ' list the mailboxes in it
   For Each sg In theServer.StorageGroups
      WScript.Echo "Storage group " & Chr(34) & sg & Chr(34)
      theSG.DataSource.open sg
      i = 0
      For Each mailDB In theSG.MailboxStoreDBs
        i = i+1
        WScript.Echo "  Mailbox database " & i & ": " & mailDB
        wscript.Echo "      Users: " 
        Set objRS = theConn.Execute(strBase & "(homeMDB=" & _
                                    mailDB & "); cn; subtree")
 
         objRS.MoveFirst
         While Not objRS.EOF
               wscript.echo "              " & objRS.Fields(0).Value
               objRS.MoveNext
         Wend   
         wscript.echo Chr(13) & Chr(13)    
      Next 
   Next
WScript.Echo "Done."

Discussion

Finding the mailboxes in a given database is simple, provided you know the DN of the mailbox database itself (which, in turn, is easy to get from the SG object, which is easy to get from the server object) By querying on the homeMDB attribute, you can select the subset of mailboxes in the database of interest. The script for this recipe takes this process up one level by iterating through all of the SGs on the server, then looping through each mailbox database in each SG and displaying the mailboxes that database contains. One caveat, though: a mailbox can exist in Active Directory, but until the user logs onto the mailbox or the mailbox is sent mail, it will not be created in the store.

See Also

Recipe 6.3 for listing the SGs on a server, and Recipes in Chapter 5 for working directly with mailboxes

6.14. Turning on Circular Logging for a Storage Group

Problem

You wish to enable circular logging for your Exchange Server transaction logs.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Expand the server that contains the target SG.

  4. Right-click the storage group and select Properties.

  5. Check the box labeled Enable Circular Logging.

  6. Click OK.

Using VBScript

' This code toggles circular logging for a storage group.
' ------ SCRIPT CONFIGURATION ------
 strServerName = "<SERVERNAME>"    ' e.g., "BATMAN"
  ' ------ END CONFIGURATION ---------

Set theServer = CreateObject("CDOEXM.ExchangeServer")
Set theSG = CreateObject("CDOEXM.StorageGroup")

theServer.DataSource.Open strServerName
arrSG = theServer.StorageGroups
theFirstSG = arrSG(0)

strURL = "LDAP://" & theServer.DirectoryServer & "/" & theFirstSG
theSG.DataSource.Open strURL
If (True = theSG.CircularLogging) Then
    wscript.echo "Circular logging is enabled; disabling it"
    theSG.CircularLogging = false
Else
    wscript.echo "Circular logging is disabled; enabling it"
    theSG.CircularLogging = true
End If
theSG.DataSource.Save
WScript.echo "Circular logging is now " & theSG.CircularLogging & " on SG " & theFirstSG

Discussion

Since a new log file is created whenever the current one fills up, log files can potentially take up a large amount of space on your disk. One solution is to put them on a dedicated disk set; another is to enable circular logging. Normally, every log file is kept until its transactions have been committed; the files are usually purged when online backups are made. When you enable circular logging, Exchange will keep a fixed number of log files, rolling from one to another as transactions arrive. The default number is four, but Exchange may use extra log files if a large set of transactions arrives. As the fourth log file fills up, Exchange will commit transactions from the first file; when the fourth file is completely full, all transactions will be flushed from the first file and it will be reused. However, since these additional log files are never deleted, a very busy server can still use more than the default 25 MB circular logging allocation.

Since circular logging overwrites transaction logs, it can be useful as a temporary space-saving measure on a drive or array that is running out of space. However, the cost is that since a full set of transaction logs don’t exist, up-to-the-minute log playback is not available in the case of media failure. I don’t recommend using circular logging on mailbox servers; however, on front-end, public folder replica, or SMTP servers, it’s often a sensible way to cap the amount of disk space used by those servers (recall that the SMTP service requires a mounted mailbox store to send NDRs for failed messages).

Toggling circular logging is easy, since it’s controlled by a single attribute on the SG. All the script does is set this attribute, then use the Save method to persist the change, which takes place immediately.

See Also

MS KB 147524 (How Circular Logging Affects the Use of Transaction Logs) and MS KB 258470 (XADM: How to Modify the Circular Logging Setting)

6.15. Controlling the Online Maintenance Process

Problem

You want to change the schedule for Exchange Server’s scheduled maintenance processes.

Solution

Using a graphical user interface

  1. Launch the Exchange System Manager (Exchange System Manager.msc).

  2. In the left pane, expand the appropriate Administrative Groups container, and then expand the Servers container.

  3. Locate the public folder or mailbox store for which you wish to control maintenance intervals.

  4. Right-click the store object and select Properties.

  5. Select the Database tab.

  6. Select one of the predefined Maintenance Intervals or click Customize to select your own schedule.

  7. Click OK.

Discussion

As with most other databases, the ESE holds on to space once it’s allocated and reuses it internally instead of returning it to the filesystem. For example, if you create 50 10 MB Word documents and delete 20 of them, you’ll regain 200 MB (20 * 10) of space. If your Exchange stores grow to 24 GB and you delete 1.5 GB worth of mailbox data, the stores will still take up 24 GB on disk, but Exchange will be able to recycle the 1.5 GB of free space within the database. The Exchange databases are like a balloon with a one-way valve attached—you can blow it up bigger and bigger, but it doesn’t normally get any smaller unless you do something purposeful to let some air out. Online maintenance performs several tasks to optimize the ways in which this whitespace is reused. These tasks include:

Defragmentation

Over time, your Exchange database files will become fragmented. This fragmentation is internal; as transactions occur, the contents of the database file itself are split into little islands of free space. Since the database must index each message component, along with the free space chunks, fragmentation slows down database performance. The more fragmented the store files become, the bigger the performance hit.

The IS automatically defragments its databases. This process, known as online defragmentation, is a scheduled maintenance task that runs nightly, or whenever else you schedule it. During an online defragmentation, the IS service shuffles data in the private and public databases to minimize fragmentation and keep mailbox and public folder stores in contiguous blocks wherever possible.

You can also use the eseutil tool to do an offline defragmentation, as described in Recipe Recipe 6.16. The difference is that during an offline defragmentation, the IS service must be stopped, and eseutil can do a more thorough job of defragmenting and recovering space. Offline defragmentations can actually shrink the size of the database files to match the actual size of the data in them; they return the unused space to the filesystem. Contrast this with online defragmentations, which move data around but don’t shrink the database size. The offline defragmentation process actually creates a temporary database and moves data from the original database to the new one, defragmenting and compacting as it goes. When the defragmentation is done, the new database replaces the old one.

The scheduled online defragmentation process will do its thing unobtrusively, and in most cases, you won’t need to run an offline defragmentation. However, there are times when you might want to force Exchange to defragment the database more thoroughly. For example, let’s say you’ve just moved two hundred users from one server to another, and you want to reclaim the space those two hundred mailboxes were taking up on the old server, instead of waiting for the private IS to grow into the space. You’ll need to run an offline defragmentation to regain the space.

Compaction

Exchange will automatically compact database entries, removing deleted items and periodically sweeping away expired public folders and views. This process is akin to opening a filing cabinet and removing any outdated or unnecessary files; it doesn’t increase the total amount of filing space, but it does increase the amount you can actually use. Exchange’s compaction process attempts to consolidate partially full pages into a smaller number of completely full pages. This consolidation speeds reading and writing to the database as transactions arrive.

Automatic maintenance tasks

Because the public and private stores are integral to Exchange’s operation, you probably won’t be surprised to see all the background maintenance tasks that take place. These tasks primarily do housekeeping, cleaning out expired data and flushing data from caches into the database. (We’ve already discussed the lazy commit system in the Introduction, which isn’t really a maintenance task anyway.) Tasks fall into two categories: those that run according to the schedule set on the Database tab of the server properties dialog box (see Table 6-1) and those that run either when Exchange needs them or when a separate schedule fires (see Table 6-2).

Table 6-1. Tasks that run during scheduled database maintenance

Task

When it runs

What it does

Index aging

Controlled by registry values described in MS KB 159197

Clients can create custom views, each of which is stored as an index in the database. Once these indices hit a certain age without being used, Exchange purges them to free up table space.

Tombstone aging

Every 24 hours

Deleted public folders and mailboxes are marked with a “tombstone.” This indicates that the marked item no longer exists and shouldn’t be replicated. After the tombstone reaches a certain age, it’s removed to keep the tombstone list from growing infinitely large.

Tombstone maintenance

Every 24 hours

This task compacts deleted items and replaces them with tombstones, which are then aged.

Public store expiration

Minimum of every 24 hours, unless overridden

Public folders may have a message age limit. Messages older than this limit are deleted as part of the maintenance process.

Public store version updates

Every 24 hours

Each server stores the version of Exchange that it’s running in its directory; this allows any two servers to agree on a common schema and feature set. Once per day, the IS maintenance task updates this version number to reflect any changes to Exchange.

Table 6-2. Other automatic maintenance tasks

Task

When it runs

What it does

Background cleanup

Controlled by the BackgroundCleanup registry values (see MS KB 159306)

Reclaims empty space formerly used by deleted items. Space is marked as unused and can be moved or reallocated by the compaction task.

Storage warning notification

Every four hours (by default), or using schedule you set

Checks each mailbox or public folder in a store, sending “you’re using too much storage” warnings to users who are over their assigned quotas.

Database grooming

Main task runs every 10 minutes; each grooming subtask has its own scheduled interval

Reloads and reapplies storage and per-user quotas from Active Directory and Exchange system policy objects.

Database compaction

Nightly at 1 a.m., unless changed

Moves all unused and reclaimed space to the end of the database.

See Also

Recipe 6.16 for adjusting the online maintenance schedule as part of shrinking the database, and MS KB 159306 (XADM: IS Maintenance Tasks Not on IS Schedule), MS KB 159197 (XADM: Controlling Folder Index Aging)

6.16. Performing an Offline Defragmentation

Problem

You want to reclaim whitespace from your Exchange database, so you need to take it offline and defragment it.

Solution

Using a command-line interface

  1. Dismount the Exchange Server database to be defragmented as described in Recipe 6.8.

  2. Open a command window (cmd.exe).

  3. Change to the directory where the database you want to defragment is located. This is optional, but it will save you some typing in the next steps.

  4. Run the eseutil utility to defragment the database:

    > eseutil /d /p "pathToDBFiledbName.edb"
  5. Wait. Database size and the amount and location of whitespace affect the time it takes to defragment it.

    • When defragmentation completes, remount the store as described in Recipe 6.7.

    • Use the recipes in Chapter 11 to make a full online backup. When you defragment the database, its database signature changes, so previous log files can’t be applied against the new EDB/STM pair.

Discussion

In normal operation, it is almost never necessary to defragment the database as it will simply grow again as more messages are sent and received. Some activities can return large amounts of space to the database whitespace pool. For example, moving large numbers of mailboxes off a server will mean that the space formerly used by those mailboxes is available; if you move enough mailboxes, this savings can be significant. To run an offline defragmentation, Microsoft recommends that you have 110% of the database size available as free disk space—for a 40 GB database, then, you should have at least 44 GB free.

Tip

It is neither necessary nor desirable to frequently perform offline defragmentations, and there is no need to use products that attempt to do this for you.

When you use eseutil’s /d option, it systematically scans through the EDB and STM files for the specific database, rearranging pages to make all of the tables, indices, folders, attachments, streamed objects, and messages contiguous. Normally, it does this by following a simple process:

  1. A new pair of temporary database files is created. You can specify the location and name of these files with the /t option (which isn’t followed by a space: /tG: empdefrag.edb is how you’d specify that you wanted to use g: empdefrag.edb as your temporary file). This option is useful if you don’t have enough space on the volume where the databases are now. It’s legal to use network-mapped drives (but not UNC paths) with /t, but beware the performance and bandwidth-consumption impact of the next two steps.

  2. eseutil scans the source database, organizing pages on the fly and writing them to the temporary file. As you would expect, this is what actually takes up the bulk of the time in the defrag process. You should probably expect this step to process 4-10 GB per hour, although that figure may vary depending on your server and disk configuration and what else your server is doing.

  3. When all pages in the database have been copied to the temporary file, eseutil copies the temporary file and overwrites the original. Once this step finishes, you can remount the database and use it normally.

Step 3 can take a significant amount of time, so you can instruct eseutil to skip it with the /p option. This forces eseutil not to copy the temporary file or overwrite the existing file; you’ll have to do that manually before you can mount the database. Alternatively, you can use the techniques in Recipe 6.9 to change the database paths to point to the newly defragmented file.

See Also

Recipe 6.9 for changing database and log file paths, Recipe 6.17 for shrinking an oversized Standard Edition database, Recipe 11.2 and Recipe 11.3 for completing a full online backup, MS KB 328804 (How to Defragment Exchange Databases), MS KB 192185 (How to defragment with the Eseutil utility [Eseutil.exe]), and MS KB 254132 (Eseutil /d defragments the database and the streaming file)

6.17. Shrinking a Database That Exceeds the 16 GB Size Limit for Standard Edition

Problem

You have the Standard Edition of Exchange 2000 or Exchange Server 2003, and your mailbox database has reached the 16 GB limit so it keeps dismounting.

Solution

Using a graphical user interface

  1. Open the Registry Editor (regedit.exe).

  2. Navigate to:

    HKEY_LOCAL_MACHINESYSTEMCurrentControlSetServicesMSExchangeIS

    Beneath that key, you’ll see a key with the name of your Exchange server; expand it.

  3. Under the Exchange server key, you’ll see a key whose name is comprised of the word “Private” plus a long hexadecimal number.

  4. Add a new REG_DWORD value named Temporary DB Size Limit Extension; give it a value of 1. This temporarily increases the size limit for the mailbox database to 17 GB.

  5. Optionally, stop the SMTP service to keep new mail from being delivered from the outside world and pushing your store over its new limit.

  6. Mount your mailbox store, as described in Recipe 6.7.

  7. Remove unneeded or unwanted data from the mailbox database. This usually involves emptying the Deleted Items folder and throwing away old mail, and it normally has to be done by your users. You can cheat and use the Mailboxes node in ESM to figure out which mailboxes are the largest and focus on cleaning them first. A better way to perform this sort of maintenance is to use the Mailbox Manager, discussed in Recipe 5.26.

  8. Open the Properties dialog box for the mailbox store and switch to the Limits tab.

  9. Enter 0 into the Keep deleted items for (days) field and click Apply.

  10. Switch to the Database tab, click the Customize button; modify the online maintenance schedule to start immediately (e.g., at the next available time period), and click OK (see Recipe 6.15).

  11. Wait for online maintenance to complete, as evidenced by the presence of event ID 1221 (see Recipe 6.10).

  12. Follow the steps in Recipe 6.16 to perform an offline defragmentation of the database.

Discussion

The standard version of Exchange has long had a 16 GB limit; the only real change between Exchange 5.5 and Exchange 2000 and Exchange Server 2003 is that the older version allowed you to have only one database, and the newer versions allow one SG with two databases: one private and one public, each limited to 16 GB. The simplest way to override the capacity limitations is to install the Enterprise version of Exchange over the existing version; this is a simple and nondestructive operation that follows the same process described in Recipe 2.12. Failing that, you can use the procedure above to temporarily increase the size limit to 17 GB, which buys you some time during which your users should clear out some of their old mail. Step 9 will force the store not to keep any previously deleted items in the deleted item retention pool, but they won’t actually be removed until the next time the online maintenance task runs. Once it runs, the store will purge all previously deleted items, and you’ll have back as much free space as you can get without defragmenting the database.

See Also

Recipe 2.14 for upgrading to the Enterprise edition of the same version of Exchange; Recipe 6.7 for remounting the mailbox database, Recipe Recipe 6.10 for determining when online maintenance has finished, Recipe 6.15 for controlling the online maintenance schedule, and MS KB 828070 (Exchange Server Mailbox Store Does Not Mount When the Mailbox Store Database Reaches the 16-GB Limit).

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.86.18