ADSI Schema Mapping Mechanism
In the previous section, we discussed the various LDAP syntaxes and showed how they map into the various data types. We also know that ADSI will map each LDAP attribute to an appropriate ADSI data type and COM data type. So, how does ADSI know the syntaxes of all of the LDAP attributes so that it knows the proper data type mappings? Given that LDAP schemas are extensible and can thus be completely unique, this obviously must be done dynamically.
To make this work, ADSI takes advantage of the fact that LDAP version 3 requires that each directory expose its schema in a special abstract form via a specific object in the directory. The abstract schema, an object of type subSchema, describes each attribute in the directory and its syntax (among many other things). The object's location is published in a DN-syntax attribute called subschemaSubentry, on the RootDSE object.
To create a schema mapping for a given directory, ADSI first reads RootDSE to find the abstract schema, and then reads the abstract schema to create a mapping in memory for that directory. From there, ADSI can create an appropriate ADSI or COM mapping for any attribute it reads or writes. The schema for each directory is read only once for a given process the first time that directory is accessed.
Schema Caching
If you've ever looked at the aggregate schema object for an LDAP directory with a large schema, like Active Directory, you may have noticed that it is pretty large. There is a definite performance penalty for reading all of this data over the network each time a directory is accessed, especially in short-lived processes like scripts. To make things faster, ADSI will attempt to cache the schema locally on the filesystem so that the abstract schema can be read from disk.
Here is how it works. The first time ADSI encounters an LDAP version 3 directory, it will
- Find the abstract schema for a directory by reading the subschemaSubentry in RootDSE.
- Read the abstract schema data from the subSchema object, including the modifyTimeStamp attribute.
- Create an in-memory model of the LDAP to ADSI and COM schema map.
- Try to write the schema data to the filesystem in the SchCache directory.
- Try to create a registry key with the name matching the DN of the subschemaSubentry object in HKLM/Software/Microsoft/ADs/Providers/LDAP, which contains values pointing to the schema file and holding the modifyTimeStamp of the object.
On a subsequent visit to the same directory, ADSI will once again access the RootDSE object and find the subschemaSubentry object.
- It then checks the registry in HKLM/Software/Microsoft/ADs/Providers/LDAP to see if a key exists that matches the DN value of the subschemaSubentry for the RootDSE object.
- If the key exists, it checks to see if the value for the file exists and if the file is on disk.
- If the file exists, it then reads the modifyTimeStamp attribute from the subSchema object.
- If the modifyTimeStamp is the same as or older than the value stored in the registry, the schema is read from the filesystem rather than the network. This is where the major performance improvement comes from, as the abstract schema can easily be 1.5MB of data on a 2003 Active Directory with the Exchange Server 2003 schema loaded.
- If the modifyTimeStamp on the subSchema object is newer than the one recorded in the registry, then the newer schema is downloaded and used, with the new data being recorded to disk and the new timestamp recorded to the registry, as explained earlier.
[a] In more-recent versions of ADSI, if a connection using different credentials accesses a directory and sees that the schema cache for that directory is in the default mode, it will attempt to download the schema again using the new credentials.