|
43 | 43 | class InfoController(LiveClusterCommandController): |
44 | 44 | def __init__(self): |
45 | 45 | self.modifiers = set(["with", "for"]) |
46 | | - self.controller_map = dict(namespace=InfoNamespaceController) |
| 46 | + self.controller_map = dict( |
| 47 | + namespace=InfoNamespaceController, |
| 48 | + transactions=InfoTransactionsController |
| 49 | + ) |
47 | 50 | self.config_getter = GetConfigController(self.cluster) |
48 | 51 | self.stat_getter = GetStatisticsController(self.cluster) |
49 | 52 |
|
@@ -299,3 +302,104 @@ async def do_object(self, line): |
299 | 302 | return util.callable( |
300 | 303 | self.view.info_namespace_object, stats, rack_ids, self.cluster, **self.mods |
301 | 304 | ) |
| 305 | + |
| 306 | + |
| 307 | +@CommandHelp( |
| 308 | + "Displays transaction metrics for each 'strong-consistency' enabled namespace.", |
| 309 | + usage=f"[{ModifierUsageHelp.WITH}]", |
| 310 | + modifiers=(with_modifier_help,), |
| 311 | +) |
| 312 | +class InfoTransactionsController(LiveClusterCommandController): |
| 313 | + def __init__(self, get_futures=False): |
| 314 | + self.modifiers = set(["with"]) |
| 315 | + self.get_futures = get_futures |
| 316 | + self.stats_getter = GetStatisticsController(self.cluster) |
| 317 | + |
| 318 | + @CommandHelp( |
| 319 | + "Displays monitors and provisionals information for transactions in each 'strong-consistency' enabled namespace.", |
| 320 | + ) |
| 321 | + async def _do_default(self, line): |
| 322 | + tasks = await asyncio.gather( |
| 323 | + self.do_monitors(line), |
| 324 | + self.do_provisionals(line), |
| 325 | + ) |
| 326 | + if self.get_futures: |
| 327 | + # Wrapped to prevent base class from calling result. |
| 328 | + return dict(futures=tasks) |
| 329 | + |
| 330 | + return tasks |
| 331 | + |
| 332 | + @CommandHelp( |
| 333 | + "Displays monitor-related transaction metrics for each 'strong-consistency' enabled namespace.", |
| 334 | + usage=f"[{ModifierUsageHelp.WITH}]", |
| 335 | + modifiers=(with_modifier_help,), |
| 336 | + ) |
| 337 | + async def do_monitors(self, line): |
| 338 | + # Get namespace statistics which contain MRT metrics |
| 339 | + ns_stats = await self.stats_getter.get_strong_consistency_namespace(nodes=self.nodes) |
| 340 | + |
| 341 | + # Collect all namespaces from all nodes |
| 342 | + namespaces = set() |
| 343 | + for node_id, node_stats in ns_stats.items(): |
| 344 | + namespaces.update(node_stats.keys()) |
| 345 | + |
| 346 | + # If no namespaces with strong consistency enabled were found, return |
| 347 | + if not namespaces: |
| 348 | + logger.debug("No namespaces with strong consistency enabled were found for do_monitors") |
| 349 | + return |
| 350 | + |
| 351 | + # Get <ERO~MRT set statistics for all namespaces from all nodes concurrently |
| 352 | + set_stats_futures = [ |
| 353 | + asyncio.create_task( |
| 354 | + self.cluster.info_set_statistics(namespace, constants.MRT_SET, nodes=self.nodes) |
| 355 | + ) |
| 356 | + for namespace in namespaces |
| 357 | + ] |
| 358 | + all_set_data = await asyncio.gather(*set_stats_futures) |
| 359 | + |
| 360 | + # Map the results back to their namespaces and merge into ns_stats |
| 361 | + for namespace, set_data in zip(namespaces, all_set_data): |
| 362 | + for node_id, set_stats in set_data.items(): |
| 363 | + if ( |
| 364 | + isinstance(set_stats, Exception) |
| 365 | + or node_id not in ns_stats |
| 366 | + or namespace not in ns_stats[node_id] |
| 367 | + ): |
| 368 | + continue |
| 369 | + |
| 370 | + # Add set metrics to namespace stats with prefixed names |
| 371 | + ns_stats[node_id][namespace]["pseudo_mrt_monitor_used_bytes"] = int(set_stats.get("data_used_bytes", 0) if set_stats else 0) |
| 372 | + ns_stats[node_id][namespace]["stop-writes-count"] = int(set_stats.get("stop-writes-count", 0) if set_stats else 0) |
| 373 | + ns_stats[node_id][namespace]["stop-writes-size"] = int(set_stats.get("stop-writes-size", 0) if set_stats else 0) |
| 374 | + |
| 375 | + return util.callable( |
| 376 | + self.view.info_transactions_monitors, |
| 377 | + ns_stats, |
| 378 | + self.cluster, |
| 379 | + **self.mods, |
| 380 | + ) |
| 381 | + |
| 382 | + @CommandHelp( |
| 383 | + "Displays provisional-related transaction metrics for each 'strong-consistency' enabled namespace.", |
| 384 | + usage=f"[{ModifierUsageHelp.WITH}]", |
| 385 | + modifiers=(with_modifier_help,), |
| 386 | + ) |
| 387 | + async def do_provisionals(self, line): |
| 388 | + # Get namespace statistics which contain MRT metrics |
| 389 | + ns_stats = await self.stats_getter.get_strong_consistency_namespace(nodes=self.nodes) |
| 390 | + |
| 391 | + # Check if any strong consistency namespaces were found |
| 392 | + namespaces = set() |
| 393 | + for _, node_stats in ns_stats.items(): |
| 394 | + namespaces.update(node_stats.keys()) |
| 395 | + |
| 396 | + if not namespaces: |
| 397 | + logger.debug("No namespaces with strong consistency enabled were found for do_provisionals") |
| 398 | + return |
| 399 | + |
| 400 | + return util.callable( |
| 401 | + self.view.info_transactions_provisionals, |
| 402 | + ns_stats, |
| 403 | + self.cluster, |
| 404 | + **self.mods, |
| 405 | + ) |
0 commit comments