Micro Cache & Micro Cache Array¶
IFS Cloud are designed to use views in the client to retrieve data and as the client often needs more data from other entities, the views uses PL/SQL functions to get that information. This is done either by Get_methods accessed through a primary key (PK) in the select list or in the where clause. The Get_methods are executed at least once for each row and are fetched from the database, often with calling columns as parameters. If instead the last record fetched is saved, and a check is added to see if it is the same record that is requested again, then the saved record could be passed back to the client. If such functionality existed then a database call (query) isn't necessary and that is exactly what the Micro Cache provides.
The Micro Cache is a runtime cache where the data is saved temporarily. By using the Micro Cache the buffer gets can be reduced significantly, but due to some limitations it should be implemented with care.
The Micro Cache is also an Oracle session cache, so each user logged on to Oracle has it's own cache. This means that if ten users access the same record in the same entity time after time, then by using the same primary key (PK) for a method they will use their own cache. If the first user updates the entity his cache will be flushed, but the other users caches are not flushed. This will lead to that they will retrieve the wrong data until they have read a new record and done a new fetch again. The cache is also flushed if one user logs out and that Oracle session is acquired by another user. In order to minimize this problem a timestamp together with the primary key could be used, then the cache is flushed if the time has past the limit. IFS EE APF pages, the cache is flushed after each client call to the server but not in other clients such as IFS Aurena / IFS EE Feature pages or Mobile clients.
The Micro Cache Array is an extension of Micro cache implementation. The only difference with Micro Cache is, Micro Cache array can store multiple records instead of a single record. When the array is filled with records, one item is randomly removed at the next request.
When to use Micro Cache¶
Some good examples of when to use Micro Cache are as follows:
- Values that can be reused even it they have been updated to a new value, e.g.. customer name, part description and so on.
- Entities with few values, e.g.. Countries, Sites and so on.
- Entities where most users request the same few records, e.g.. where company or site is the only key.
- Where the same entity get_methods exists more than once in the select list.
- Where a get_method exists in the where-clause and its likely that the same request appears frequently.
- If the get_methods are called in a way where data is ordered.
Example of when to use Micro Cache¶
When executing the query below the database first fetches all Order_Head rows and then executes Get_Cust_Name method for each row. Since this query is ordered by Customer_No it is most likely that the same Customer_No is used several times, before changing the Customer_no. If the last record fetched is saved, then there is a check to see if it is the same record that is being requested again. If it is, then the saved record is passed back to the client. Then a call (query) to the database isn't necessary.
BEGIN
SELECT order_no, customer_no, Customer_API.Get_Name(customer_no)
FROM order_head
ORDER BY customer_no;
END;
FUNCTION Get_Cust_Name (
customer_no_ IN NUMBER ) RETURN VARCHAR2
IS
temp_ customer_tab.name%TYPE;
CURSOR get_attr IS
SELECT name
FROM customer_tab
WHERE customer_no = customer_no_;
BEGIN
OPEN get_attr;
FETCH get_attr INTO temp_;
CLOSE get_attr;
RETURN temp_;
END Get_Cust_Name;
When to use Micro Cache Array¶
Micro Cache Array is preferred for most of the scenarios where Micro Cache is applicable & more than one record of the LU is referred in an application flow. But if this number of records is in hundreds or even higher, then there may be hardly any advantage implementing either Micro Cache or Micro Cache Array for that LU.
When not to use Micro Cache or Micro Cache Array¶
Examples of when not to use either Micro Cache or Micro Cache Array:
- Values that are extreme important to get the exact value, e.g.. currency rate, inventory quantity on hand and so on.
- Stored or computed values which are dependent on child tables, e.g.. order values based on order lines.
- If the query returns the requested values in an unsorted result set, then the positive effect is gone, e.g.. in the query example above was ordered by Order_No instead of Customer_No then it is unlikely that the same Customer_No will appear after each other.
- On derived attributes.
Micro Cache & Micro Cache Array Implementation¶
To get the Micro Cache / Micro Cache Array implementation to work, you only need to add a codegen property in the entity model.
Micro Cache:
codegenproperties {
DbImplementation "micro-cache";
}
When the code is generated a few variables will be declared. A public record holding the cached values, a number to be used for the timestamp and an id for the cached Primary Key. If more than one Primary Key exists then more variables needs to be declared.
FUNCTION Private_Declarations (
customer_no_ IN NUMBER) RETURN VARCHAR2
IS
micro_cache_value_ Public_Rec;
micro_cache_id_ NUMBER;
micro_cache_time_ NUMBER := 0;
BEGIN
RETURN customer_no_;
END Private_Declarations;
The Update_Cache_ method in the Get_method will be generated and used instead of a cursor and then return the value from the Micro Cache record.
FUNCTION Get_Name (
customer_no_ IN NUMBER ) RETURN VARCHAR2
IS
BEGIN
Update_Cache___(customer_no_);
RETURN micro_cache_value_.name;
END Get_Name;
The Invalidate_Cache___ method will be generated into Update___ and Delete___ to reset the cache in case the record is modified or removed.
PROCEDURE Update___ (
objid_ IN VARCHAR2,
oldrec_ IN micro_cache_tab%ROWTYPE,
newrec_ IN OUT micro_cache_tab%ROWTYPE,
attr_ IN OUT VARCHAR2,
objversion_ IN OUT VARCHAR2,
by_keys_ IN BOOLEAN DEFAULT FALSE )
IS
value_too_large EXCEPTION;
PRAGMA EXCEPTION_INIT(value_too_large, -12899);
BEGIN
newrec_.rowversion := sysdate;
IF by_keys_ THEN
UPDATE micro_cache_tab
SET ROW = newrec_
WHERE id = newrec_.id;
ELSE
UPDATE micro_cache_tab
SET ROW = newrec_
WHERE rowid = objid_;
END IF;
objversion_ := to_char(newrec_.rowversion,'YYYYMMDDHH24MISS');
Invalidate_Cache___;
EXCEPTION
WHEN dup_val_on_index THEN
DECLARE
constraint_ VARCHAR2(4000) := Utility_SYS.Get_Constraint_From_Error_Msg(sqlerrm);
BEGIN
IF (constraint_ = 'MICRO_CACHE_RK') THEN
Error_SYS.Fnd_Rowkey_Exist(Micro_Cache_API.lu_name_, newrec_.rowkey);
ELSIF (constraint_ = 'MICRO_CACHE_PK') THEN
Raise_Record_Exist___(newrec_);
ELSE
Raise_Constraint_Violated___(newrec_, constraint_);
END IF;
END;
WHEN value_too_large THEN
Error_SYS.Fnd_Item_Length(lu_name_, sqlerrm);
END Update___;