ua_historydatabackend_memory.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  4. *
  5. * Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
  6. */
  7. #include "ua_historydatabackend_memory.h"
  8. #include <limits.h>
  9. #include <string.h>
  10. typedef struct {
  11. UA_DateTime timestamp;
  12. UA_DataValue value;
  13. } UA_DataValueMemoryStoreItem;
  14. static void
  15. UA_DataValueMemoryStoreItem_deleteMembers(UA_DataValueMemoryStoreItem* item) {
  16. UA_DateTime_deleteMembers(&item->timestamp);
  17. UA_DataValue_deleteMembers(&item->value);
  18. }
  19. typedef struct {
  20. UA_NodeId nodeId;
  21. UA_DataValueMemoryStoreItem **dataStore;
  22. size_t storeEnd;
  23. size_t storeSize;
  24. } UA_NodeIdStoreContextItem_backend_memory;
  25. static void
  26. UA_NodeIdStoreContextItem_deleteMembers(UA_NodeIdStoreContextItem_backend_memory* item) {
  27. UA_NodeId_deleteMembers(&item->nodeId);
  28. for (size_t i = 0; i < item->storeEnd; ++i) {
  29. UA_DataValueMemoryStoreItem_deleteMembers(item->dataStore[i]);
  30. UA_free(item->dataStore[i]);
  31. }
  32. UA_free(item->dataStore);
  33. }
  34. typedef struct {
  35. UA_NodeIdStoreContextItem_backend_memory *dataStore;
  36. size_t storeEnd;
  37. size_t storeSize;
  38. size_t initialStoreSize;
  39. } UA_MemoryStoreContext;
  40. static void
  41. UA_MemoryStoreContext_deleteMembers(UA_MemoryStoreContext* ctx) {
  42. for (size_t i = 0; i < ctx->storeEnd; ++i) {
  43. UA_NodeIdStoreContextItem_deleteMembers(&ctx->dataStore[i]);
  44. }
  45. UA_free(ctx->dataStore);
  46. memset(ctx, 0, sizeof(UA_MemoryStoreContext));
  47. }
  48. static UA_NodeIdStoreContextItem_backend_memory *
  49. getNewNodeIdContext_backend_memory(UA_MemoryStoreContext* context,
  50. UA_Server *server,
  51. const UA_NodeId *nodeId) {
  52. UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext*)context;
  53. if (ctx->storeEnd >= ctx->storeSize) {
  54. size_t newStoreSize = ctx->storeSize * 2;
  55. if (newStoreSize == 0)
  56. return NULL;
  57. ctx->dataStore = (UA_NodeIdStoreContextItem_backend_memory*)UA_realloc(ctx->dataStore, (newStoreSize * sizeof(UA_NodeIdStoreContextItem_backend_memory)));
  58. if (!ctx->dataStore) {
  59. ctx->storeSize = 0;
  60. return NULL;
  61. }
  62. ctx->storeSize = newStoreSize;
  63. }
  64. UA_NodeIdStoreContextItem_backend_memory *item = &ctx->dataStore[ctx->storeEnd];
  65. UA_NodeId_copy(nodeId, &item->nodeId);
  66. UA_DataValueMemoryStoreItem ** store = (UA_DataValueMemoryStoreItem **)UA_calloc(ctx->initialStoreSize, sizeof(UA_DataValueMemoryStoreItem*));
  67. if (!store) {
  68. UA_NodeIdStoreContextItem_deleteMembers(item);
  69. return NULL;
  70. }
  71. item->dataStore = store;
  72. item->storeSize = ctx->initialStoreSize;
  73. item->storeEnd = 0;
  74. ++ctx->storeEnd;
  75. return item;
  76. }
  77. static UA_NodeIdStoreContextItem_backend_memory *
  78. getNodeIdStoreContextItem_backend_memory(UA_MemoryStoreContext* context,
  79. UA_Server *server,
  80. const UA_NodeId *nodeId)
  81. {
  82. for (size_t i = 0; i < context->storeEnd; ++i) {
  83. if (UA_NodeId_equal(nodeId, &context->dataStore[i].nodeId)) {
  84. return &context->dataStore[i];
  85. }
  86. }
  87. return getNewNodeIdContext_backend_memory(context, server, nodeId);
  88. }
  89. static UA_Boolean
  90. binarySearch_backend_memory(const UA_NodeIdStoreContextItem_backend_memory* item,
  91. const UA_DateTime timestamp,
  92. size_t *index) {
  93. if (item->storeEnd == 0) {
  94. *index = item->storeEnd;
  95. return false;
  96. }
  97. size_t min = 0;
  98. size_t max = item->storeEnd - 1;
  99. while (min <= max) {
  100. *index = (min + max) / 2;
  101. if (item->dataStore[*index]->timestamp == timestamp) {
  102. return true;
  103. } else if (item->dataStore[*index]->timestamp < timestamp) {
  104. if (*index == item->storeEnd - 1) {
  105. *index = item->storeEnd;
  106. return false;
  107. }
  108. min = *index + 1;
  109. } else {
  110. if (*index == 0)
  111. return false;
  112. max = *index - 1;
  113. }
  114. }
  115. *index = min;
  116. return false;
  117. }
  118. static size_t
  119. resultSize_backend_memory(UA_Server *server,
  120. void *context,
  121. const UA_NodeId *sessionId,
  122. void *sessionContext,
  123. const UA_NodeId * nodeId,
  124. size_t startIndex,
  125. size_t endIndex) {
  126. const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
  127. if (item->storeEnd == 0
  128. || startIndex == item->storeEnd
  129. || endIndex == item->storeEnd)
  130. return 0;
  131. return endIndex - startIndex + 1;
  132. }
  133. static size_t
  134. getDateTimeMatch_backend_memory(UA_Server *server,
  135. void *context,
  136. const UA_NodeId *sessionId,
  137. void *sessionContext,
  138. const UA_NodeId * nodeId,
  139. const UA_DateTime timestamp,
  140. const MatchStrategy strategy) {
  141. const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
  142. size_t current;
  143. UA_Boolean retval = binarySearch_backend_memory(item, timestamp, &current);
  144. if ((strategy == MATCH_EQUAL
  145. || strategy == MATCH_EQUAL_OR_AFTER
  146. || strategy == MATCH_EQUAL_OR_BEFORE)
  147. && retval)
  148. return current;
  149. switch (strategy) {
  150. case MATCH_AFTER:
  151. if (retval)
  152. return current+1;
  153. return current;
  154. case MATCH_EQUAL_OR_AFTER:
  155. return current;
  156. case MATCH_EQUAL_OR_BEFORE:
  157. // retval == true aka "equal" is handled before
  158. // Fall through if !retval
  159. case MATCH_BEFORE:
  160. if (current > 0)
  161. return current-1;
  162. else
  163. return item->storeEnd;
  164. default:
  165. break;
  166. }
  167. return item->storeEnd;
  168. }
  169. static UA_StatusCode
  170. serverSetHistoryData_backend_memory(UA_Server *server,
  171. void *context,
  172. const UA_NodeId *sessionId,
  173. void *sessionContext,
  174. const UA_NodeId * nodeId,
  175. UA_Boolean historizing,
  176. const UA_DataValue *value)
  177. {
  178. UA_NodeIdStoreContextItem_backend_memory *item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);
  179. if (item->storeEnd >= item->storeSize) {
  180. size_t newStoreSize = item->storeSize == 0 ? INITIAL_MEMORY_STORE_SIZE : item->storeSize * 2;
  181. item->dataStore = (UA_DataValueMemoryStoreItem **)UA_realloc(item->dataStore, (newStoreSize * sizeof(UA_DataValueMemoryStoreItem*)));
  182. if (!item->dataStore) {
  183. item->storeSize = 0;
  184. return UA_STATUSCODE_BADOUTOFMEMORY;
  185. }
  186. item->storeSize = newStoreSize;
  187. }
  188. UA_DateTime timestamp = 0;
  189. if (value->hasSourceTimestamp) {
  190. timestamp = value->sourceTimestamp;
  191. } else if (value->hasServerTimestamp) {
  192. timestamp = value->serverTimestamp;
  193. } else {
  194. timestamp = UA_DateTime_now();
  195. }
  196. UA_DataValueMemoryStoreItem *newItem = (UA_DataValueMemoryStoreItem *)UA_calloc(1, sizeof(UA_DataValueMemoryStoreItem));
  197. newItem->timestamp = timestamp;
  198. UA_DataValue_copy(value, &newItem->value);
  199. size_t index = getDateTimeMatch_backend_memory(server,
  200. context,
  201. NULL,
  202. NULL,
  203. nodeId,
  204. timestamp,
  205. MATCH_EQUAL_OR_AFTER);
  206. if (item->storeEnd > 0 && index < item->storeEnd) {
  207. memmove(&item->dataStore[index+1], &item->dataStore[index], sizeof(UA_DataValueMemoryStoreItem*) * (item->storeEnd - index));
  208. }
  209. item->dataStore[index] = newItem;
  210. ++item->storeEnd;
  211. return UA_STATUSCODE_GOOD;
  212. }
  213. static void
  214. UA_MemoryStoreContext_delete(UA_MemoryStoreContext* ctx) {
  215. UA_MemoryStoreContext_deleteMembers(ctx);
  216. UA_free(ctx);
  217. }
  218. static size_t
  219. getEnd_backend_memory(UA_Server *server,
  220. void *context,
  221. const UA_NodeId *sessionId,
  222. void *sessionContext,
  223. const UA_NodeId * nodeId) {
  224. const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);;
  225. return item->storeEnd;
  226. }
  227. static size_t
  228. lastIndex_backend_memory(UA_Server *server,
  229. void *context,
  230. const UA_NodeId *sessionId,
  231. void *sessionContext,
  232. const UA_NodeId * nodeId) {
  233. const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);;
  234. return item->storeEnd - 1;
  235. }
  236. static size_t
  237. firstIndex_backend_memory(UA_Server *server,
  238. void *context,
  239. const UA_NodeId *sessionId,
  240. void *sessionContext,
  241. const UA_NodeId * nodeId) {
  242. return 0;
  243. }
  244. static UA_Boolean
  245. boundSupported_backend_memory(UA_Server *server,
  246. void *context,
  247. const UA_NodeId *sessionId,
  248. void *sessionContext,
  249. const UA_NodeId * nodeId) {
  250. return true;
  251. }
  252. static UA_Boolean
  253. timestampsToReturnSupported_backend_memory(UA_Server *server,
  254. void *context,
  255. const UA_NodeId *sessionId,
  256. void *sessionContext,
  257. const UA_NodeId *nodeId,
  258. const UA_TimestampsToReturn timestampsToReturn) {
  259. const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);;
  260. if (item->storeEnd == 0) {
  261. return true;
  262. }
  263. if (timestampsToReturn == UA_TIMESTAMPSTORETURN_NEITHER
  264. || timestampsToReturn == UA_TIMESTAMPSTORETURN_INVALID
  265. || (timestampsToReturn == UA_TIMESTAMPSTORETURN_SERVER
  266. && !item->dataStore[0]->value.hasServerTimestamp)
  267. || (timestampsToReturn == UA_TIMESTAMPSTORETURN_SOURCE
  268. && !item->dataStore[0]->value.hasSourceTimestamp)
  269. || (timestampsToReturn == UA_TIMESTAMPSTORETURN_BOTH
  270. && !(item->dataStore[0]->value.hasSourceTimestamp
  271. && item->dataStore[0]->value.hasServerTimestamp))) {
  272. return false;
  273. }
  274. return true;
  275. }
  276. static const UA_DataValue*
  277. getDataValue_backend_memory(UA_Server *server,
  278. void *context,
  279. const UA_NodeId *sessionId,
  280. void *sessionContext,
  281. const UA_NodeId * nodeId, size_t index) {
  282. const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);;
  283. return &item->dataStore[index]->value;
  284. }
  285. static UA_StatusCode
  286. UA_DataValue_backend_copyRange(const UA_DataValue *src, UA_DataValue *dst,
  287. const UA_NumericRange range)
  288. {
  289. memcpy(dst, src, sizeof(UA_DataValue));
  290. if (src->hasValue)
  291. return UA_Variant_copyRange(&src->value, &dst->value, range);
  292. return UA_STATUSCODE_BADDATAUNAVAILABLE;
  293. }
  294. static UA_StatusCode
  295. copyDataValues_backend_memory(UA_Server *server,
  296. void *context,
  297. const UA_NodeId *sessionId,
  298. void *sessionContext,
  299. const UA_NodeId * nodeId,
  300. size_t startIndex,
  301. size_t endIndex,
  302. UA_Boolean reverse,
  303. size_t maxValues,
  304. UA_NumericRange range,
  305. UA_Boolean releaseContinuationPoints,
  306. const UA_ByteString *continuationPoint,
  307. UA_ByteString *outContinuationPoint,
  308. size_t * providedValues,
  309. UA_DataValue * values)
  310. {
  311. size_t skip = 0;
  312. if (continuationPoint->length > 0) {
  313. if (continuationPoint->length == sizeof(size_t)) {
  314. skip = *((size_t*)(continuationPoint->data));
  315. } else {
  316. return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
  317. }
  318. }
  319. const UA_NodeIdStoreContextItem_backend_memory* item = getNodeIdStoreContextItem_backend_memory((UA_MemoryStoreContext*)context, server, nodeId);;
  320. size_t index = startIndex;
  321. size_t counter = 0;
  322. size_t skipedValues = 0;
  323. if (reverse) {
  324. while (index >= endIndex && index < item->storeEnd && counter < maxValues) {
  325. if (skipedValues++ >= skip) {
  326. if (range.dimensionsSize > 0) {
  327. UA_DataValue_backend_copyRange(&item->dataStore[index]->value, &values[counter], range);
  328. } else {
  329. UA_DataValue_copy(&item->dataStore[index]->value, &values[counter]);
  330. }
  331. ++counter;
  332. }
  333. --index;
  334. }
  335. } else {
  336. while (index <= endIndex && counter < maxValues) {
  337. if (skipedValues++ >= skip) {
  338. if (range.dimensionsSize > 0) {
  339. UA_DataValue_backend_copyRange(&item->dataStore[index]->value, &values[counter], range);
  340. } else {
  341. UA_DataValue_copy(&item->dataStore[index]->value, &values[counter]);
  342. }
  343. ++counter;
  344. }
  345. ++index;
  346. }
  347. }
  348. if (providedValues)
  349. *providedValues = counter;
  350. if ((!reverse && (endIndex-startIndex-skip+1) > counter) || (reverse && (startIndex-endIndex-skip+1) > counter)) {
  351. outContinuationPoint->length = sizeof(size_t);
  352. size_t t = sizeof(size_t);
  353. outContinuationPoint->data = (UA_Byte*)UA_malloc(t);
  354. *((size_t*)(outContinuationPoint->data)) = skip + counter;
  355. }
  356. return UA_STATUSCODE_GOOD;
  357. }
  358. static void
  359. deleteMembers_backend_memory(UA_HistoryDataBackend *backend)
  360. {
  361. if (backend == NULL || backend->context == NULL)
  362. return;
  363. UA_MemoryStoreContext_deleteMembers((UA_MemoryStoreContext*)backend->context);
  364. }
  365. UA_HistoryDataBackend
  366. UA_HistoryDataBackend_Memory(size_t initialNodeIdStoreSize, size_t initialDataStoreSize) {
  367. if (initialNodeIdStoreSize == 0)
  368. initialNodeIdStoreSize = 1;
  369. if (initialDataStoreSize == 0)
  370. initialDataStoreSize = 1;
  371. UA_HistoryDataBackend result;
  372. memset(&result, 0, sizeof(UA_HistoryDataBackend));
  373. UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext *)UA_calloc(1, sizeof(UA_MemoryStoreContext));
  374. if (!ctx)
  375. return result;
  376. ctx->dataStore = (UA_NodeIdStoreContextItem_backend_memory*)UA_calloc(initialNodeIdStoreSize, sizeof(UA_NodeIdStoreContextItem_backend_memory));
  377. ctx->initialStoreSize = initialDataStoreSize;
  378. ctx->storeSize = initialNodeIdStoreSize;
  379. ctx->storeEnd = 0;
  380. result.serverSetHistoryData = &serverSetHistoryData_backend_memory;
  381. result.resultSize = &resultSize_backend_memory;
  382. result.getEnd = &getEnd_backend_memory;
  383. result.lastIndex = &lastIndex_backend_memory;
  384. result.firstIndex = &firstIndex_backend_memory;
  385. result.getDateTimeMatch = &getDateTimeMatch_backend_memory;
  386. result.copyDataValues = &copyDataValues_backend_memory;
  387. result.getDataValue = &getDataValue_backend_memory;
  388. result.boundSupported = &boundSupported_backend_memory;
  389. result.timestampsToReturnSupported = &timestampsToReturnSupported_backend_memory;
  390. result.deleteMembers = deleteMembers_backend_memory;
  391. result.getHistoryData = NULL;
  392. result.context = ctx;
  393. return result;
  394. }
  395. void
  396. UA_HistoryDataBackend_Memory_deleteMembers(UA_HistoryDataBackend *backend)
  397. {
  398. UA_MemoryStoreContext *ctx = (UA_MemoryStoreContext*)backend->context;
  399. UA_MemoryStoreContext_delete(ctx);
  400. memset(backend, 0, sizeof(UA_HistoryDataBackend));
  401. }