Trick: uidNumber Attribute Auto-Incrementing Method

The LDAP protocol has no way to auto-increment an integer value. This is necessary for Directory-enabled applications that need to create new users with an incremented, unique value. There can be a race condition if two applications try to increment the same value at the same time. If both applications read the value at the same time, they will both end up thinking that they have the same value.

With the Sun Directory Server, there is an “Attribute Uniqueness Plugin” which can be used to enforce attribute uniqueness over a container. However, this method is not recommended as it is very expensive and unnecessary if you use the “uidNext” method described in this article (see below).

There is a commonly accepted solution to this which works well. However, it must be coded into the applications due to the lack of auto-incrementing functionality in LDAP servers or LDAP client libraries. This article will discuss how to use the “Atomic uidNext Auto-increment Method”. We will assume that the requirement is to automatically increment uidNumber, but this method could be used for any number that needs to be automatically incremented.

“Atomic uidNext Auto-increment Method” Basic Steps

  1. Create a new objectClass “uidNext”. Here is an example of what you might use:
    objectclass ( 1.3.6.1.4.1.19173.2.2.2.8
      NAME 'uidNext'
      DESC 'Where we get the next uidNumber from'
      MUST ( cn $ uidNumber ) )
  2. Create a “uidNext” entry (objectClass: uidNext) at an specific location in the directory to store the incrementing value. Publish this location in your application programming guides as the well-known location for obtaining the next UID. Also publish this method as the required method to retrieve a next UID.
  3. When an application needs the next UID, it can use this “uidNext” entry to find the next uid value in the DIT – use the specified spot in the DIT to store a “uidNext” value.
    • Use “search” to find the current value of “uidNext”.
    • Programmatically construct the LDAP operation so that we have a “delete (specific attribute) +add attribute” modification, not a “modify attribute” modification.
    • The entire delete +add operation is atomic, meaning, the whole thing succeeds or it fails. By getting either an “operation success” or “operation fail”, you have avoided the race condition. If the delete fails, the add fails too, hence the entire modification fails. No two applications can modify uidNext at the same time.
    • If the “delete+add” operation succeeds, you can use the value.
    • If the “delete+add” operation fails, the application can back off and try again.
    • NOTE: In the “delete” the value should be specified. In LDAP you can specify an attribute only or an attribute:value pair for a deletion. It important to use the attribute:value delete here, to make sure that no one else has beat you to taking and updating the UID that you just searched and are planning to use/increment.
  4. Why this works so well is built into the protocol. According to RFC 2251 Section 4.6:“Note that due to the requirement for atomicity in applying the list of modifications in the Modify Request, the client may expect that no modifications of the DIT have been performed if the Modify Response received indicates any sort of error, and that all requested modifications have been performed if the Modify Response indicates successful completion of the Modify Operation. If the connection fails, whether the modification occurred or not is indeterminate.”

UidNext ObjectClass and Entry

  • Create a uidNext objectclass– This objectClass is used to store the next PID.objectClasses: ( uidNext-oid
    NAME ‘uidNext’
    SUP top
    STRUCTURAL
    MUST ( cn $ uidNumber ))
  • Create the cn=uidNext,dc=rexconsulting,dc=net entry. This is the entry in the DIT where we store the next value.dn: cn=uidNext,dc=rexconsulting,dc=net
    objectClass: uidNext
    cn: uidNext
    uidNumber: (this is where the next value goes)

Pseudocode for Automatically Incrementing uidNumber

  • Step 1. Read the uidNext value from cn=uidNext,dc=rexconsulting,dc=net.
  • Step 2. Submit one LDAP operation with two modifications:
    1. Delete the specific value read from Step 1 from the uidNext attribute of entry cn=uidNext,dc=rexconsulting,dc=net.
    2. Add the next uidNext value to cn=uidNext,dc=rexconsulting,dc=net.

    NOTE: Specify the read value from step 1 when in your “delete” so it only fails if no one else runs this operation quicker than you!!! If the deletion of the specific value you read in step 1 fails, then you know some one else changed the value before you did.

    Here is an LDIF of the operation:

    dn: cn=uidNext,dc=rexconsulting,dc=net
    changetype: modify
    delete: uidNumber
    uidNumber: 1

    add: uidNumber
    uidNumber: 2

  • Step 3.
    1. If you get an Operation Failed (error 16: “No Such Attribute”), it is because someone else got the number already. Try again.
    2. If you get an Operation Succeeded (error 0), you can safely use the old value from Step 2(a) for your new entry’s uidNumber value.

Performance Considerations when Using the Sun Directory Server Attribute Uniqueness Plugin

There are several severe performance hits when using the Sun Directory Server Attribute Uniqueness Plugin in a Multi-Master Replication topology. (See http://docs.sun.com/source/816-6400-10/attruniq.html#wp19648). Because of this, you should not use the Sun Directory Server Attribute Uniqueness Plugin unless you have a good reason to.

  • Requires Stable Topology – cannot promote/demote masters with attribute uniqueness plugin enabled.1
  • Directory Modification Unavailable at Startup – When the attribute value uniqueness plug-in is first enabled, the network of plug-ins must create the table of values for each monitored attribute. Hashing all values of all attributes being monitored for uniqueness and distributing those values requires some time at initialization. During this time, the server will refuse modify operations.2
  • Severe Modify Performance Degradation – Enforcing attribute value uniqueness in a multi-master topology involves additional communication between servers. Before any update operation can be allowed to proceed, the network of plug-ins must determine if the new value of a given attribute is already used on any of the other masters. The plug-in architecture optimizes this verification procedure, but it may still lead to measurable overhead on update operations. Client operation is blocked during this time.3
  • Single Point of Failure – If one server goes down, modifications will fail since uniqueness cannot be enforced. You can configure this to just log errors and continue to avoid, so the application can proceed.

© Copyright 2018 Rex Consulting, Inc. - All rights reserved

From an early age, Chris Paul moved frequently because his dad was in the US Air Force. Born in Germany, then moved to Alabama, then Maryland, then Naples, Italy, then California since high school, with many Christmas seasons spent in Pittsburgh, PA, the home of his grandparents.

3 responses to “Trick: uidNumber Attribute Auto-Incrementing Method”

  1. Hi,
    Thank you very much for your post.
    It was very useful.

    I Just had to make a change from your version, as I couldn’t delete the uidNumber

    This was giving error:

    dn: cn=uidNext,dc=rexconsulting,dc=net
    changetype: modify
    delete: uidNumber
    uidNumber: 1

    Creating the objectClass with MUST ( cn $ uidNumber ) made impossible to delete the attribute.

    I changed it to MAY , and now it works for me.

    I suppose it’s a good way too.

    Thanks a lot

    • Hi Maddish,

      Thanks for your feedback. This may be implementation specific. What LDAP server software/version are you using?
      I see the logic in what you say – how could it allow the delete if it’s MUST? I just checked and MUST works in my schema with openldap-2.4.31. I think that the “MUST” works because it’s just one “atomic” transaction. This is the way I look at it though, a different type of logic: If you combine a delete with an add in one operation, the schema is not violated because the attribute is empty for 0 seconds in an atomic transaction.

      The thing to remember here is that this operation is a delete+add, not a delete. See, only one “changetype”, so only one operation. Here is the successful operation I just tested:

      dn: cn=uidNext,dc=lab,dc=rex,dc=net
      changetype: modify
      delete: uidNumber
      uidNumber: 51525

      add: uidNumber
      uidNumber: 51526

      So I think you forgot to include the “add” along with the delete in the same operation. Or you are using a different implementation with different behavior. I have seen how schema can be implemented differently by different vendors and version.

  2. I understand.

    Sorry, I’m not familiar with ldap.

    The thing is that actually I’m using your idea in a php application, and as far as I know it’s not possible to do it atomically.
    That’s why I decided to split it into two different functions , first delete end then add.

    Your solution is better. I’ll dig to find out if php has some way to do it

    Thanks a lot

Leave a Reply

Your email address will not be published. Required fields are marked *