|
Directiva de caducidad de entrada de caché
|
Descripción
|
|---|---|
|
Nunca
|
La entrada de la caché nunca se elimina en función de la cantidad de tiempo que ha pasado en la caché. Sin embargo, todavía se puede expulsar si la caché alcanza la configuración de tamaño máximo o mediante el servicio DeleteEntry. La opción de configuración Hora de vencimiento de la entrada de caché (segundos) se desestima cuando se configura la directiva de caducidad Never.
|
|
Hora de vencimiento desde el último acceso
|
La entrada se quita si no se ha leído dentro de la hora de vencimiento especificada.
|
|
Hora de vencimiento desde la creación
|
La entrada se quita una vez transcurrido el tiempo especificado desde su creación.
|
|
Hora de vencimiento desde la última modificación
|
La entrada se quita si no se ha modificado dentro de la hora de vencimiento especificada.
|
|
Hora de vencimiento desde la última vez que se tocó
|
La entrada se quita si no se ha accedido a ella o no se ha modificado dentro de la hora de vencimiento especificada.
|
|
Nombre del servicio
|
Descripción
|
|---|---|
|
PutEntry
|
• Permite añadir una entrada a la caché.
• Valor de entrada: infotable de una fila que utiliza la definición de datos configurada de la CacheThing.
|
|
GetEntry
|
• Se devuelve el resultado de una infotable de una fila de la caché.
• Si no se encuentra la entrada (error de caché) y la caché no está configurada con Cache Performs Loading of Missing Entries, se devuelve una infotable vacía. Si la caché está configurada con esa opción, se llama automáticamente al servicio LoadEntry y se devuelve su resultado.
• Se pueden producir errores de caché si la entrada nunca se ha añadido a la caché, se ha expulsado o ha caducado.
• Valor de entrada: infotable de una fila que utiliza la definición de datos configurada de la CacheThing. Solo se deben rellenar los valores Primary Key.
|
|
GetEntryByKey
|
• Se devuelve el resultado de una infotable de una fila de la caché.
• Si no se encuentra la entrada, se devuelve una infotable vacía. Se pueden producir errores de caché si la entrada nunca se ha añadido a la caché, se ha expulsado o ha caducado.
• Valor de entrada: cadena que representa la clave primaria de la entrada que se recupera. Este servicio solo está disponible si la definición de datos configurada tiene una única clave primaria. Esto funciona mejor con claves primarias de cadena, pero también soporta la mayoría de los tipos con una conversión de cadena clara.
|
|
LoadEntry
|
• Se utiliza para obtener automáticamente datos de caché del origen de datos cuando se produce un error de caché.
• Este servicio se debe sustituir si la opción Cache Performs Loading of Missing Entries está activada.
|
|
DeleteEntry
|
• Permite borrar una entrada de la caché.
• En un entorno de alta disponibilidad, esto solo afecta al nodo donde se llama al servicio DeleteEntry.
• Valor de entrada: infotable de una fila que utiliza la definición de datos configurada de la CacheThing. Solo se deben rellenar los valores Primary Key.
|
|
DeleteEntryByKey
|
• Permite borrar una entrada de la caché.
• En un entorno de alta disponibilidad, esto solo afecta al nodo donde se llama al servicio DeleteEntryByKey.
• Valor de entrada: cadena que representa la clave primaria de la entrada que se recupera. Este servicio solo está disponible si la definición de datos configurada tiene una única clave primaria.
|
|
PurgeCache
|
• Permite quitar todas las entradas de la caché.
• En un entorno de alta disponibilidad, esto solo afecta al nodo donde se llama al servicio PurgeCache.
|
|
GetDataShape
|
Se devuelve la definición de datos configurada de la caché.
|
|
SetDataShape
|
Permite definir el campo de la definición de cosa en la tabla de configuración de la caché. Si se cambia este valor, se depurará automáticamente la caché.
|
|
GetEstimatedEntryCount
|
Permite devolver el número estimado de entradas en la caché. Las operaciones PUT y DELETE en curso, así como los procesos de caducidad o expulsión, pueden afectar a la precisión.
|
|
EstimateEntrySize
|
• Se devuelve el tamaño estimado de una entrada si se ha añadido a la caché. Esto no coloca la entrada en la caché y no requiere ninguna entrada que ya esté en la caché. Este servicio puede ser de utilidad para estimar un valor de Tamaño máximo de caché (MB) adecuado o para evitar que se añadan entradas de gran tamaño a la caché.
• Valor de entrada: infotable de una fila que utiliza la definición de datos configurada de la CacheThing.
|
|
Métricas de caché
|
Descripción
|
|---|---|
|
thingworx_cache_hit_rate
|
Proporción de solicitudes de caché que han dado lugar a la búsqueda de una entrada en la caché
|
|
thingworx_cache_hits
|
Número de veces que los métodos de búsqueda en caché han devuelto un valor almacenado en caché
|
|
thingworx_cache_request_count
|
Número de veces que los métodos de búsqueda en caché han devuelto un valor almacenado en caché o no almacenado en caché
|
|
thingworx_cache_miss_rate
|
Proporción de métodos de búsqueda en caché que han devuelto un valor no almacenado en caché (recién cargado) o nulo
|
|
thingworx_cache_misses
|
Número de veces que los métodos de búsqueda en caché han devuelto un valor no almacenado en caché (recién cargado) o nulo
|
|
thingworx_cache_eviction_count
|
Número de veces que se ha expulsado una entrada
|
|
thingworx_cache_average_load_penalty
|
Tiempo medio empleado en cargar nuevos valores
|
|
thingworx_cache_weighted_size
|
Tamaño actual aproximado de la caché en bytes
|
|
thingworx_cache_max_weight
|
Tamaño máximo de la caché en bytes antes de la expulsión
|
|
thingworx_cache_estimated_entry_count
|
Número estimado de entradas en la caché
|
|
thingworx_cache_global_max_size
|
Tamaño máximo global configurado para todas las cachés en bytes
|
// Input is x as a LONG
// Output is result as LONG
// MyTimesTwoCache CacheThing is configured with a DataShape with two fields:
// operand: (LONG, primaryKey)
// timesTwoValue: (LONG)
result = -1;
// Check the cache first, to see if we have already calculated x*2
// GetEntryByKey is a convenience method that takes the String value the configured DataShape's Primary Key ("key" in this example)
// cacheResult is an InfoTable with the DataShape of the cache
let cacheResult = Things["MyTimesTwoCache"].GetEntryByKey({ operand: x.toString() });
if (cacheResult.getRowCount() === 0) {
// Cache didn't have a result, so calculate it
let timesTwo = x*2;
// Put the result in the cache for the next time we need this multiple
// operand and value are from the Cache's configured DataShape
let cacheInput = getInfoTableForPut(x, timesTwo);
Things["MyTimesTwoCache"].PutEntry({
values: cacheInput
});
// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("PutEntry the following entry into the MyTimesTwoCache: {operand: " + x + ", timesTwoValue: " + timesTwo + "}");
// Set the global result Output variable
result = timesTwo;
} else {
// If results are found, they are always in the first row of the InfoTable
let row = cacheResult.getRow(0);
logger.debug("Found the following entry already in MyTimesTwoCache: {operand: " + row.operand + ", timesTwoValue: " + row.timesTwoValue + "}");
result = row.timesTwoValue;
}
function getInfoTableForPut(operand, timesTwoValue) {
let infoTable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: Things["MyTimesTwoCache"].GetDataShape()
});
infoTable.AddRow({"operand": operand, "timesTwoValue ": timesTwoValue });
return infoTable;
}
/*
This Service queries QueryImplementingThingsV2 and caches the results as needed
Service Name: CachingQueryImplementingThingsV2 (Overridden on CacheThing)
Input: values InfoTable with Cached_QueryImplementingThingsV2_DataShape
Cached_QueryImplementingThingsV2_DataShape:
maxItems: NUMBER, Primary Key
nameMask: STRING, Primary Key
query: QUERY, Primary Key
isSortFirst: BOOLEAN, Primary Key
result: INFOTABLE, DataShape RootEntityListV2 (NOT a Primary Key!)
*/
let cacheEntryInfoTable = getCacheEntryInfoTable();
cacheEntryInfoTable.AddRow({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */
});
let getEntryResult = me.GetEntry({values: cacheEntryInfoTable});
if (getEntryResult.getRowCount() === 0) {
// Cache didn't have results, so call QueryImplementingThingsV2
let queryResult = ThingTemplates["GenericThing"].QueryImplementingThingsV2({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */
});
// Add the result to the cache, with the primaryKey parameters used to uniquely identify the query.
let newCacheEntryInfoTable = getCacheEntryInfoTable();
newCacheEntryInfoTable.AddRow({
maxItems: maxItems /* NUMBER */,
nameMask: nameMask /* STRING */,
query: query /* QUERY */,
isSortFirst: isSortFirst /* BOOLEAN */,
result: queryResult /* INFOTABLE */
});
me.PutEntry({
values: newCacheEntryInfoTable
});
logger.debug("Entry not found in Cache, retrieved from QueryImplementingThingsV2:" + queryResult.ToJSON());
result = queryResult;
} else {
logger.debug("Found entry from Cache:" + getEntryResult.ToJSON());
let row = getEntryResult.getRow(0);
result = row.result;
}
function getCacheEntryInfoTable() {
return Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "Cached_QueryImplementingThingsV2_DataShape"
});
}
/*
This Service simply proxies a query to QueryImplementingThingsV2 for Read Through caching
Service Name: LoadEntry (Overridden on CacheThing)
Input: values InfoTable with Cached_QueryImplementingThingsV2_DataShape
Cached_QueryImplementingThingsV2_DataShape:
maxItems: NUMBER, Primary Key
nameMask: STRING, Primary Key
query: QUERY, Primary Key
isSortFirst: BOOLEAN, Primary Key
result: INFOTABLE, DataShape RootEntityListV2 (NOT a Primary Key!)
*/
let queryResult = ThingTemplates["GenericThing"].QueryImplementingThingsV2({
maxItems: values.maxItems /* NUMBER */,
nameMask: values.nameMask /* STRING */,
query: values.query /* QUERY */,
isSortFirst: values.isSortFirst /* BOOLEAN */
});
// Copy the results into a new InfoTable.
// This prevents some internal ThingWorx casting issues with some InfoTables
let resultTable = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: me.GetDataShape() // Returns Cached_QueryImplementingThingsV2_DataShape
});
resultTable.AddRow({
maxItems: values.maxItems /* NUMBER {"defaultValue":500} */,
nameMask: values.nameMask /* STRING */,
query: values.query /* QUERY */,
isSortFirst: values.isSortFirst /* BOOLEAN */,
result: queryResult
});
let result = resultTable;
Este servicio permite rellenar automáticamente los datos de demostración en la tabla de datos del rango de fechas consultado. |
/* Reads the Cached results of BetweenDatesDataTableQuery Service.
If Cache doesn't have the result, call BetweenDatesDataTableQuery and load results into Cache.
Service Name: CachingBetweenDatesDataTableQuery
Inputs: StartDate[DATETIME, required], EndDate[DATETIME, required]
Output: LONG
*/
// This example uses CacheThing.GetEntry, which requires a one-row infoTable populated with the CacheThing's DataShapes primaryKey getEntryByKey
let cacheEntryInfoTable = getCacheEntryInfoTable();
cacheEntryInfoTable.AddRow({"startDate": StartDate, "endDate": EndDate});
let getEntryResult = Things["CacheThingDemo"].GetEntry({
values: cacheEntryInfoTable
});
if (getEntryResult.getRowCount() === 0) {
// Cache didn't have results, so go to backing DataTable, by calling the BetweenDatesDataTableQuery Service
let queryResult = Things["CacheThingDemo"].BetweenDatesDataTableQuery({
StartDate: StartDate,
EndDate: EndDate
});
// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("PutEntry called for BetweenDatesQueryCache: {StartDate: " + StartDate + ", EndDate: " + EndDate + " value: " + queryResult + "}");
if (!queryResult || queryResult < 0) {
// BetweenDatesDataTableQuery should always populate with demo data if no data is in the StartDate - EndDate range
throw new Error("BetweenDatesDataTableQuery did not return results");
}
let newCacheEntryInfoTable = getCacheEntryInfoTable();
newCacheEntryInfoTable.AddRow({"startDate": StartDate, "endDate": EndDate, "longValue": queryResult});
Things["CacheThingDemo"].PutEntry({
values: newCacheEntryInfoTable
});
result = queryResult;
} else {
let row = getEntryResult.getRow(0);
logger.debug("Found the following entry already in Cache : {StartDate: " + row.startDate + ", EndDate: " + row.endDate + ", LongValue: " + row.longValue + "}");
result = row.longValue;
}
function getCacheEntryInfoTable() {
return Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "TimeSpanValueCacheDataShape"
});
}
/* This service queries a range of dates, based on the dateKey column, and returns the greatest longKey value found.
If there are no entries between StartDate and EndDate this Service dynamically populates demo data into demoDataTable, and returns that result.
Service Name: BetweenDatesDataTableQuery
Inputs: StartDate[DATETIME, required], EndDate[DATETIME, required]
Output: LONG
*/
if (StartDate >= EndDate) {
throw Error("StartDate must be before EndDate");
}
let dataTable = Things["DemoDataTable"];
let queryResult = queryGreatestLongKeyBetweenDates(dataTable, StartDate, EndDate);
if (queryResult.getRowCount() === 0) {
// If we don't get any results, first populate the date range with random values, then retry
// Turn ScriptLogger to debug mode to see the logger messages
logger.debug("No values found between [" + StartDate + "] and [" + EndDate + "], populating 100 demo values and re-querying");
populateDemoDataTable(dataTable, StartDate, EndDate);
// Re-query the now populated DateTable
queryResult = queryGreatestLongKeyBetweenDates(dataTable, StartDate, EndDate);
result = queryResult.getRow(0).get("longKey");
} else {
result = queryResult.getRow(0).get("longKey");
}
// Queries the DataTable for the largest longKey column value between the given dates
// Returns: One-row InfoTable with the found row.
function queryGreatestLongKeyBetweenDates(dateTable, startDate, endDate) {
let greatestBetweenDatesQuery = {
"filters": {
"type": "Between",
"fieldName": "dateKey",
"from": startDate,
"to": endDate
},
"sorts": [{
"fieldName": "longKey",
"isAscending": false
}]
};
// Run the Query to find the greatest Value Between Two Dates
let queryResult = dataTable.QueryDataTableEntries({
maxItems: 1,
query: greatestBetweenDatesQuery,
});
logger.debug("Queried between [" + StartDate + "] and [" + EndDate + "], found:" + queryResult.toJSON());
return queryResult;
}
function populateDemoDataTable(dataTable, startDate, endDate) {
// add 100 random entries between startDate and endDate
for (let entry = 0; entry < 100; entry++) {
let randomTimeBetween = randomDate(startDate, endDate);
let entry = Resources["InfoTableFunctions"].CreateInfoTableFromDataShape({
infoTableName: "InfoTable",
dataShapeName: "TimeValueDataShape"
});
entry.AddRow({
"longKey": Math.floor(Math.random() * 1000),
"dateKey": randomTimeBetween
});
Things["DemoDataTable"].AddDataTableEntry({
values: entry /* INFOTABLE */ ,
});
}
}
function randomDate(startDate, endDate) {
let randomTime = Math.random() * (endDate.getTime() - startDate.getTime()) + startDate.getTime();
return new Date(randomTime);
}