Skip to content

Commit d8b2799

Browse files
authored
feat: improve total buckets tracking (#926)
1 parent f6e0f95 commit d8b2799

2 files changed

Lines changed: 119 additions & 8 deletions

File tree

.changeset/lucky-beers-report.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@powersync/diagnostics-app': patch
3+
---
4+
5+
Improved query parameter warnings and limits

tools/diagnostics-app/src/app/views/sync-diagnostics.tsx

Lines changed: 114 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@ import { Spinner } from '@/components/ui/spinner';
88
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
99
import { NewStreamSubscription } from '@/components/widgets/NewStreamSubscription';
1010
import { StreamsTable } from '@/components/widgets/StreamsTable';
11-
import { formatBytes } from '@/lib/utils';
11+
import { cn, formatBytes } from '@/lib/utils';
1212
import { clearData, connector, db, sync, useSyncStatus } from '@/library/powersync/ConnectionManager';
13+
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
1314
import { decodeTokenPayload, getTokenUserId } from '@/library/powersync/TokenConnector';
1415
import { useQueryClient, useQuery as useTanstackQuery } from '@tanstack/react-query';
1516
import { ChevronDown, ChevronUp, Eye, Info } from 'lucide-react';
@@ -90,6 +91,17 @@ const syncDiagnosticsKeys = {
9091
/** When total_operations exceeds row_count by this factor, we show a warning that bucket history has accumulated and compacting may help. This is an abritrary threshold and indicates significant history buildup.*/
9192
const BUCKET_HISTORY_THRESHOLD = 3;
9293

94+
/**
95+
* Default server-side limit for both the "too many buckets" and "too many parameter query results"
96+
* limits (both reported as error PSYNC_S2305). These are two distinct limits that often coincide
97+
* but can differ:
98+
* - Duplicate parameter query results count individually toward the parameter result limit,
99+
* but are de-duplicated in the bucket count.
100+
* - Non-partitioning queries count 1 toward the bucket limit but not toward the parameter result limit.
101+
* The default is 1000 but can be configured on the server.
102+
*/
103+
const DEFAULT_SYNC_LIMIT = 1000;
104+
93105
interface SyncStats {
94106
bucketRows: any[] | null;
95107
tableRows: any[] | null;
@@ -222,6 +234,7 @@ export default function SyncDiagnosticsPage() {
222234

223235
const totals = {
224236
buckets: rows.length,
237+
parameterized_buckets: rows.filter((row) => !row.name.endsWith('[]')).length,
225238
row_count: rows.reduce((total, row) => total + row.row_count, 0),
226239
downloaded_operations: rows.reduce((total, row) => total + row.downloaded_operations, 0),
227240
total_operations: rows.reduce((total, row) => total + row.total_operations, 0),
@@ -272,7 +285,44 @@ export default function SyncDiagnosticsPage() {
272285
<Table>
273286
<TableHeader>
274287
<TableRow>
275-
<TableHead>Buckets</TableHead>
288+
<TableHead>
289+
<TooltipProvider>
290+
<Tooltip>
291+
<TooltipTrigger asChild>
292+
<span className="inline-flex items-center gap-1 cursor-default">
293+
Buckets
294+
<Info className="h-3 w-3 text-muted-foreground" />
295+
</span>
296+
</TooltipTrigger>
297+
<TooltipContent className="max-w-92">
298+
Two separate limits apply (both PSYNC_S2305, default {DEFAULT_SYNC_LIMIT.toLocaleString()}{' '}
299+
each): <strong>bucket count</strong> and <strong>parameter query results</strong>.
300+
<div className="mt-2">
301+
Global buckets count only toward bucket count. Parameter query buckets (in either{' '}
302+
<a
303+
href="https://docs.powersync.com/sync/rules/parameter-queries"
304+
target="_blank"
305+
rel="noopener noreferrer"
306+
className="underline hover:text-foreground"
307+
>
308+
Sync Rules
309+
</a>{' '}
310+
or{' '}
311+
<a
312+
href="https://docs.powersync.com/sync/streams/parameters"
313+
target="_blank"
314+
rel="noopener noreferrer"
315+
className="underline hover:text-foreground"
316+
>
317+
Sync Streams
318+
</a>
319+
) count toward both, but are de-duplicated client-side, so the server's parameter result count
320+
may be higher.
321+
</div>
322+
</TooltipContent>
323+
</Tooltip>
324+
</TooltipProvider>
325+
</TableHead>
276326
<TableHead className="text-right">Total Rows</TableHead>
277327
<TableHead className="text-right">Downloaded Ops</TableHead>
278328
<TableHead className="text-right">Total Ops</TableHead>
@@ -284,7 +334,22 @@ export default function SyncDiagnosticsPage() {
284334
</TableHeader>
285335
<TableBody>
286336
<TableRow>
287-
<TableCell className="font-medium">{totals.buckets}</TableCell>
337+
<TableCell className="font-medium">
338+
<span
339+
className={cn(
340+
totals.buckets >= 900 ? 'text-destructive' : totals.buckets >= 800 ? 'text-amber-600' : ''
341+
)}
342+
>
343+
{totals.buckets.toLocaleString()}
344+
</span>
345+
<span className="text-muted-foreground text-xs ml-1">
346+
/ {DEFAULT_SYNC_LIMIT.toLocaleString()} (default)
347+
</span>
348+
<div className="text-muted-foreground text-xs font-normal mt-0.5">
349+
{totals.parameterized_buckets.toLocaleString()} parameterized,{' '}
350+
{(totals.buckets - totals.parameterized_buckets).toLocaleString()} global
351+
</div>
352+
</TableCell>
288353
<TableCell className="text-right">{totals.row_count.toLocaleString()}</TableCell>
289354
<TableCell className="text-right">{totals.downloaded_operations.toLocaleString()}</TableCell>
290355
<TableCell className="text-right">{totals.total_operations.toLocaleString()}</TableCell>
@@ -300,7 +365,22 @@ export default function SyncDiagnosticsPage() {
300365
<div className="md:hidden p-4 grid grid-cols-2 gap-3 text-sm">
301366
<div>
302367
<div className="text-muted-foreground">Buckets</div>
303-
<div className="font-medium">{totals.buckets}</div>
368+
<div className="font-medium">
369+
<span
370+
className={cn(
371+
totals.buckets >= 900 ? 'text-destructive' : totals.buckets >= 800 ? 'text-amber-600' : ''
372+
)}
373+
>
374+
{totals.buckets.toLocaleString()}
375+
</span>
376+
<span className="text-muted-foreground text-xs ml-1">
377+
/ {DEFAULT_SYNC_LIMIT.toLocaleString()} (default)
378+
</span>
379+
<div className="text-muted-foreground text-xs font-normal mt-0.5">
380+
{totals.parameterized_buckets.toLocaleString()} parameterized,{' '}
381+
{(totals.buckets - totals.parameterized_buckets).toLocaleString()} global
382+
</div>
383+
</div>
304384
</div>
305385
<div>
306386
<div className="text-muted-foreground">Total Rows</div>
@@ -358,7 +438,8 @@ export default function SyncDiagnosticsPage() {
358438
variant="ghost"
359439
size="sm"
360440
className="h-7 gap-1.5 text-muted-foreground"
361-
onClick={() => setShowTokenDialog(true)}>
441+
onClick={() => setShowTokenDialog(true)}
442+
>
362443
<Eye className="h-3.5 w-3.5" />
363444
View Token
364445
</Button>
@@ -401,7 +482,8 @@ export default function SyncDiagnosticsPage() {
401482
variant="outline"
402483
onClick={() => {
403484
clearData();
404-
}}>
485+
}}
486+
>
405487
Clear & Redownload
406488
</Button>
407489
<span className="text-sm text-muted-foreground">
@@ -420,12 +502,35 @@ export default function SyncDiagnosticsPage() {
420502
href="https://docs.powersync.com/maintenance-ops/compacting-buckets"
421503
target="_blank"
422504
rel="noopener noreferrer"
423-
className="underline hover:text-foreground">
505+
className="underline hover:text-foreground"
506+
>
424507
Learn about compacting
425508
</a>
426509
</AlertDescription>
427510
</Alert>
428511
)}
512+
{totals.buckets >= 800 && (
513+
<Alert className={cn('mt-4', totals.buckets >= 900 ? 'border-destructive/50' : 'border-amber-500/50')}>
514+
<Info className={cn('h-4 w-4', totals.buckets >= 900 ? 'text-destructive' : 'text-amber-600')} />
515+
<AlertDescription>
516+
<span className={cn('font-medium', totals.buckets >= 900 ? 'text-destructive' : 'text-amber-600')}>
517+
{totals.buckets >= 900 ? 'Critical: ' : 'Warning: '}
518+
</span>
519+
{totals.buckets.toLocaleString()} of {DEFAULT_SYNC_LIMIT.toLocaleString()} buckets used (PSYNC_S2305,
520+
default limit). {totals.parameterized_buckets.toLocaleString()} are parameterized - at least that many
521+
parameter query results on the server. Review your Sync Config to reduce buckets and parameter query
522+
results for this user.{' '}
523+
<a
524+
href="https://docs.powersync.com/debugging/troubleshooting#too-many-buckets-psync_s2305"
525+
target="_blank"
526+
rel="noopener noreferrer"
527+
className="underline hover:text-foreground"
528+
>
529+
For troubleshooting steps, see the docs
530+
</a>
531+
</AlertDescription>
532+
</Alert>
533+
)}
429534
</div>
430535

431536
<div className="space-y-4">
@@ -511,7 +616,8 @@ function TruncatedTablesList({ tables }: { tables: string }) {
511616
e.stopPropagation();
512617
setExpanded(!expanded);
513618
}}
514-
className="inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors">
619+
className="inline-flex items-center gap-1 text-xs text-muted-foreground hover:text-foreground transition-colors"
620+
>
515621
{expanded ? (
516622
<>
517623
<ChevronUp className="h-3 w-3" />

0 commit comments

Comments
 (0)