13 Optimizing Concurrent Resource Allocation

This chapter provides information about optimizing Oracle Communications Unified Inventory Management (UIM) concurrent resource allocation. The information describes the use of row locking to optimize concurrent resource allocation for consumable entities, and how you can extend additional entities to use row locking in your UIM environment. For example, if your UIM environment heavily uses party entities, you can extend UIM to have party entities use row locking to optimize concurrent resource allocation of party entities.

About Concurrent Resource Allocation

Concurrent resource allocation occurs when multiple clients simultaneously select the same resource from the same resource pool and then try to reserve or assign that resource.

The inherent problem with concurrent resource allocation is that only one of the clients can assign the resource; the other clients fail and must re-try the operation. When the client re-tries the operation, the resources are queried a second time, and again only one client succeeds. As this scenario unfolds, new clients may query the same resource pool. Multiple clients simultaneously selecting from the same resource pool, failing to reserve or assign a resource, and re-trying the operation can continue indefinitely, causing performance issues.

For example, when two clients simultaneously search by ZIP code for an available telephone number to assign, the search results can return the same telephone number to both clients. If both clients try to assign the same telephone number, one client succeeds, and one client fails. The client that fails must re-run the search to get a new set of available telephone numbers from which to assign.

In most UIM environments, telephone number entities are heavily used. Due to this, telephone number entities use row locking to optimize concurrent resource allocation for assigning and reserving telephone numbers. See "About Row Locking" for more information.

About Row Locking

This section builds upon the information presented in Chapter 4, "Extending the Data Model".

Row locking is a capability, which is a design pattern that is applied to an entity. A capability is declared in the metadata using tags, and results in the generation of attributes and related entities that are not explicitly defined in the *-entities.xml or *-types.xsd metadata files. See "About Entity Capabilities" and "Understanding Entity Capability Definitions" for more information.

The row locking capability is declared for a UIM entity in the metadata files using the RowLockEnabled tag. The row locking capability declaration results in the generation of the EntityNameRowLock entity, where EntityName is the name of an entity. Row locking is enabled and used through UIM functionality, which processes entities with row locking capabilities differently than entities without row locking capabilities.

The following example shows the RowLockEnabled tag as declared for the TelephoneNumber entity:

                <rowLockEnabled prefix="TelephoneNumber"/>    
 

In this example, the RowLockEnabled tag as declared for the TelephoneNumber entity results in the generation of the TelephoneNumberRowLock entity.

Upon UIM installation, all consumable entities have row locking capability and use row locking through UIM. For example, TelephoneNumber, Equipment, IPAddress, and so forth. (Being a consumable entity is also a capability that is declared in the metadata files.)

You can statically extend additional entities to declare the row locking capability through the metadata files, and enable and use row locking on these entities through custom code.

When row locking is in place for an entity and an entity finder API called, lock policy details may be provided to the entity finder API. If lock policy details are provided, selected entity rows are locked. If no lock policy details are provided, selected entities are returned to the client with no row locks on them.

For example, when two clients simultaneously search by ZIP code for an available telephone number to reserve or assign, the search results do not return the same telephone number to both clients because each telephone number entity that meets the search criteria is locked prior to returning the search results. The locking is achieved by updating the TelephoneNumberRowLock table with the telephone numbers returned in the search. If a telephone number is already present in the TelephoneNumberRowLock table, the telephone number is filtered from the search results prior to returning the search results to the client. When telephone number locks are released, the telephone numbers are removed from the TelephoneNumberRowLock table.

Row locking removes the potential of the same telephone number being returned to both clients. If the same number is not returned to both clients, the same number cannot be selected by both clients, which eliminates the possibility of one client failing to assign the telephone number.

Row locking is applied by setting the appropriate LockPolicy values during the search. See "About the LockPolicy Object" for more information.

Note:

Implementing row locking as described here achieves the same result as database row-locking. However, traditional database row-locking is not used.

Understanding How Row Locking Works

This section uses the TelephoneNumber entity as an example to provide an understanding of how row locking works.

In UIM, TelephoneNumber entities are used for resource reservation and resource assignment. Upon UIM installation, the TelephoneNumber entity declares the row locking capability through the entity definition in the metadata. UIM search logic performs row-locking operations based on the lock policy details provided to the search.

For example, when the entity finder API is called to find telephone numbers for resource reservation, the entity finder API logic row-locks the telephone numbers.If the row-lock operation is successful, telephone numbers are reserved and the row-locks are released. If the row-lock operation fails (row-locks for all the telephone numbers are not obtained), an error message displays and no attempt is made to reserve the telephone numbers.

Similarly, when the entity finder API is called to find telephone numbers for resource assignment, the entity finder API logic row-locks the telephone numbers. If the row-lock operation is successful, telephone numbers are assigned to a configuration item and the row-locks are released. If the row-lock operation fails (row-locks for all the telephone numbers are not obtained), an error message displays and no attempt is made to assign the telephone numbers.

The RowLock capability is statically declared for an entity in the metadata. Additionally, a LockPolicy object is used in the entity search criteria. When searching for entities, such as telephone numbers or logical devices, the entities returned in the search results are locked based on the details specified in the LockPolicy object. In this manner, concurrent resource allocation attempts return different sets of entities.

About Releasing Locked Rows

Locked rows are released in the following ways:

  • When an entity finder API is called with a LockPolicy, the entity finder API logic calls a method at the end of the operation that releases the locks.

  • A timer listener automatically releases row-locked entities at specified intervals.

  • A database administrator can manually release row-locked entities.

About the LockPolicy Object

The LockPolicy object defines the attributes listed in Table 13-1. LockPolicy attribute values are set as part of the search criteria, which is passed to the entity finder API, and which affects the search behavior.

Table 13-1 LockPolicy Attributes

Attribute Data Type Default Value

numberOfResources

long

0

expirationTimeStamp

Date or int

Value specified for the lockPolicy.defaultRowLockExpirationDuration property in the system-config.properties file.

filterExistingLocks

boolean

false


numberOfResources

The numberOfResources value tells the entity finder API the number of entity rows to lock. For example, when a value of zero is specified, no entity rows are locked; when a value greater than zero is specified, the number of entity rows specified by the value are locked.

If the search criteria specifies a range, and the numberOfResources value is greater than zero, the entity finder API ignores the range and returns the number of entities specified by the numberOfResources value. For example, if the range specifies 0-20 and the numberOfResources values specifies 50, 50 entities are returned. This occurs because the find-by-range feature is disabled when row locking is used when calling and entity finder API.

expirationTimeStamp

The expirationTimeStamp value is used by the entity finder API when creating the locked row. The expirationTimeStamp value can be set as a date or as a duration. When the value is a date, the value is used to set the lock expiration date and time. When the value is a duration, the value is added to the current timestamp to calculate the lock expiration date and time.

filterExistingLocks

The filterExistingLocks value indicates whether or not the entity finder API filters out existing locked entities from the search result. When the value is true, existing locks are not included in the search results. When the value is false, existing locks are included in the search results. When a client search results are for view-only purposes, the value must be false.

Example LockPolicy Attribute Combinations

The entity finder API finds entities based on the specified search criteria and lock policy. Table 13-2 summarizes the different LockPolicy attribute value combinations and the affect each has on the entity finder API search results.

When numberOfResources is zero, the expirationTimeStamp value is not applicable because if no locks are applied, there is no need to set when the locks expire. When numberOfResources is greater than zero, the expirationTimeStamp value does not affect the outcome. As a result, the expirationTimeStamp attribute is not included in the table.

Table 13-2 LockPolicy Attribute Combination Outcomes

numberOfResources filterExistingLocks Entity Finder API Search Results

0

true

The search results exclude row-locked entities. From the search results, no entities are locked. The search results are returned to the client.

0

false

The search results include row-locked entities. From the search results, no entities are locked. The search results are returned to the client.

n

true

The search results exclude row-locked entities. From the search results, n entities are locked, time stamped, and returned to the client.

n

false

The search results include row-locked entities. From the results, n entities are locked, time stamped, and returned to the client.


About the Lock Strategies

The LockStrategy object utilizes the LockPolicy object when a lock of resources is requested. UIM provides the following lock strategies:

  • The Random Range Locking Strategy selects the range of resources to be locked randomly. The start range is determined using a thread-based local random value. This allows the concurrent threads to look at different resources so that collisions are avoided.

  • The Extended Range Locking Strategy executes the concurrent threads with the same range; however, the range is widened by a multiplier so that collisions are avoided. For example, if the client code requires 10 resources, this strategy looks at 1-100 resources assuming the range multiplier is 10.

  • The No Range Locking Strategy is a strategy where no range is applied. This strategy continues until the required number of locks are obtained. You can use this in cases where the ordering or resources to be consumed is critical to the scenario.

You choose the lock strategy by specifying the value in the locking policy properties file named locking-policy.properties. You can also define a custom lock strategy. The valid values are:

  • RandomRangeLocking

  • ExtendedRangeLocking

  • NoRangeLocking

  • Custom

For example:

lockpolicy.processing.strategy=RandomRangeLocking

Table 13-3 lists the locking properties.

Table 13-3 Locking Property Settings

Property Default Value Description

lockpolicy.processing.strategy

NoRangeLocking

This property defines the desired locking strategy. The valid UIM strategy values are RandomRangeLocking, ExtendedRangeLocking, and NoRangeLocking. The value of Custom is also valid. If Custom is given then you must provide the class name in the lockpolicy.custom.strategy.class property.

lockpolicy.custom.strategy.class

n/a

This property defines the custom Java class name of the strategy. You only give this property a value if the lockpolicy.processing.strategy property is set to the Custom.


In addition to setting the locking strategy in the property file, the following method can be used for a particular scenario.

lockpolicy.setLockingStrategy();

Use this method only if you need a locking strategy other than the one defined in the property file.

Extending UIM Entities to Use Row Locking

Extending UIM entities to use row locking involves:

Statically Extending the Data Model

This section builds upon the information presented in Chapter 4, "Extending the Data Model".

To statically extend the data model.

  1. Open Oracle Communications Design Studio.

  2. Import the UIM_Home/cartridges/tools/ora_uim_entity_sdk_cartproj.zip file.

  3. Create a new uim-*-entities.xml file in the ora_uim_entity_sdk/src directory.

  4. Open the existing *-entities.xml file that contains the entity definition you plan to extend.

  5. Copy and paste the entity definition you plan to extend from the existing file to your new file.

  6. Add the EntityRowLock tag to the entity definition.

    Example 13-1 is an excerpt from the uim-number-entities.xml metadata file that shows the TelephoneNumber entity definition, which declares the row locking capability.

    Example 13-1 uim-number-entities.xml

            <entity type="ocim:TelephoneNumber" managedBy="oracle.communications.inventory.api.number.TelephoneNumberManager">
        .
        .
        . 
                        <!-- **************** Capabilities ******************-->
                        <rowLockEnabled prefix="TelephoneNumber"/>      
            </entity>
      
    

    Example 13-2 shows what you would need to add to the uim-party-entities.xml metadata file to extend the Party entity to declare the row locking capability.

    Example 13-2 uim-party-entities.xml

            <entity type="ocim:Party" managedBy="oracle.communications.inventory.api.number.PartyManager">
        .
        .
        . 
                        <!-- **************** Capabilities ******************-->
                        <rowLockEnabled prefix="Party"/>        
            </entity>
     
    
  7. Generate the data model to include any newly declared entity row lock capabilities. See "Generating, Compiling, and Packaging the Entity Source Files" for more information.

Enabling Row Locking

To enable row locking:

  1. Configure the timer.properties file so the default RowLockExpiryTimerListener class is called at regular intervals by defining the firstTime and period properties, as shown in Example 13-3.

    Example 13-3 timer.properties File

    # Timer to cleanup the expired entity row locks
    rowLockExpiration.firstTime=120
    rowLockExpiration.period=600
    rowLockExpiration.listener=oracle.communications.inventory.api.common.impl.RowLockExpiryTimerListener
    

    Note:

    Do not change the rowLockExpiration.listener property. The default RowLockExpiryTimerListener class clears out expired locks for all entities with row locking capability, including any entities you extend to have the capability.
  2. Configure the system-config.properties file to set the default values for the defaultRowLockExpirationDuration and maxSupportedRowLocks properties, as shown in Example 13-4.

    Example 13-4 system.config.properties File

    # The default row locks expiration duration in milliseconds for the entity. 
    # This value should be defined to be less than the transaction time out.
    lockPolicy.defaultRowLockExpirationDuration=30000
    
    # Default maximum number of entities to be row locked. 
    # This should be in sync with the maximum number or range.
    lockPolicy.MaxSupportedRowLocks=100
    

Using Row Locking with Entity Finder APIs

You can write custom code to use row locking with entity finder APIs for any heavily-used entities in your UIM environment.

Understanding How UIM Uses Row Locking

Figure 13-1 shows the flow of an entity finder API call for UIM entities that do not use row locking. When a UIM user initiates an entity search, an entity finder API is called, and the search results are returned to the client.

Figure 13-1 Flow of Entity Finder API without Row Locking

Description of Figure 13-1 follows
Description of ''Figure 13-1 Flow of Entity Finder API without Row Locking''

Figure 13-2 shows the flow of an entity finder API call for UIM entities that use row locking. When a UIM user initiates an entity search, the LockPolicy attributes are set before calling the entity finder API, and the locked search results are returned to the client.

Figure 13-2 Flow of Entity Finder API with Row Locking

Description of Figure 13-2 follows
Description of ''Figure 13-2 Flow of Entity Finder API with Row Locking''

Writing Custom Code to Use Row Locking

You can write custom code to use row locking with entity finder APIs for any heavily-used entities in your UIM environment. The custom code must set the LockPolicy attributes and call the entity finder API. This can be accomplished through:

Custom Rulesets

Note:

This section builds upon the information presented in Chapter 8, "Extending UIM Through Rulesets", and assumes you have an understanding of rulesets, extension points, and ruleset extension points.

In the following scenario, the custom code resides in an Inventory cartridge, within a custom Java class that is called by a custom ruleset.

Figure 13-3 shows the flow of an entity finder API call for rowlock-enabled entities that you use with row locking through custom code. After the customizations are in place, when a UIM user initiates an entity search, an entity finder API is called. However, before the entity finder API runs, the method is intercepted by the custom extension point, which is configured to run the custom ruleset instead of the entity finder API. The custom ruleset calls the custom code, which sets the LockPolicy attributes and calls the same entity finder API. Based on the LockPolicy attributes specified, the search results are locked and returned to the client.

Figure 13-3 Flow of Entity Finder API Using a Custom Ruleset

Description of Figure 13-3 follows
Description of ''Figure 13-3 Flow of Entity Finder API Using a Custom Ruleset''

The following procedure provides detailed steps and example custom code that you can use to create the customized flow of an entity finder API call that uses row locking.

To use row locking with entity finder APIs:

  1. Create a custom Java class.

    Example 13-5 shows a custom Java class that finds party entities using row locking, but you can write similar logic for any entity. To accomplish this, the custom logic must:

    • Create a LockPolicy object

    • Set the LockPolicy attributes

    • Set the entity-specific search criteria object with the LockPolicy object

    • Call the appropriate entity finder API method, passing in the appropriate entity search criteria object that is populated with the LockPolicy

    • Set the ruleset return value to the row-locked results from the entity finder API call

    Example 13-5 Custom Java Class

    package oracle.communications.custom;
     
    import java.util.*;
    import oracle.communications.platform.persistence.PersistenceHelper;
    import oracle.communications.inventory.api.entity.Party;
    import oracle.communications.inventory.api.party.PartyManager;
    import oracle.communications.inventory.api.party.PartySearchCriteria;
    import oracle.communications.inventory.api.framework.LockPolicy;
    import oracle.communications.inventory.extensibility.extension.util.
    ExtensionPointRuleContext;
     
    public class CustomPartySearch 
    {        
            public void main(PartySearchCriteria criteria ExtensionPointRuleContext 
        context) throws Exception
                {
                            LockPolicy lockPolicy = PersistenceHelper.makeLockPolicy();                  
     
                            lockPolicy.setNumberOfResources(20);
                            lockPolicy.setExpiration(5000);
                            lockPolicy.setFilterExistingLocks(true);
    
                            criteria.setLockPolicy(lockPolicy);
    
                            PartyManager partyMgr = PersistenceHelper.makePartyManager();                
                            List<Party> partyObjs = partyMgr.findParty(criteria);
    
                            context.setReturnValue(partyObjs);              
            }
            }
    
  2. Create a custom ruleset.

    Example 13-6 shows a custom ruleset that call the custom Java class shown in Example 13-5. You can write a similar custom ruleset to call any custom Java class.

    Example 13-6 Custom Ruleset Using Drools

    package oracle.communications.inventory.rules
    
    import oracle.communications.custom.CustomPartySearch;
    import oracle.communications.inventory.api.entity.party.PartySearchCriteria;
    import racle.communications.inventory.extensibility.extension.util.
    ExtensionPointRuleContext;
    
    rule "PartySearch"
        salience 0
            when
                criteria : PartySearchCriteria()
                context : ExtensionPointRuleContext()                   
            then
                        CustomPartySearch customClass = new CustomPartySearch();
                customClass.main(criteria, context);
    end
    

    Example 13-7 shows the same custom ruleset content-wise, but using Groovy instead of Drools. For more information on writing custom rulesets, and on the use of Drools and Groovy to do so, see Chapter 8, "Extending UIM Through Rulesets".

    Example 13-7 Custom Ruleset Using Groovy

    package oracle.communications.inventory.rules
    
    import oracle.communications.custom.CustomPartySearch;
    import oracle.communications.inventory.api.entity.party.PartySearchCriteria;
    import racle.communications.inventory.extensibility.extension.util.
    ExtensionPointRuleContext;
    
                    CustomPartySearch customClass = new CustomPartySearch();
    customClass.main(criteria, context);
    

    Note:

    The criteria local variable is based on the argument that the custom extension point defines, which is PartySearchCriteria, as shown in Example 13-8. The context local variable of ExtensionPointRulesetContext is made available to all rulesets by the extensibility framework, which appends this argument to the list of arguments defined by the custom extension point. See "ExtensionPointContext and ExtensionPointRuleContext Class" for more information.
  3. Create a custom extension point.

    Example 13-8 shows the custom extension point method signature for the findParty API method. You can define a similar extension point signature for any entity finder API.

    Example 13-8 Custom Extension Point Signature

    public abstract interface java.lang.String oracle.communications.inventory.api.party.PartyManager.findParty(oracle.communications.inventory.api.entity.party.PartySearchCriteria)
    
  4. Create a custom ruleset extension point.

    The custom ruleset extension point configures the custom ruleset to run at the custom extension point. In this scenario, the placement of the custom ruleset must be Instead of the method defined by the custom extension point. In this manner, the custom ruleset calls the entity finder API and returns the row-locked entities to UIM.

Custom Web Services

Note:

This section builds upon information presented in UIM Web Services Developer's Guide, and assumes you have an understanding of web services and how to develop them.

In this scenario, the custom code resides in a custom web service.

Figure 13-4 shows the flow of an entity finder API call for rowlock-enabled entities that you use with row locking through custom code. After the customizations are in place, the web service is initiated by an external system through a request. The web service custom code sets the LockPolicy attributes and calls the entity finder API. Based on the LockPolicy attributes specified, the search results are locked and returned to the web service. The web service then sends the locked search results back to the external system through a response.

Figure 13-4 Flow of Entity Finder API Using a Custom Web Service

Description of Figure 13-4 follows
Description of ''Figure 13-4 Flow of Entity Finder API Using a Custom Web Service ''

To use row locking with entity finder APIs through a custom web service, the web service must contain a Java class similar to the one shown in Figure 13-3.

Using Row Locking Without Entity Finder APIs

You can also use row locking without using entity finder APIs. Example 13-9 shows a custom Java class that locks a Collection of entities. To accomplish this, the custom logic must:

  • Create a Collection of entities

  • Create a LockPolicy object

  • Set the LockPolicy attributes

  • Call the RowLockManager.lock method, passing in the entity rows to be locked and the LockPolicy used to lock them

Example 13-9 Custom Java Class

package oracle.communications.custom;
 
import java.util.*;
import oracle.communications.platform.persistence.PersistenceHelper;
import oracle.communications.inventory.api.common.RowLockManager;
import oracle.communications.inventory.api.framework.LockPolicy;
 
public class CustomClass 
{        
        public void main() throws Exception
            {
        Collection myCollection = new Collection();              

                // Poulate myCollection with like entities, such as Party entities,
        // Role entities, etc.
        .
        .
        . 
        // Create a LockPolicy and populate the attributes
                        LockPolicy lockPolicy = PersistenceHelper.makeLockPolicy();                  
                        lockPolicy.setNumberOfResources(20);
                        lockPolicy.setExpiration(5000);
                        lockPolicy.setFilterExistingLocks(true);

        // Call RowLockManager.lock to lock entities in myCollection
                        RowLockManager rowLockMgr = PersistenceHelper.makeRowLockMgr();              
        Collection myLockedCollection = 
            rowLockMgr.lock(myCollection, lockPolicy);
        }
        }

Note:

You can use rulesets and extension points to run the custom code shown in Example 13-9. See "Using Row Locking with Entity Finder APIs" for an example.