Skip to content

Commit 565702b

Browse files
committed
It now displays live the 25 hottest shards
1 parent 449a8a9 commit 565702b

File tree

3 files changed

+62
-56
lines changed

3 files changed

+62
-56
lines changed

cratedb_toolkit/admin/xmover/analysis/shard.py

Lines changed: 61 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,13 @@
77
from collections import defaultdict
88
from time import sleep
99
from typing import Any, Dict, List, Optional, Set, Tuple, Union
10+
from unittest import result
1011

1112
from rich import box
1213
from rich.console import Console
1314
from rich.panel import Panel
1415
from rich.table import Table
16+
from rich.live import Live
1517

1618
from cratedb_toolkit.admin.xmover.model import (
1719
DistributionStats,
@@ -840,88 +842,95 @@ def plan_node_decommission(self, node_name: str, min_free_space_gb: float = 100.
840842
class ShardMonitor:
841843
def __init__(self, analyzer: ShardAnalyzer):
842844
self.analyzer = analyzer
843-
self.shard_time_deltas: dict[str, int] = {}
844-
self.shard_seq_deltas: dict[str, int] = {}
845-
self.shards: dict[str, ShardInfo] = {}
845+
self.reference_shards: dict[str, ShardInfo]
846+
self.latest_shards: list[ShardInfo]
847+
self.seq_deltas: dict[str, int]
848+
self.size_deltas: dict[str, float]
846849

847850
def _get_shard_compound_id(self, shard: ShardInfo) -> str:
848851
return f"{shard.node_id}-{shard.shard_id}"
849-
850-
def refresh_deltas(self, refresh_data: bool=True):
851-
if refresh_data:
852-
self.analyzer._refresh_data()
853852

854-
shards: list[ShardInfo] = self.analyzer.shards
853+
def calculate_heat_deltas(self, reference_shards: dict[str, ShardInfo], updated_shards: list[ShardInfo]):
854+
seq_result: dict[str, int] = {}
855+
size_result: dict[str, float] = {}
855856

856-
refreshed_shards: list[str] = []
857-
self.shards = {}
858-
for shard in shards:
857+
for shard in updated_shards:
859858
shard_compound_id = self._get_shard_compound_id(shard)
860-
refreshed_shards.append(shard_compound_id)
861-
self.shards[shard_compound_id] = shard
862-
863-
hot_timestamp = datetime.datetime.fromtimestamp(float(shard.hot_timestamp) / 1000)
864-
hot_delta = int((datetime.datetime.now() - hot_timestamp).total_seconds()) if shard.hot_timestamp else None
865859

866-
self.shard_time_deltas[shard_compound_id] = hot_delta
867-
if not shard_compound_id in self.shard_seq_deltas:
868-
self.shard_seq_deltas[shard_compound_id] = shard.seq_stats_max_seq_no
860+
if shard_compound_id not in reference_shards:
861+
seq_result[shard_compound_id] = 0
862+
size_result[shard_compound_id] = shard.size_gb
869863
else:
870-
self.shard_seq_deltas[shard_compound_id] = shard.seq_stats_max_seq_no - self.shard_seq_deltas[shard_compound_id]
864+
refreshed_number = shard.seq_stats_max_seq_no
865+
reference = reference_shards[shard_compound_id].seq_stats_max_seq_no
871866

872-
# Forget shards that are not reported
873-
to_delete: set[str] = set(self.shard_seq_deltas.keys()).difference(refreshed_shards)
874-
for id in to_delete:
875-
del(self.shard_seq_deltas[id])
876-
del(self.shard_time_deltas[id])
867+
if refreshed_number < reference:
868+
refreshed_number += 2 ** 63 - 1
877869

878-
def filter_shards(self, max_seconds_old: int) -> list[ShardInfo]:
879-
"""
880-
Filter shards not touched in the last `max_seconds_old` seconds
881-
"""
882-
return [self.shards.get(k) for k, v in self.shard_time_deltas.items() if v <= max_seconds_old]
870+
seq_result[shard_compound_id] = refreshed_number - reference
871+
size_result[shard_compound_id] = shard.size_gb - reference_shards[shard_compound_id].size_gb
872+
873+
self.seq_deltas = seq_result
874+
self.size_deltas = size_result
875+
876+
def refresh_data(self):
877+
self.analyzer._refresh_data()
878+
updated_shards: list[ShardInfo] = self.analyzer.shards
879+
self.calculate_heat_deltas(self.reference_shards, updated_shards)
880+
self.latest_shards = sorted(updated_shards, key=lambda s: self.seq_deltas[self._get_shard_compound_id(s)], reverse=True)
881+
self.latest_shards = self.latest_shards[:20]
883882

884883
def monitor_shards(self):
885-
max_seconds_old = 300
884+
self.reference_shards = {self._get_shard_compound_id(shard): shard for shard in self.analyzer.shards}
885+
self.refresh_data()
886886

887-
self.refresh_deltas(refresh_data=False)
888-
sleep(10)
889-
self.refresh_deltas()
887+
console.print(Panel.fit("[bold blue]The 25 most Hot Shards[/bold blue]"))
888+
shards_table = self.display_shards_table_header()
890889

891-
shards: list[ShardInfo] = self.filter_shards(max_seconds_old)
892-
sorted_shards: list[ShardInfo] = sorted(shards, key=lambda s: self.shard_seq_deltas[self._get_shard_compound_id(s)])
890+
with Live(self.generate_table(self.latest_shards, self.seq_deltas), refresh_per_second=4, console=console) as live:
891+
while True:
892+
sleep(10)
893+
self.refresh_data()
894+
# self.display_shards_table_rows(shards_table, self.latest_shards, self.deltas)
895+
live.update(self.generate_table(self.latest_shards, self.seq_deltas))
893896

894-
console.print(Panel.fit("[bold blue]CrateDB Hot Shard Monitor[/bold blue]"))
897+
def generate_table(self, sorted_shards: list[ShardInfo], deltas: dict[str, int]):
898+
t = self.display_shards_table_header()
899+
self.display_shards_table_rows(t, self.latest_shards, self.seq_deltas)
900+
return t
895901

896902
# Cluster summary table
903+
def display_shards_table_header(self):
897904
shards_table = Table(title="Hot shards", box=box.ROUNDED)
898905
shards_table.add_column("Schema", style="cyan")
899906
shards_table.add_column("Table", style="cyan")
900907
shards_table.add_column("ID", style="cyan")
901908
shards_table.add_column("Node", style="cyan")
902909
shards_table.add_column("Primary", style="cyan")
903910
shards_table.add_column("Size", style="magenta")
911+
shards_table.add_column("Size Delta", style="magenta")
904912
shards_table.add_column("Seq Delta", style="magenta")
905-
shards_table.add_column("Seconds ago", style="magenta")
913+
return shards_table
914+
915+
def display_shards_table_rows(self, shards_table: Table, sorted_shards: list[ShardInfo], deltas: dict[str, int]):
916+
shards_table.rows.clear()
906917

907918
for shard in sorted_shards:
908919
shard_compound_id = self._get_shard_compound_id(shard)
909-
shards_table.add_row(
910-
shard.schema_name,
911-
shard.table_name,
912-
str(shard.shard_id),
913-
shard.node_name,
914-
str(shard.is_primary),
915-
format_size(shard.size_gb),
916-
str(self.shard_seq_deltas[shard_compound_id]),
917-
str(self.shard_time_deltas[shard_compound_id]),
918-
)
920+
seq_delta = deltas.get(shard_compound_id, 0)
921+
if seq_delta != 0:
922+
shards_table.add_row(
923+
shard.schema_name,
924+
shard.table_name,
925+
str(shard.shard_id),
926+
shard.node_name,
927+
str(shard.is_primary),
928+
format_size(shard.size_gb),
929+
format_size(self.size_deltas[shard_compound_id]),
930+
str(seq_delta),
931+
)
919932
console.print(shards_table)
920933

921-
console.print(Panel.fit("[bold blue]CrateDB Heat per Node[/bold blue]"))
922-
923-
924-
925934

926935
class ShardReporter:
927936
def __init__(self, analyzer: ShardAnalyzer):

cratedb_toolkit/admin/xmover/model.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ class ShardInfo:
4848
seq_stats_max_seq_no: int
4949
seq_stats_global_checkpoint: int
5050
seq_stats_local_checkpoint: int
51-
hot_timestamp: int
5251

5352
@property
5453
def shard_type(self) -> str:

cratedb_toolkit/admin/xmover/util/database.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,7 @@ def get_shards_info(
150150
s.routing_state,
151151
s.seq_no_stats['max_seq_no'],
152152
s.seq_no_stats['global_checkpoint'],
153-
s.seq_no_stats['local_checkpoint'],
154-
s.retention_leases['leases'][1]['timestamp']
153+
s.seq_no_stats['local_checkpoint']
155154
FROM sys.shards s
156155
JOIN sys.nodes n ON s.node['id'] = n.id
157156
{where_clause}
@@ -179,7 +178,6 @@ def get_shards_info(
179178
seq_stats_max_seq_no=row[12],
180179
seq_stats_global_checkpoint=row[13],
181180
seq_stats_local_checkpoint=row[14],
182-
hot_timestamp=row[15],
183181
)
184182
)
185183

0 commit comments

Comments
 (0)