[Java programming language only]

Enabling evictors programmatically

Evictors are associated with BackingMap instances.

Before you begin

Before you begin, decide on the type of evictor you are going to use:
Default time-based TTL evictor
The default evictor uses a time-to-live (TTL) eviction policy for each BackingMap instance.
Pluggable evictor mechanism
Pluggable evictors typically use an eviction policy that is based on the number of entries instead of on time.
Most evictor settings should be set before you initialize the ObjectGrid.

Procedure

  • Set the default TTL evictor.
    Use the BackingMap interface to set the expiration time for each entry to 10 minutes after the entry was created.
    Figure 1. Programmatic time-to-live evictor
    import com.ibm.websphere.objectgrid.ObjectGridManagerFactory;
    import com.ibm.websphere.objectgrid.ObjectGridManager;
    import com.ibm.websphere.objectgrid.ObjectGrid;
    import com.ibm.websphere.objectgrid.BackingMap;
    import com.ibm.websphere.objectgrid.TTLType;
    ObjectGridManager ogManager = ObjectGridManagerFactory.getObjectGridManager();
    ObjectGrid og = ogManager.createObjectGrid( "grid" );
    BackingMap bm = og.defineMap( "myMap" );
    bm.setTtlEvictorType( TTLType.CREATION_TIME );
    bm.setTimeToLive( 600 );

    The setTimeToLive method argument is 600 because it indicates the time-to-live value is in seconds. The preceding code must run before the initialize method is invoked on the ObjectGrid instance. These BackingMap attributes cannot be changed after the ObjectGrid instance is initialized. After the code runs, any entry that is inserted into the myMap BackingMap has an expiration time. After the expiration time is reached, the TTL evictor removes the entry.

    To set the expiration time to the last access time plus 10 minutes, change the argument that is passed to the setTtlEvictorType method from TTLType.CREATION_TIME to TTLType.LAST_ACCESS_TIME. With this value, the expiration time is computed as the last access time plus 10 minutes. When an entry is first created, the last access time is the creation time. To base the expiration time on the last update, instead of merely the last access (whether or not it involved an update), substitute the TTLType.LAST_UPDATE_TIME setting for the TTLType.LAST_ACCESS_TIME setting.

    When using the TTLType.LAST_ACCESS_TIME or TTLType.LAST_UPDATE_TIME setting, you can use the ObjectMap and JavaMap interfaces to override the BackingMap time-to-live value. This mechanism allows an application to use a different time-to-live value for each entry that is created. Assume that the preceding snippet of code set the ttlType attribute to LAST_ACCESS_TIME and set the time-to-live value to 10 minutes. An application can then override the time-to-live value for each entry by running the following code prior to creating or modifying an entry:

    import com.ibm.websphere.objectgrid.Session;
    import com.ibm.websphere.objectgrid.ObjectMap;
    Session session = og.getSession();
    ObjectMap om = session.getMap( "myMap" );
    int oldTimeToLive1 = om.setTimeToLive( 1800 );
    om.insert("key1", "value1" );
    int oldTimeToLive2 = om.setTimeToLive( 1200 );
    om.insert("key2", "value2" );

    In the previous snippet of code, the entry with the key1 key has an expiration time of the insert time plus 30 minutes as a result of the setTimeToLive( 1800 ) method invocation on the ObjectMap instance. The oldTimeToLive1 variable is set to 600 because the time-to-live value from the BackingMap is used as a default value if the setTimeToLive method was not previously called on the ObjectMap instance.

    The entry with the key2 key has an expiration time of insert time plus 20 minutes as a result of the setTimeToLive( 1200 ) method call on the ObjectMap instance. The oldTimeToLive2 variable is set to 1800 because the time-to-live value from the previous ObjectMap.setTimeToLive method invocation set the time-to-live value to 1800.

    The previous example shows two map entries being inserted in the myMap map for keys key1 and key2. At a later point in time, the application can still update these map entries while retaining the time-to-live values that are used at insert time for each map entry. The following example illustrates how to retain the time-to-live values by using a constant defined in the ObjectMap interface:

    Session session = og.getSession();
    ObjectMap om = session.getMap( "myMap" );
    om.setTimeToLive( ObjectMap.USE_DEFAULT );
    session.begin();
    om.update("key1", "updated value1" );
    om.update("key2", "updated value2" );
    om.insert("key3", "value3" );
    session.commit();

    Since the ObjectMap.USE_DEFAULT special value is used on the setTimeToLive method call, the key1 key retains its time-to-live value of 1800 seconds and the key2 key retains its time-to-live value of 1200 seconds because those values were used when these map entries were inserted by the prior transaction.

    The previous example also shows a new map entry for the key3 key insert. In this case, the USE_DEFAULT special value indicates to use the default setting of time-to-live value for this map. The default value is defined by the time-to-live BackingMap attribute. See BackingMap interface attributes for information about how the time-to-live attribute is defined on the BackingMap instance.

    See the API documentation for the setTimeToLive method on the ObjectMap and JavaMap interfaces. The documentation explains that an IllegalStateException exception results if the BackingMap.getTtlEvictorType method returns anything other than the TTLType.LAST_ACCESS_TIME or TTLType.LAST_UPDATE_TIME value. The ObjectMap and JavaMap interfaces can override the time-to-live value only when you are using the LAST_ACCESS_TIME or LAST_UPDATE_TIME setting for the TTL evictor type. The setTimeToLive method cannot be used to override the time-to-live value when you are using the evictor type setting NONE.

  • Set a pluggable evictor.

    Because evictors are associated with BackingMaps, use the BackingMap interface to specify the pluggable evictor. The following code snippet is an example of specifying a LRUEvictor evictor for the map1 BackingMap and a LFUEvictor evictor for the map2 BackingMap instance:

    Figure 2. Plugging in an evictor programmatically
    import com.ibm.websphere.objectgrid.ObjectGridManagerFactory;
    import com.ibm.websphere.objectgrid.ObjectGridManager;
    import com.ibm.websphere.objectgrid.ObjectGrid;
    import com.ibm.websphere.objectgrid.BackingMap;
    import com.ibm.websphere.objectgrid.plugins.builtins.LRUEvictor;
    import com.ibm.websphere.objectgrid.plugins.builtins.LFUEvictor;
    ObjectGridManager ogManager = ObjectGridManagerFactory.getObjectGridManager();
    ObjectGrid og = ogManager.createObjectGrid( "grid" );
    BackingMap bm = og.defineMap( "map1" );
    LRUEvictor evictor = new LRUEvictor();
    evictor.setMaxSize(1000);
    evictor.setSleepTime( 15 );
    evictor.setNumberOfLRUQueues( 53 );
    bm.setEvictor(evictor);
    bm = og.defineMap( "map2" );
    LFUEvictor evictor2 = new LFUEvictor();
    evictor2.setMaxSize(2000);
    evictor2.setSleepTime( 15 );
    evictor2.setNumberOfHeaps( 211 );
    bm.setEvictor(evictor2);

    The preceding snippet shows an LRUEvictor evictor being used for map1 BackingMap with an approximate maximum number of entries of 53,000 (53 * 1000). The LFUEvictor evictor is used for the map2 BackingMap with an approximate maximum number of entries of 422,000 (211 * 2000). Both the LRU and LFU evictors have a sleep time property that indicates how long the evictor sleeps before waking up and checking to see if any entries need to be evicted. The sleep time is specified in seconds. A value of 15 seconds is a good compromise between performance impact and preventing BackingMap from growing too large. The goal is to use the largest sleep time possible without causing the BackingMap to grow to an excessive size.

    The setNumberOfLRUQueues method sets the LRUEvictor property that indicates how many LRU queues the evictor uses to manage LRU information. A collection of queues is used so that every entry does not keep LRU information in the same queue. This approach can improve performance by minimizing the number of map entries that need to synchronize on the same queue object. Increasing the number of queues is a good way to minimize the impact that the LRU evictor can cause on performance. A good starting point is to use ten percent of the maximum number of entries as the number of queues. Using a prime number is typically better than using a number that is not prime. The setMaxSize method indicates how many entries are allowed in each queue. When a queue reaches its maximum number of entries, the least recently used entry or entries in that queue are evicted the next time that the evictor checks to see if any entries need to be evicted.

    The setNumberOfHeaps method sets the LFUEvictor property to set how many binary heap objects the LFUEvictor uses to manage LFU information. Again, a collection is used to improve performance. Using ten percent of the maximum number of entries is a good starting point and a prime number is typically better than using a number that is not prime. The setMaxSize method indicates how many entries are allowed in each heap. When a heap reaches its maximum number of entries, the least frequently used entry or entries in that heap are evicted the next time that the evictor checks to see if any entries need to be evicted.