SharePoint has what is known as the Configuration Cache. Sometimes we get recommendations to clear it, especially when timer jobs don’t appear to be operating properly. But what exactly is the Configuration Cache and how does it function?
The Configuration Cache exists on each SharePoint server joined to the farm, regardless of role. The cache is sorted at C:\ProgramData\Microsoft\SharePoint\Config\<GUID>\ and consists of often thousands of XML files and a single cache.ini file.
The XML files are simply farm objects from the SharePoint Configuration database within the Objects table. For example, take this file, 7fb0b296-fae7-45bd-88fc-9a4a4e69b484.xml. If we look at the internals of the file, it is simply an object! In this particular case, it is the User Profile Import Job.
<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
<PersistedObject id="7fb0b296-fae7-45bd-88fc-9a4a4e69b484" parentId="cb87c186-60f2-4131-8fd5-a02ec8ad20d5" classId="e4744cf9-44c4-4b6c-b30a-ad0996b08528" name="User_x0020_Profile_x0020_Service_x0020_Application_ProfileImportJob" status="0" version="739330">
<object type="Microsoft.Office.Server.UserProfiles.UserProfileImportJob, Microsoft.Office.Server.UserProfiles, Version=188.8.131.52, Culture=neutral, PublicKeyToken=71e9bce111e9429c"><sFld type="Int32" name="maxStepRetryCount">3</sFld><sFld type="Int32" name="keepHistoryInterval">90</sFld><sFld type="Boolean" name="runOnceAsFullSync">False</sFld><fld type="Microsoft.Office.Server.UserProfiles.StringSet, Microsoft.Office.Server.UserProfiles, Version=184.108.40.206, Culture=neutral, PublicKeyToken=71e9bce111e9429c" name="runAsFullImport" /><fld type="Microsoft.Office.Server.UserProfiles.StringSet, Microsoft.Office.Server.UserProfiles, Version=220.127.116.11, Culture=neutral, PublicKeyToken=71e9bce111e9429c" name="runAsFullSync" /><fld type="System.Collections.Generic.List`1[[Microsoft.Office.Server.UserProfiles.SynchronizationRunStatus, Microsoft.Office.Server.UserProfiles, Version=18.104.22.168, Culture=neutral, PublicKeyToken=71e9bce111e9429c]], mscorlib, Version=22.214.171.124, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="syncRuns" /><sFld type="DateTime" name="lastStatusUpdate">2014-02-06T19:42:19</sFld><sFld type="Boolean" name="lastRunFailed">True</sFld><sFld type="Guid" name="m_UserProfileApplicationId">5884b821-b739-4099-ba47-55c31b64f351</sFld><fld name="m_Data" type="null" /><fld name="m_Server" type="null" /><sFld type="Guid" name="m_OriginatingServerId">993a8add-12f5-46cc-bd37-e95650344185</sFld><sFld type="Boolean" name="m_skipOriginatingServer">False</sFld><fld type="Microsoft.SharePoint.Administration.SPJobLockType, Microsoft.SharePoint, Version=126.96.36.199, Culture=neutral, PublicKeyToken=71e9bce111e9429c" name="m_LockType">Job</fld><sFld type="String" name="m_Recurrence">daily between 01:00:00 and 01:00:00</sFld><sFld type="DateTime" name="m_OneTimeOccurrence">0001-01-01T00:00:00</sFld><sFld type="String" name="m_Title"></sFld><sFld type="Int32" name="m_Flags">0</sFld><sFld type="DateTime" name="m_runNowTime">2014-02-06T19:43:00</sFld><sFld type="Boolean" name="m_verboseTracingEnabled">False</sFld><fld type="System.Collections.Hashtable, mscorlib, Version=188.8.131.52, Culture=neutral, PublicKeyToken=b77a5c561934e089" name="m_UpgradedPersistedFields" /><fld name="m_Properties" type="null" /><sFld type="String" name="m_LastUpdatedUser">NAUPLIUS\s-sp2013farm</sFld><sFld type="String" name="m_LastUpdatedProcess">OWSTIMER (3716)</sFld><sFld type="String" name="m_LastUpdatedMachine">SP2013</sFld><sFld type="DateTime" name="m_LastUpdatedTime">2014-02-06T11:43:00</sFld></object>
The XML file name matches the ID column in the Objects table, as well as the Persisted Object ID.
From clearing the Configuration Cache, we know that cache.ini is involved in this process. It must exist, and it must have a numeral value contained within it (1 or higher). The cache.ini file closely mirrors the number contained within the Configuration database’s LastUpdate table. This table contains two columns, a Value column and a Version column. The Version column increments on a regular basis, and the cache.ini updates from the Version value. To accomplish this, there is a local Timer Job on each server with the internal name of “job-config-refresh”. This timer job runs on a 15 second interval. The timer job itself validates that the cache.ini has not been invalidated, then runs the stored procedure within the Configuration database, proc_getNewObjects. If the value in the cache.ini file is less than the value contained in the LastUpdate table, a SELECT statement is run against the Objects table where the value within the LastUpdate table is less than the value of the Version column in the Objects table; it also tombstones objects in the Tombstone table.
From there, the timer job compares the objects on the file system in the Config folder with the newest returned versions of the objects. Expired objects (files) are deleted, and new or updated objects (files) are written to the Config folder.
Now, as for how the value of the Version column is updated in the LastUpdate table? Within the Objects table there is also a column named Version. This is a timestamp column, which means the value is unique within the database (and doesn’t actually have anything to do with a date or time, it is just an incremental binary number). This data type is automatically incremented when the row has changed (or is inserted, etc.). When SharePoint makes a change to a row in the Objects table via the stored procedure proc_pubObjectTVP, that particular object has it’s Version column updated automatically. In addition, there is a SQL Trigger on the Objects table named trigger_OnTouchObjects. What this trigger does is simply update the value of the Value column in the LastUpdate table to 0 (the single row in this table always has a value of 0 for the Value column). By doing this, the Version column within the LastUpdate table is automatically updated, as it is also a timestamp column! And for a bonus, since the timestamp column is unique in the database, the LastUpdate Version column will always be one greater than the last Object updated!
This will also explain why you may encounter the Concurrency Update exceptions from either PowerShell or commonly, the Configuration Wizard. A service has updated an object which then updates the Version of the object as well as the LastUpdate Version column, thus when attempting to execute against that “old” object, it is no longer valid and must be manually refreshed.
Hopefully this helps demystify the Configuration Cache, what it does, and how it is associated with the Configuration database!