|
Règle d'expiration des entrées de cache
|
Description
|
|---|---|
|
Jamais
|
L'entrée de cache n'est jamais supprimée sur la base de la durée de son séjour dans le cache. Toutefois, elle pourra toujours être évincée si le cache atteint la configuration de taille maximale ou à l'aide du service DeleteEntry. Le paramètre Délai d'expiration des entrées de cache (secondes) est ignoré lorsque la règle d'expiration Never est configurée.
|
|
Délai d'expiration depuis le dernier accès
|
L'entrée est supprimée si elle n'a pas été lue dans le délai d'expiration spécifié.
|
|
Délai d'expiration depuis la création
|
L'entrée est supprimée une fois que le temps spécifié s'est écoulé depuis sa création.
|
|
Délai d'expiration depuis la dernière modification
|
L'entrée est supprimée si elle n'a pas été modifiée dans le délai d'expiration spécifié.
|
|
Délai d'expiration depuis le dernier contact
|
L'entrée est supprimée si elle n'a pas été consultée ou modifiée dans le délai d'expiration spécifié.
|
|
Nom du service
|
Description
|
|---|---|
|
PutEntry
|
• Ajoute une entrée au cache.
• Valeur d'entrée : table d'informations d'une ligne utilisant la forme de données configurée de l'objet cache.
|
|
GetEntry
|
• Renvoie un résultat de table d'informations d'une ligne issu du cache.
• Si l'entrée est introuvable (cache manquant) et que le cache n'est pas configuré avec l'option Cache Performs Loading of Missing Entries, une table d'informations vide est renvoyée. Si le cache est configuré avec cette option, le service LoadEntry est appelé automatiquement et son résultat est renvoyé.
• Des échecs de cache peuvent se produire si l'entrée n'a jamais été ajoutée au cache, a été supprimée ou a expiré.
• Valeur d'entrée : table d'informations d'une ligne utilisant la forme de données configurée de l'objet cache. Seules les valeurs Primary Key doivent être renseignées.
|
|
GetEntryByKey
|
• Renvoie un résultat de table d'informations d'une ligne issu du cache.
• Si l'entrée est introuvable, une table d'informations vide est renvoyée. Des échecs de cache peuvent se produire si l'entrée n'a jamais été ajoutée au cache, a été supprimée ou a expiré.
• Valeur d'entrée : chaîne représentant la clé primaire de l'entrée en cours de récupération. Ce service n'est disponible que si la forme de données possède une clé primaire unique. Il fonctionne mieux avec des clés primaires de type chaîne, mais prend également en charge la plupart des types avec une conversion de chaîne claire.
|
|
LoadEntry
|
• Utilisé pour récupérer automatiquement les données de cache à partir de la source de données en cas de cache manquant.
• Ce service doit être remplacé si l'option Cache Performs Loading of Missing Entries est activée.
|
|
DeleteEntry
|
• Supprime une entrée du cache.
• Dans un environnement haute disponibilité, cela affecte uniquement le noeud sur lequel le service DeleteEntry est appelé.
• Valeur d'entrée : table d'informations d'une ligne utilisant la forme de données configurée de l'objet cache. Seules les valeurs Primary Key doivent être renseignées.
|
|
DeleteEntryByKey
|
• Supprime une entrée du cache.
• Dans un environnement haute disponibilité, cela affecte uniquement le noeud sur lequel le service DeleteEntryByKey est appelé.
• Valeur d'entrée : chaîne représentant la clé primaire de l'entrée en cours de récupération. Ce service n'est disponible que si la forme de données possède une clé primaire unique.
|
|
PurgeCache
|
• Supprime toutes les entrées du cache.
• Dans un environnement haute disponibilité, cela affecte uniquement le noeud sur lequel le service PurgeCache est appelé.
|
|
GetDataShape
|
Renvoie la forme de données configurée du cache.
|
|
SetDataShape
|
Définit le champ de la forme de données dans la table de configuration du cache. Si vous modifiez cette valeur, le cache sera automatiquement purgé.
|
|
GetEstimatedEntryCount
|
Renvoie le nombre estimé d'entrées dans le cache. Les opérations PUT et DELETE en cours, ainsi que les processus d'expiration ou d'éviction, peuvent affecter la précision.
|
|
EstimateEntrySize
|
• Renvoie la taille estimée d'une entrée si elle a été ajoutée au cache. Cette opération n'insère pas l'entrée dans le cache et ne nécessite aucune entrée déjà existante dans le cache. Ce service peut être utile pour estimer une Taille maximale du cache (Mo) ou pour empêcher l'ajout d'entrées volumineuses dans le cache.
• Valeur d'entrée : table d'informations d'une ligne utilisant la forme de données configurée de l'objet cache.
|
|
Mesures de cache
|
Description
|
|---|---|
|
thingworx_cache_hit_rate
|
Ratio de requêtes en cache ayant abouti à la détection d'une entrée dans le cache
|
|
thingworx_cache_hits
|
Nombre de fois où les méthodes de consultation du cache ont renvoyé une valeur mise en cache
|
|
thingworx_cache_request_count
|
Nombre de fois où les méthodes de consultation du cache ont renvoyé une valeur mise en cache ou non mise en cache
|
|
thingworx_cache_miss_rate
|
Ratio des méthodes de consultation du cache ayant renvoyé une valeur non mise en cache (nouvellement chargée) ou une valeur nulle
|
|
thingworx_cache_misses
|
Nombre de fois où les méthodes de consultation du cache ont renvoyé une valeur non mise en cache (nouvellement chargée) ou une valeur nulle
|
|
thingworx_cache_eviction_count
|
Nombre de fois qu'une entrée a été évincée
|
|
thingworx_cache_average_load_penalty
|
Temps moyen de chargement des nouvelles valeurs
|
|
thingworx_cache_weighted_size
|
Taille actuelle approximative du cache en octets
|
|
thingworx_cache_max_weight
|
Taille maximale du cache en octets avant éviction
|
|
thingworx_cache_estimated_entry_count
|
Estimation du nombre d'entrées dans le cache
|
|
thingworx_cache_global_max_size
|
Taille maximale globale configurée pour tous les caches en octets
|
// 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;
Ce service renseigne automatiquement les données de démonstration dans la table de données dans la plage de dates interrogée. |
/* 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);
}