cds-caching 1.2.1 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +195 -1114
  2. package/app/dashboard/Component-dbg.js +59 -0
  3. package/app/dashboard/Component-dbg.js.map +1 -0
  4. package/app/dashboard/Component.js +2 -0
  5. package/app/dashboard/Component.js.map +1 -0
  6. package/app/dashboard/Component.ts +59 -0
  7. package/app/dashboard/controller/App-dbg.controller.js +132 -0
  8. package/app/dashboard/controller/App-dbg.controller.js.map +1 -0
  9. package/app/dashboard/controller/App.controller.js +2 -0
  10. package/app/dashboard/controller/App.controller.js.map +1 -0
  11. package/app/dashboard/controller/App.controller.ts +147 -0
  12. package/app/dashboard/controller/BaseController-dbg.js +75 -0
  13. package/app/dashboard/controller/BaseController-dbg.js.map +1 -0
  14. package/app/dashboard/controller/BaseController.js +2 -0
  15. package/app/dashboard/controller/BaseController.js.map +1 -0
  16. package/app/dashboard/controller/BaseController.ts +88 -0
  17. package/app/dashboard/controller/Cache-dbg.controller.js +421 -0
  18. package/app/dashboard/controller/Cache-dbg.controller.js.map +1 -0
  19. package/app/dashboard/controller/Cache.controller.js +2 -0
  20. package/app/dashboard/controller/Cache.controller.js.map +1 -0
  21. package/app/dashboard/controller/Cache.controller.ts +490 -0
  22. package/app/dashboard/controller/Main-dbg.controller.js +32 -0
  23. package/app/dashboard/controller/Main-dbg.controller.js.map +1 -0
  24. package/app/dashboard/controller/Main.controller.js +2 -0
  25. package/app/dashboard/controller/Main.controller.js.map +1 -0
  26. package/app/dashboard/controller/Main.controller.ts +31 -0
  27. package/app/dashboard/controller/SingleMetric-dbg.controller.js +306 -0
  28. package/app/dashboard/controller/SingleMetric-dbg.controller.js.map +1 -0
  29. package/app/dashboard/controller/SingleMetric.controller.js +2 -0
  30. package/app/dashboard/controller/SingleMetric.controller.js.map +1 -0
  31. package/app/dashboard/controller/SingleMetric.controller.ts +335 -0
  32. package/app/dashboard/i18n/i18n.properties +61 -0
  33. package/app/dashboard/i18n/i18n_de.properties +3 -0
  34. package/app/dashboard/i18n/i18n_en.properties +3 -0
  35. package/app/dashboard/index-cdn.html +28 -0
  36. package/app/dashboard/index.html +19 -0
  37. package/app/dashboard/manifest.json +145 -0
  38. package/app/dashboard/model/formatter-dbg.js +253 -0
  39. package/app/dashboard/model/formatter-dbg.js.map +1 -0
  40. package/app/dashboard/model/formatter.js +2 -0
  41. package/app/dashboard/model/formatter.js.map +1 -0
  42. package/app/dashboard/model/formatter.ts +275 -0
  43. package/app/dashboard/model/models-dbg.js +13 -0
  44. package/app/dashboard/model/models-dbg.js.map +1 -0
  45. package/app/dashboard/model/models.js +2 -0
  46. package/app/dashboard/model/models.js.map +1 -0
  47. package/app/dashboard/model/models.ts +13 -0
  48. package/app/dashboard/resources/sap-ui-custom-dbg.js +4695 -0
  49. package/app/dashboard/resources/sap-ui-custom-dbg.js.map +1 -0
  50. package/app/dashboard/resources/sap-ui-custom.js +5794 -0
  51. package/app/dashboard/resources/sap-ui-custom.js.map +1 -0
  52. package/app/dashboard/service/CacheStatisticsService-dbg.js +267 -0
  53. package/app/dashboard/service/CacheStatisticsService-dbg.js.map +1 -0
  54. package/app/dashboard/service/CacheStatisticsService.js +2 -0
  55. package/app/dashboard/service/CacheStatisticsService.js.map +1 -0
  56. package/app/dashboard/service/CacheStatisticsService.ts +397 -0
  57. package/app/dashboard/view/App.view.xml +18 -0
  58. package/app/dashboard/view/Cache.view.xml +777 -0
  59. package/app/dashboard/view/Main.view.xml +57 -0
  60. package/app/dashboard/view/SingleMetric.view.xml +337 -0
  61. package/cds-plugin.js +52 -0
  62. package/db/cache-store.cds +12 -0
  63. package/db/statistics.cds +128 -0
  64. package/index.cds +2 -128
  65. package/lib/CachingService.js +13 -0
  66. package/lib/add.js +17 -0
  67. package/lib/operations/AsyncOperations.js +162 -111
  68. package/lib/operations/BasicOperations.js +35 -0
  69. package/lib/operations/CapOperations.js +92 -40
  70. package/lib/support/CacheStatisticsHandler.js +35 -10
  71. package/lib/support/CacheStoreManager.js +29 -0
  72. package/lib/support/KeyvCDS.js +149 -0
  73. package/lib/support/MultitenancyDetector.js +25 -0
  74. package/lib/support/RuntimeConfigurationManager.js +69 -37
  75. package/lib/support/StatisticsPersistenceManager.js +18 -2
  76. package/lib/support/Telemetry.js +137 -0
  77. package/lib/util.js +29 -11
  78. package/package.json +43 -11
  79. package/srv/caching-api-service.js +47 -2
@@ -0,0 +1,57 @@
1
+ <mvc:View controllerName="cds.plugin.caching.dashboard.controller.Main" displayBlock="true"
2
+ xmlns="sap.m"
3
+ xmlns:mvc="sap.ui.core.mvc"
4
+ xmlns:core="sap.ui.core"
5
+ xmlns:l="sap.ui.layout"
6
+ xmlns:f="sap.f"
7
+ xmlns:fb="sap.ui.comp.filterbar"
8
+ xmlns:card="sap.f.cards"
9
+ xmlns:cssgrid="sap.ui.layout.cssgrid"
10
+ xmlns:viz="sap.viz.ui5.controls"
11
+ xmlns:viz.feeds="sap.viz.ui5.controls.common.feeds"
12
+ xmlns:viz.data="sap.viz.ui5.data" core:require="{
13
+ formatter: 'cds/plugin/caching/dashboard/model/formatter'
14
+ }">
15
+
16
+ <f:DynamicPage title="cds-caching – Dashboard" headerExpanded="true" headerPinned="true">
17
+ <f:title>
18
+ <f:DynamicPageTitle>
19
+ <f:heading>
20
+ <Title text="cds-caching – Dashboard" />
21
+ </f:heading>
22
+ <f:actions>
23
+ <Button type="Transparent" icon="sap-icon://refresh" text="Refresh" press="onRefresh" />
24
+ </f:actions>
25
+ </f:DynamicPageTitle>
26
+ </f:title>
27
+
28
+ <f:content>
29
+
30
+ <Table id="cachesList" headerText="Caching Services" mode="SingleSelectMaster" items="{path: '/Caches'}" itemPress="onCacheSelect" noDataText="No caches available">
31
+ <columns>
32
+ <Column>
33
+ <Text text="Name" />
34
+ </Column>
35
+ <Column>
36
+ <Text text="Statistic Tracking Enabled" />
37
+ </Column>
38
+ <Column>
39
+ <Text text="Key Tracking Enabled" />
40
+ </Column>
41
+ </columns>
42
+ <items>
43
+ <ColumnListItem type="Navigation">
44
+ <cells>
45
+ <Text text="{name}" />
46
+ <Text text="{path: 'metricsEnabled' }" />
47
+ <Text text="{path: 'keyMetricsEnabled' }" />
48
+ </cells>
49
+
50
+ </ColumnListItem>
51
+ </items>
52
+ </Table>
53
+ </f:content>
54
+
55
+ </f:DynamicPage>
56
+
57
+ </mvc:View>
@@ -0,0 +1,337 @@
1
+ <mvc:View controllerName="cds.plugin.caching.dashboard.controller.SingleMetric"
2
+ xmlns="sap.m"
3
+ xmlns:mvc="sap.ui.core.mvc"
4
+ xmlns:core="sap.ui.core"
5
+ xmlns:l="sap.ui.layout"
6
+ xmlns:f="sap.f"
7
+ xmlns:fb="sap.ui.comp.filterbar"
8
+ xmlns:card="sap.f.cards"
9
+ xmlns:cssgrid="sap.ui.layout.cssgrid"
10
+ xmlns:viz="sap.viz.ui5.controls"
11
+ xmlns:viz.feeds="sap.viz.ui5.controls.common.feeds"
12
+ xmlns:viz.data="sap.viz.ui5.data"
13
+ xmlns:form="sap.ui.layout.form" core:require="{
14
+ formatter: 'cds/plugin/caching/dashboard/model/formatter'
15
+ }">
16
+
17
+ <f:DynamicPage title="Metric Details" showFooter="false">
18
+ <f:title>
19
+ <f:DynamicPageTitle>
20
+ <f:heading>
21
+ <Title text="Metric: {ui>/metricId}" />
22
+ </f:heading>
23
+ <f:actions>
24
+ <Button icon="sap-icon://refresh" text="Refresh" type="Transparent" press="onRefresh" />
25
+ </f:actions>
26
+ <f:navigationActions>
27
+ <OverflowToolbarButton type="Transparent" icon="sap-icon://full-screen" press="handleFullScreen" tooltip="Enter Full Screen Mode" visible="{= ${app>/layout} !== 'EndColumnFullScreen' }"/>
28
+ <OverflowToolbarButton type="Transparent" icon="sap-icon://exit-full-screen" press="handleExitFullScreen" tooltip="Exit Full Screen Mode" visible="{= ${app>/layout} === 'EndColumnFullScreen' }"/>
29
+ <OverflowToolbarButton type="Transparent" icon="sap-icon://decline" press="handleClose" tooltip="Close end column"/>
30
+ </f:navigationActions>
31
+ </f:DynamicPageTitle>
32
+ </f:title>
33
+
34
+ <f:content>
35
+ <cssgrid:CSSGrid id="metricMainGrid" width="100%">
36
+ <cssgrid:customLayout>
37
+ <cssgrid:ResponsiveColumnLayout />
38
+ </cssgrid:customLayout>
39
+
40
+ <!-- Read-Through Performance Section -->
41
+ <VBox renderType="Bare">
42
+ <layoutData>
43
+ <cssgrid:ResponsiveColumnItemLayoutData columns="24"/>
44
+ </layoutData>
45
+
46
+ <Title text="Read-Through Performance" titleStyle="H5" class="sapUiMediumMarginTop sapUiTinyMarginBottom" />
47
+
48
+ <f:GridContainer id="metricCacheThroughGrid" columnsChange=".onColumnsChange">
49
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Hit Ratio" subheader="Cache Hit Rate">
50
+ <TileContent unit="%">
51
+ <NumericContent valueColor="{formatter: 'formatter.formatHitRatioWithColor', path: 'ui>/hitRatio'}" value="{ path: 'ui>/hitRatio', type: 'sap.ui.model.type.Float', formatOptions: {style: 'short', decimals: 2}}" />
52
+ </TileContent>
53
+ <layoutData>
54
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
55
+ </layoutData>
56
+ </GenericTile>
57
+
58
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Cache Efficiency" subheader="Performance Factor">
59
+ <TileContent unit="x">
60
+ <NumericContent valueColor="{formatter: 'formatter.formatCacheEfficiencyWithColor', path: 'ui>/cacheEfficiency'}" value="{path: 'ui>/cacheEfficiency', type: 'sap.ui.model.type.Float', formatOptions: {style: 'short', decimals: 2}}" />
61
+ </TileContent>
62
+ <layoutData>
63
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
64
+ </layoutData>
65
+ </GenericTile>
66
+
67
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Throughput" subheader="Requests per Second">
68
+ <TileContent unit="req/s">
69
+ <NumericContent value="{ path: 'ui>/throughput', type: 'sap.ui.model.type.Float', formatOptions: {style: 'short', decimals: 2}}" withMargin="false" />
70
+ </TileContent>
71
+ <layoutData>
72
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
73
+ </layoutData>
74
+ </GenericTile>
75
+
76
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Error Rate" subheader="Cache Errors">
77
+ <TileContent unit="%">
78
+ <NumericContent valueColor="{formatter: 'formatter.formatErrorRateWithColor', path: 'ui>/errorRate'}" value="{ path: 'ui>/errorRate', formatter: 'formatter.formatPercentageValue' }" />
79
+ </TileContent>
80
+ <layoutData>
81
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
82
+ </layoutData>
83
+ </GenericTile>
84
+
85
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Total Requests" subheader="Cache Operations">
86
+ <TileContent unit="req">
87
+ <NumericContent value="{= ${ui>/hits} + ${ui>/misses}}" withMargin="false" />
88
+ </TileContent>
89
+ <layoutData>
90
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
91
+ </layoutData>
92
+ </GenericTile>
93
+
94
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Cache Hits" subheader="Successful Retrievals">
95
+ <TileContent unit="hits">
96
+ <NumericContent value="{ui>/hits}" withMargin="false" />
97
+ </TileContent>
98
+ <layoutData>
99
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
100
+ </layoutData>
101
+ </GenericTile>
102
+
103
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Cache Misses" subheader="Failed Retrievals">
104
+ <TileContent unit="misses">
105
+ <NumericContent value="{ui>/misses}" withMargin="false" />
106
+ </TileContent>
107
+ <layoutData>
108
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
109
+ </layoutData>
110
+ </GenericTile>
111
+
112
+
113
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Cache Errors" subheader="Error Count">
114
+ <TileContent unit="errors">
115
+ <NumericContent value="{ui>/errors}" withMargin="false" />
116
+ </TileContent>
117
+ <layoutData>
118
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
119
+ </layoutData>
120
+ </GenericTile>
121
+
122
+
123
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Hit Latency" subheader="Cache Hit Response">
124
+ <TileContent unit="ms">
125
+ <NumericContent valueColor="{formatter: 'formatter.formatLatencyWithColor', path: 'ui>/avgHitLatency'}" value="{ path: 'ui>/avgHitLatency', type: 'sap.ui.model.type.Float', formatOptions: {style: 'short', decimals: 2}}" />
126
+ </TileContent>
127
+ <layoutData>
128
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
129
+ </layoutData>
130
+ </GenericTile>
131
+
132
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Miss Latency" subheader="Cache Miss Response">
133
+ <TileContent unit="ms">
134
+ <NumericContent valueColor="{formatter: 'formatter.formatLatencyWithColor', path: 'ui>/avgMissLatency'}" value="{ path: 'ui>/avgMissLatency', type: 'sap.ui.model.type.Float', formatOptions: {style: 'short', decimals: 2}}" />
135
+ </TileContent>
136
+ <layoutData>
137
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
138
+ </layoutData>
139
+ </GenericTile>
140
+
141
+ <!-- Read-Through Distribution Chart -->
142
+ <f:Card class="sapUiTinyMargin">
143
+ <f:header>
144
+ <card:Header title="Read-Through Operations" subtitle="Hit/Miss/Error Distribution" />
145
+ </f:header>
146
+ <f:content>
147
+ <l:VerticalLayout width="100%">
148
+ <viz:Popover id="metricCacheThroughPopOver"></viz:Popover>
149
+ <viz:VizFrame id="metricCacheThroughChart" vizType="pie" width="100%" height="300px">
150
+ <viz:dataset>
151
+ <viz.data:FlattenedDataset data="{ui>/cacheThroughData}">
152
+ <viz.data:dimensions>
153
+ <viz.data:DimensionDefinition name="Operation" value="{operation}" />
154
+ </viz.data:dimensions>
155
+ <viz.data:measures>
156
+ <viz.data:MeasureDefinition name="Count" value="{count}" />
157
+ </viz.data:measures>
158
+ </viz.data:FlattenedDataset>
159
+ </viz:dataset>
160
+ <viz:feeds>
161
+ <viz.feeds:FeedItem id="metricCacheThroughValueAxisFeed" uid="size" type="Measure" values="Count" />
162
+ <viz.feeds:FeedItem id="metricCacheThroughCategoryAxisFeed" uid="color" type="Dimension" values="Operation" />
163
+ </viz:feeds>
164
+ </viz:VizFrame>
165
+ </l:VerticalLayout>
166
+ </f:content>
167
+ <f:layoutData>
168
+ <f:GridContainerItemLayoutData columns="4" minRows="4"/>
169
+ </f:layoutData>
170
+ </f:Card>
171
+
172
+
173
+
174
+
175
+ <!-- Latency Chart -->
176
+ <f:Card class="sapUiTinyMargin">
177
+ <f:header>
178
+ <card:Header title="Latency Comparison" subtitle="Read-Through Latency Metrics" />
179
+ </f:header>
180
+ <f:content>
181
+ <l:VerticalLayout width="100%">
182
+ <viz:Popover id="metricLatencyPopOver"></viz:Popover>
183
+ <viz:VizFrame id="metricLatencyChart" vizType="bar" width="100%" height="300px">
184
+ <viz:dataset>
185
+ <viz.data:FlattenedDataset data="{ui>/latencyData}">
186
+ <viz.data:dimensions>
187
+ <viz.data:DimensionDefinition name="Operation" value="{operation}" />
188
+ </viz.data:dimensions>
189
+ <viz.data:measures>
190
+ <viz.data:MeasureDefinition name="Latency" value="{latency}" />
191
+ </viz.data:measures>
192
+ </viz.data:FlattenedDataset>
193
+ </viz:dataset>
194
+ <viz:feeds>
195
+ <viz.feeds:FeedItem id="metricValueAxisFeed" uid="valueAxis" type="Measure" values="Latency" />
196
+ <viz.feeds:FeedItem id="metricCategoryAxisFeed" uid="categoryAxis" type="Dimension" values="Operation" />
197
+ </viz:feeds>
198
+ </viz:VizFrame>
199
+ </l:VerticalLayout>
200
+ </f:content>
201
+ <f:layoutData>
202
+ <f:GridContainerItemLayoutData columns="12" minRows="4"/>
203
+ </f:layoutData>
204
+ </f:Card>
205
+
206
+
207
+
208
+ </f:GridContainer>
209
+ </VBox>
210
+
211
+ <!-- Native Function Performance Section -->
212
+ <VBox renderType="Bare">
213
+ <layoutData>
214
+ <cssgrid:ResponsiveColumnItemLayoutData columns="24"/>
215
+ </layoutData>
216
+
217
+ <Title text="Native Function Performance" titleStyle="H5" class="sapUiMediumMarginTop sapUiTinyMarginBottom" />
218
+
219
+ <f:GridContainer id="metricNativeGrid" columnsChange=".onColumnsChange">
220
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Native Throughput" subheader="Operations per Second">
221
+ <TileContent unit="ops/s">
222
+ <NumericContent value="{ path: 'ui>/nativeThroughput', formatter: 'formatter.formatNumberValue' }" withMargin="false" />
223
+ </TileContent>
224
+ <layoutData>
225
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
226
+ </layoutData>
227
+ </GenericTile>
228
+
229
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Native Error Rate" subheader="Native Function Errors">
230
+ <TileContent unit="%">
231
+ <NumericContent valueColor="{formatter: 'formatter.formatErrorRateWithColor', path: 'ui>/nativeErrorRate'}" value="{ path: 'ui>/nativeErrorRate', formatter: 'formatter.formatPercentageValue' }" />
232
+ </TileContent>
233
+ <layoutData>
234
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
235
+ </layoutData>
236
+ </GenericTile>
237
+
238
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Native Sets" subheader="Write Operations">
239
+ <TileContent unit="sets">
240
+ <NumericContent value="{ui>/nativeSets}" withMargin="false" />
241
+ </TileContent>
242
+ <layoutData>
243
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
244
+ </layoutData>
245
+ </GenericTile>
246
+
247
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Native Gets" subheader="Read Operations">
248
+ <TileContent unit="gets">
249
+ <NumericContent value="{ui>/nativeGets}" withMargin="false" />
250
+ </TileContent>
251
+ <layoutData>
252
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
253
+ </layoutData>
254
+ </GenericTile>
255
+
256
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Native Deletes" subheader="Delete Operations">
257
+ <TileContent unit="deletes">
258
+ <NumericContent value="{ui>/nativeDeletes}" withMargin="false" />
259
+ </TileContent>
260
+ <layoutData>
261
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
262
+ </layoutData>
263
+ </GenericTile>
264
+
265
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Native Clears" subheader="Clear Operations">
266
+ <TileContent unit="clears">
267
+ <NumericContent value="{ui>/nativeClears}" withMargin="false" />
268
+ </TileContent>
269
+ <layoutData>
270
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
271
+ </layoutData>
272
+ </GenericTile>
273
+
274
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Delete By Tags" subheader="Tag-based Deletes">
275
+ <TileContent unit="deletes">
276
+ <NumericContent value="{ui>/nativeDeleteByTags}" withMargin="false" />
277
+ </TileContent>
278
+ <layoutData>
279
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
280
+ </layoutData>
281
+ </GenericTile>
282
+
283
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Native Errors" subheader="Error Count">
284
+ <TileContent unit="errors">
285
+ <NumericContent value="{ui>/nativeErrors}" withMargin="false" />
286
+ </TileContent>
287
+ <layoutData>
288
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
289
+ </layoutData>
290
+ </GenericTile>
291
+
292
+ <GenericTile class="sapUiTinyMarginBegin sapUiTinyMarginTop tileLayout" header="Total Native Ops" subheader="All Operations">
293
+ <TileContent unit="ops">
294
+ <NumericContent value="{ui>/totalNativeOperations}" withMargin="false" />
295
+ </TileContent>
296
+ <layoutData>
297
+ <f:GridContainerItemLayoutData columns="2" minRows="2"/>
298
+ </layoutData>
299
+ </GenericTile>
300
+ <!-- Native Function Distribution Chart -->
301
+ <f:Card class="sapUiTinyMargin">
302
+ <f:header>
303
+ <card:Header title="Native Function Operations" subtitle="Hit/Miss/Error Distribution" />
304
+ </f:header>
305
+ <f:content>
306
+ <l:VerticalLayout width="100%">
307
+ <viz:Popover id="metricNativePopOver"></viz:Popover>
308
+ <viz:VizFrame id="metricNativeChart" vizType="pie" width="100%" height="300px">
309
+ <viz:dataset>
310
+ <viz.data:FlattenedDataset data="{ui>/nativeData}">
311
+ <viz.data:dimensions>
312
+ <viz.data:DimensionDefinition name="Operation" value="{operation}" />
313
+ </viz.data:dimensions>
314
+ <viz.data:measures>
315
+ <viz.data:MeasureDefinition name="Count" value="{count}" />
316
+ </viz.data:measures>
317
+ </viz.data:FlattenedDataset>
318
+ </viz:dataset>
319
+ <viz:feeds>
320
+ <viz.feeds:FeedItem id="metricNativeValueAxisFeed" uid="size" type="Measure" values="Count" />
321
+ <viz.feeds:FeedItem id="metricNativeCategoryAxisFeed" uid="color" type="Dimension" values="Operation" />
322
+ </viz:feeds>
323
+ </viz:VizFrame>
324
+ </l:VerticalLayout>
325
+ </f:content>
326
+ <f:layoutData>
327
+ <f:GridContainerItemLayoutData columns="4" minRows="4"/>
328
+ </f:layoutData>
329
+ </f:Card>
330
+ </f:GridContainer>
331
+ </VBox>
332
+
333
+ </cssgrid:CSSGrid>
334
+ </f:content>
335
+ </f:DynamicPage>
336
+
337
+ </mvc:View>
package/cds-plugin.js CHANGED
@@ -1,7 +1,59 @@
1
1
  const cds = require('@sap/cds')
2
+ const { fs, path } = cds.utils;
2
3
  const CachingService = require('./lib/CachingService')
3
4
  const { scanCachingAnnotations } = require('./lib/util')
4
5
 
6
+ // Auto-register plugin entity models based on service configuration.
7
+ // Pushes absolute file paths (without extension) into cds.env.roots so that
8
+ // cds.resolve('*') picks them up during model compilation — before cds.model is set.
9
+ const cachingConfigs = Object.values(cds.env.requires ?? {}).filter(r => r?.impl === 'cds-caching');
10
+ if (cachingConfigs.some(c => c.store === 'cds')) {
11
+ cds.env.roots.push(path.join(__dirname, 'db', 'cache-store'));
12
+ }
13
+ if (cachingConfigs.some(c => c.statistics)) {
14
+ cds.env.roots.push(path.join(__dirname, 'db', 'statistics'));
15
+ }
16
+
17
+ cds.add?.register?.('caching-dashboard', require('./lib/add'))
18
+
5
19
  cds.on('served', scanCachingAnnotations)
20
+ const LOG = cds.log("cds-caching");
21
+
22
+ // Register HANA build plugin to generate .hdbtable artifacts during `cds build`
23
+ cds.build?.register?.('cds-caching', class CachingBuildPlugin extends cds.build.Plugin {
24
+ static taskDefaults = { src: cds.env.folders.db }
25
+
26
+ init() { }
27
+ clean() { }
28
+
29
+ static hasTask() {
30
+ const requires = cds.env.requires || {};
31
+ return Object.values(requires).some(
32
+ r => r.impl === 'cds-caching' && r.store === 'hana'
33
+ );
34
+ }
35
+
36
+ async build() {
37
+ const requires = cds.env.requires || {};
38
+ for (const [, config] of Object.entries(requires)) {
39
+ if (config.impl === 'cds-caching' && config.store === 'hana') {
40
+ const table = config.credentials?.table || 'KEYV';
41
+ const keySize = config.credentials?.keySize || 255;
42
+ const content = [
43
+ `COLUMN TABLE "${table}" (`,
44
+ ` "ID" NVARCHAR(${keySize}) PRIMARY KEY,`,
45
+ ` "VALUE" NCLOB`,
46
+ `)`,
47
+ ].join('\n');
48
+ await this.write(content).to(`src/gen/${table}.hdbtable`);
49
+ LOG.info('Building cds-caching hana table', { table, keySize });
50
+ }
51
+ // For store: 'cds' with HANA, the CacheStore entity from db/cache-store.cds
52
+ // is loaded via cds.env.roots and deployed automatically by the HDI deployer —
53
+ // no manual .hdbtable needed. For SQLite/Postgres, CAP's cds deploy handles
54
+ // table creation from the CDS model.
55
+ }
56
+ }
57
+ });
6
58
 
7
59
  module.exports = cds.service.impl(CachingService)
@@ -0,0 +1,12 @@
1
+ namespace plugin.cds_caching;
2
+
3
+ /**
4
+ * Key-value store for the CDS cache adapter (`store: 'cds'`).
5
+ * Uses CAP's managed DB connection — works with HANA, PostgreSQL, SQLite.
6
+ * In MTX mode, each tenant's HDI container gets its own table automatically.
7
+ */
8
+ entity CacheStore {
9
+ key ID : String(900);
10
+ value : LargeString;
11
+ expiresAt : Int64;
12
+ }
@@ -0,0 +1,128 @@
1
+ namespace plugin.cds_caching;
2
+
3
+ entity Caches {
4
+ key name : String;
5
+ config : String;
6
+ metricsEnabled : Boolean default false;
7
+ keyMetricsEnabled : Boolean default false;
8
+ metrics : Composition of many Metrics
9
+ on metrics.cache = $self.name;
10
+ keyMetrics : Composition of many KeyMetrics
11
+ on keyMetrics.cache = $self.name;
12
+ }
13
+
14
+ entity Metrics {
15
+ key ID : String; // e.g., 'daily:2024-03-20' or 'hourly:2024-03-20-15'
16
+ key cache : String;
17
+ timestamp : DateTime;
18
+ period : String enum {
19
+ hourly;
20
+ daily;
21
+ monthly;
22
+ }; // Granularity
23
+
24
+ // Read-through metrics (hits and misses only)
25
+ hits : Integer default 0;
26
+ misses : Integer default 0;
27
+ errors : Integer default 0;
28
+ totalRequests : Integer default 0;
29
+ // Read-through latency metrics
30
+ avgHitLatency : Double; // average hit latency in milliseconds
31
+ minHitLatency : Double; // minimum hit latency
32
+ maxHitLatency : Double; // maximum hit latency
33
+ avgMissLatency : Double; // average miss latency in milliseconds
34
+ minMissLatency : Double; // minimum miss latency
35
+ maxMissLatency : Double; // maximum miss latency
36
+ avgReadThroughLatency : Double; // average read through latency in milliseconds
37
+
38
+ // Read-through performance metrics
39
+ hitRatio : Double; // hit ratio as percentage
40
+ throughput : Double; // requests per second
41
+ errorRate : Double; // error rate as percentage
42
+ cacheEfficiency : Double; // ratio of miss latency to hit latency
43
+
44
+ // Native function metrics (basic counts only)
45
+ nativeSets : Integer default 0;
46
+ nativeGets : Integer default 0;
47
+ nativeDeletes : Integer default 0;
48
+ nativeClears : Integer default 0;
49
+ nativeDeleteByTags : Integer default 0;
50
+ nativeErrors : Integer default 0;
51
+ totalNativeOperations : Integer default 0;
52
+ // Native function performance metrics
53
+ nativeThroughput : Double; // native operations per second
54
+ nativeErrorRate : Double; // native operation error rate
55
+
56
+ // Common metrics
57
+ memoryUsage : Integer; // in bytes
58
+ itemCount : Integer;
59
+ uptimeMs : Integer; // uptime in milliseconds
60
+ }
61
+
62
+ entity KeyMetrics {
63
+ key ID : String;
64
+ key cache : String;
65
+ key keyName : String;
66
+ lastAccess : DateTime;
67
+ period : String enum {
68
+ current;
69
+ hourly;
70
+ daily;
71
+ };
72
+
73
+ // Operation type tracking
74
+ operationType : String enum {
75
+ read_through;
76
+ native;
77
+ mixed;
78
+ };
79
+
80
+ // Read-through metrics (hits and misses only)
81
+ hits : Integer default 0;
82
+ misses : Integer default 0;
83
+ errors : Integer default 0;
84
+ totalRequests : Integer default 0;
85
+ hitRatio : Double; // hit ratio as percentage
86
+ cacheEfficiency : Double; // ratio of miss latency to hit latency
87
+
88
+ // Read-through latency metrics
89
+ avgHitLatency : Double; // average hit latency in milliseconds
90
+ minHitLatency : Double; // minimum hit latency
91
+ maxHitLatency : Double; // maximum hit latency
92
+ avgMissLatency : Double; // average miss latency in milliseconds
93
+ minMissLatency : Double; // minimum miss latency
94
+ maxMissLatency : Double; // maximum miss latency
95
+ avgReadThroughLatency : Double; // average read through latency in milliseconds
96
+
97
+ // Read-through performance metrics
98
+ throughput : Double; // requests per second
99
+ errorRate : Double; // error rate as percentage
100
+
101
+ // Native function metrics (counts only)
102
+ nativeHits : Integer default 0;
103
+ nativeMisses : Integer default 0;
104
+ nativeSets : Integer default 0;
105
+ nativeDeletes : Integer default 0;
106
+ nativeClears : Integer default 0;
107
+ nativeDeleteByTags : Integer default 0;
108
+ nativeErrors : Integer default 0;
109
+ totalNativeOperations : Integer default 0;
110
+ // Native function performance metrics
111
+ nativeThroughput : Double; // native operations per second
112
+ nativeErrorRate : Double; // native operation error rate
113
+
114
+ // Metadata fields
115
+ dataType : String;
116
+ operation : String; // concatenated cache service operations (e.g., SET, GET, WRAP, RUN...)
117
+ metadata : LargeString; // JSON string for additional metadata
118
+ // Enhanced context information
119
+ context : String; // JSON string with detailed context
120
+ query : LargeString; // CQL query text if applicable
121
+ subject : LargeString; // JSON string with subject information
122
+ target : String; // Target information
123
+ tenant : String; // Tenant information
124
+ user : String; // User information
125
+ locale : String; // Locale information
126
+ timestamp : DateTime; // When this key was first accessed
127
+ cacheOptions : String; // JSON string with cache options
128
+ }