Skip to content

Commit eb670f4

Browse files
committed
Add TXG timestamp database
This feature enables tracking of when TXGs are committed to disk, providing an estimated timestamp for each TXG. With this information, it becomes possible to perform scrubs based on specific date ranges, improving the granularity of data management and recovery operations. Signed-off-by: Mariusz Zaborski <[email protected]>
1 parent 75e921d commit eb670f4

File tree

23 files changed

+731
-167
lines changed

23 files changed

+731
-167
lines changed

cmd/zpool/zpool_main.c

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ get_usage(zpool_help_t idx)
513513
return (gettext("\tinitialize [-c | -s | -u] [-w] <pool> "
514514
"[<device> ...]\n"));
515515
case HELP_SCRUB:
516-
return (gettext("\tscrub [-e | -s | -p | -C] [-w] "
516+
return (gettext("\tscrub [-e | -s | -p | -C | -E | -S] [-w] "
517517
"<pool> ...\n"));
518518
case HELP_RESILVER:
519519
return (gettext("\tresilver <pool> ...\n"));
@@ -8368,6 +8368,8 @@ zpool_do_reopen(int argc, char **argv)
83688368
typedef struct scrub_cbdata {
83698369
int cb_type;
83708370
pool_scrub_cmd_t cb_scrub_cmd;
8371+
time_t cb_date_start;
8372+
time_t cb_date_end;
83718373
} scrub_cbdata_t;
83728374

83738375
static boolean_t
@@ -8411,7 +8413,8 @@ scrub_callback(zpool_handle_t *zhp, void *data)
84118413
return (1);
84128414
}
84138415

8414-
err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd);
8416+
err = zpool_scan(zhp, cb->cb_type, cb->cb_scrub_cmd, cb->cb_date_start,
8417+
cb->cb_date_end);
84158418

84168419
if (err == 0 && zpool_has_checkpoint(zhp) &&
84178420
cb->cb_type == POOL_SCAN_SCRUB) {
@@ -8430,10 +8433,27 @@ wait_callback(zpool_handle_t *zhp, void *data)
84308433
return (zpool_wait(zhp, *act));
84318434
}
84328435

8436+
static time_t
8437+
date_string_to_sec(const char *timestr)
8438+
{
8439+
struct tm tm = {0};
8440+
8441+
if (strptime(timestr, "%Y-%m-%d %H:%M", &tm) == NULL) {
8442+
if (strptime(timestr, "%Y-%m-%d", &tm) == NULL) {
8443+
fprintf(stderr, gettext("Failed to parse the date.\n"));
8444+
usage(B_FALSE);
8445+
}
8446+
}
8447+
8448+
return (timegm(&tm));
8449+
}
8450+
84338451
/*
8434-
* zpool scrub [-e | -s | -p | -C] [-w] <pool> ...
8452+
* zpool scrub [-e | -s | -p | -C | -E | -S] [-w] <pool> ...
84358453
*
84368454
* -e Only scrub blocks in the error log.
8455+
* -E End date of scrub.
8456+
* -S Start date of scrub.
84378457
* -s Stop. Stops any in-progress scrub.
84388458
* -p Pause. Pause in-progress scrub.
84398459
* -w Wait. Blocks until scrub has completed.
@@ -8449,21 +8469,28 @@ zpool_do_scrub(int argc, char **argv)
84498469

84508470
cb.cb_type = POOL_SCAN_SCRUB;
84518471
cb.cb_scrub_cmd = POOL_SCRUB_NORMAL;
8472+
cb.cb_date_start = cb.cb_date_end = 0;
84528473

84538474
boolean_t is_error_scrub = B_FALSE;
84548475
boolean_t is_pause = B_FALSE;
84558476
boolean_t is_stop = B_FALSE;
84568477
boolean_t is_txg_continue = B_FALSE;
84578478

84588479
/* check options */
8459-
while ((c = getopt(argc, argv, "spweC")) != -1) {
8480+
while ((c = getopt(argc, argv, "spweCE:S:")) != -1) {
84608481
switch (c) {
84618482
case 'e':
84628483
is_error_scrub = B_TRUE;
84638484
break;
8485+
case 'E':
8486+
cb.cb_date_end = date_string_to_sec(optarg);
8487+
break;
84648488
case 's':
84658489
is_stop = B_TRUE;
84668490
break;
8491+
case 'S':
8492+
cb.cb_date_start = date_string_to_sec(optarg);
8493+
break;
84678494
case 'p':
84688495
is_pause = B_TRUE;
84698496
break;
@@ -8511,6 +8538,19 @@ zpool_do_scrub(int argc, char **argv)
85118538
}
85128539
}
85138540

8541+
if ((cb.cb_date_start != 0 || cb.cb_date_end != 0) &&
8542+
cb.cb_scrub_cmd != POOL_SCRUB_NORMAL) {
8543+
(void) fprintf(stderr, gettext("invalid option combination: "
8544+
"start/end date is available only with normal scrub\n"));
8545+
usage(B_FALSE);
8546+
}
8547+
if (cb.cb_date_start != 0 && cb.cb_date_end != 0 &&
8548+
cb.cb_date_start > cb.cb_date_end) {
8549+
(void) fprintf(stderr, gettext("invalid arguments: "
8550+
"end date has to be later than start date\n"));
8551+
usage(B_FALSE);
8552+
}
8553+
85148554
if (wait && (cb.cb_type == POOL_SCAN_NONE ||
85158555
cb.cb_scrub_cmd == POOL_SCRUB_PAUSE)) {
85168556
(void) fprintf(stderr, gettext("invalid option combination: "

include/Makefile.am

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ COMMON_H = \
1010
cityhash.h \
1111
zfeature_common.h \
1212
zfs_comutil.h \
13+
zfs_crrd.h \
1314
zfs_deleg.h \
1415
zfs_fletcher.h \
1516
zfs_namecheck.h \

include/libzfs.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,8 @@ typedef struct trimflags {
291291
/*
292292
* Functions to manipulate pool and vdev state
293293
*/
294-
_LIBZFS_H int zpool_scan(zpool_handle_t *, pool_scan_func_t, pool_scrub_cmd_t);
294+
_LIBZFS_H int zpool_scan(zpool_handle_t *, pool_scan_func_t, pool_scrub_cmd_t,
295+
time_t, time_t);
295296
_LIBZFS_H int zpool_initialize(zpool_handle_t *, pool_initialize_func_t,
296297
nvlist_t *);
297298
_LIBZFS_H int zpool_initialize_wait(zpool_handle_t *, pool_initialize_func_t,

include/sys/dmu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,9 @@ typedef struct dmu_buf {
394394
#define DMU_POOL_ZPOOL_CHECKPOINT "com.delphix:zpool_checkpoint"
395395
#define DMU_POOL_LOG_SPACEMAP_ZAP "com.delphix:log_spacemap_zap"
396396
#define DMU_POOL_DELETED_CLONES "com.delphix:deleted_clones"
397+
#define DMU_POOL_TXG_LOG_TIME_MINUTES "com.klaraystems:txg_log_time:minutes"
398+
#define DMU_POOL_TXG_LOG_TIME_DAYS "com.klaraystems:txg_log_time:days"
399+
#define DMU_POOL_TXG_LOG_TIME_MONTHS "com.klaraystems:txg_log_time:months"
397400

398401
/*
399402
* Allocate an object from this objset. The range of object numbers

include/sys/spa_impl.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
#include <sys/dsl_deadlist.h>
5656
#include <zfeature_common.h>
5757

58+
#include "zfs_crrd.h"
59+
5860
#ifdef __cplusplus
5961
extern "C" {
6062
#endif
@@ -343,6 +345,12 @@ struct spa {
343345
spa_checkpoint_info_t spa_checkpoint_info; /* checkpoint accounting */
344346
zthr_t *spa_checkpoint_discard_zthr;
345347

348+
kmutex_t spa_txg_log_time_lock; /* for spa_txg_log_time */
349+
dbrrd_t spa_txg_log_time;
350+
uint64_t spa_last_noted_txg;
351+
uint64_t spa_last_noted_txg_time;
352+
uint64_t spa_last_flush_txg_time;
353+
346354
space_map_t *spa_syncing_log_sm; /* current log space map */
347355
avl_tree_t spa_sm_logs_by_txg;
348356
kmutex_t spa_flushed_ms_lock; /* for metaslabs_by_flushed */

include/zfs_crrd.h

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/*
2+
* CDDL HEADER START
3+
*
4+
* The contents of this file are subject to the terms of the
5+
* Common Development and Distribution License (the "License").
6+
* You may not use this file except in compliance with the License.
7+
*
8+
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9+
* or https://opensource.org/licenses/CDDL-1.0.
10+
* See the License for the specific language governing permissions
11+
* and limitations under the License.
12+
*
13+
* When distributing Covered Code, include this CDDL HEADER in each
14+
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15+
* If applicable, add the following below this CDDL HEADER, with the
16+
* fields enclosed by brackets "[]" replaced with your own identifying
17+
* information: Portions Copyright [yyyy] [name of copyright owner]
18+
*
19+
* CDDL HEADER END
20+
*/
21+
/*
22+
* Copyright (c) 2024 Klara Inc.
23+
*
24+
* This software was developed by
25+
* Fred Weigel <[email protected]>
26+
* Mariusz Zaborski <[email protected]>
27+
* under sponsorship from Wasabi Technology, Inc. and Klara Inc.
28+
*/
29+
30+
#ifndef _CRRD_H_
31+
#define _CRRD_H_
32+
33+
#define RRD_MAX_ENTRIES 256
34+
35+
#define RRD_ENTRY_SIZE sizeof (uint64_t)
36+
#define RRD_STRUCT_ELEM (sizeof (rrd_t) / RRD_ENTRY_SIZE)
37+
38+
typedef enum {
39+
DBRRD_FLOOR,
40+
DBRRD_CEILING
41+
} dbrrd_rounding_t;
42+
43+
typedef struct {
44+
uint64_t rrdd_time;
45+
uint64_t rrdd_txg;
46+
} rrd_data_t;
47+
48+
typedef struct {
49+
uint64_t rrd_head; /* head (beginning) */
50+
uint64_t rrd_tail; /* tail (end) */
51+
uint64_t rrd_length;
52+
53+
rrd_data_t rrd_entries[RRD_MAX_ENTRIES];
54+
} rrd_t;
55+
56+
typedef struct {
57+
rrd_t dbr_minutes;
58+
rrd_t dbr_days;
59+
rrd_t dbr_months;
60+
} dbrrd_t;
61+
62+
size_t rrd_len(rrd_t *rrd);
63+
64+
const rrd_data_t *rrd_entry(rrd_t *r, size_t i);
65+
const rrd_data_t *rrd_tail_entry(rrd_t *rrd);
66+
uint64_t rrd_tail(rrd_t *rrd);
67+
uint64_t rrd_get(rrd_t *rrd, size_t i);
68+
69+
void rrd_add(rrd_t *rrd, hrtime_t time, uint64_t txg);
70+
71+
void dbrrd_add(dbrrd_t *db, hrtime_t time, uint64_t txg);
72+
uint64_t dbrrd_query(dbrrd_t *r, hrtime_t tv, dbrrd_rounding_t rouding);
73+
74+
#endif

lib/libnvpair/libnvpair.abi

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,6 +2194,7 @@
21942194
</data-member>
21952195
</class-decl>
21962196
<typedef-decl name='stack_t' type-id='380f9954' id='ac5e685f'/>
2197+
<typedef-decl name='unw_regnum_t' type-id='95e97e5e' id='c53620f0'/>
21972198
<class-decl name='unw_cursor' size-in-bits='8128' is-struct='yes' visibility='default' id='384a1f22'>
21982199
<data-member access='public' layout-offset-in-bits='0'>
21992200
<var-decl name='opaque' type-id='dc70ec0b' visibility='default'/>
@@ -2306,6 +2307,10 @@
23062307
<parameter type-id='b59d7dce'/>
23072308
<return type-id='79a0948f'/>
23082309
</function-decl>
2310+
<function-decl name='_Ux86_64_regname' visibility='default' binding='global' size-in-bits='64'>
2311+
<parameter type-id='c53620f0'/>
2312+
<return type-id='80f4b756'/>
2313+
</function-decl>
23092314
<function-decl name='_ULx86_64_init_local' visibility='default' binding='global' size-in-bits='64'>
23102315
<parameter type-id='3946e4d1'/>
23112316
<parameter type-id='2e408b96'/>

lib/libuutil/libuutil.abi

Lines changed: 6 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,7 @@
652652
</data-member>
653653
</class-decl>
654654
<typedef-decl name='stack_t' type-id='380f9954' id='ac5e685f'/>
655+
<typedef-decl name='unw_regnum_t' type-id='95e97e5e' id='c53620f0'/>
655656
<class-decl name='unw_cursor' size-in-bits='8128' is-struct='yes' visibility='default' id='384a1f22'>
656657
<data-member access='public' layout-offset-in-bits='0'>
657658
<var-decl name='opaque' type-id='dc70ec0b' visibility='default'/>
@@ -763,6 +764,10 @@
763764
<parameter type-id='b59d7dce'/>
764765
<return type-id='79a0948f'/>
765766
</function-decl>
767+
<function-decl name='_Ux86_64_regname' visibility='default' binding='global' size-in-bits='64'>
768+
<parameter type-id='c53620f0'/>
769+
<return type-id='80f4b756'/>
770+
</function-decl>
766771
<function-decl name='_ULx86_64_init_local' visibility='default' binding='global' size-in-bits='64'>
767772
<parameter type-id='3946e4d1'/>
768773
<parameter type-id='2e408b96'/>
@@ -1011,16 +1016,9 @@
10111016
</function-decl>
10121017
</abi-instr>
10131018
<abi-instr address-size='64' path='lib/libspl/os/linux/getmntany.c' language='LANG_C99'>
1014-
<array-type-def dimensions='1' type-id='38b51b3c' size-in-bits='832' id='02b72c00'>
1015-
<subrange length='13' type-id='7359adad' id='487fded1'/>
1016-
</array-type-def>
10171019
<array-type-def dimensions='1' type-id='03085adc' size-in-bits='192' id='083f8d58'>
10181020
<subrange length='3' type-id='7359adad' id='56f209d2'/>
10191021
</array-type-def>
1020-
<class-decl name='__locale_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='23de8b96'/>
1021-
<array-type-def dimensions='1' type-id='80f4b756' size-in-bits='832' id='39e6f84a'>
1022-
<subrange length='13' type-id='7359adad' id='487fded1'/>
1023-
</array-type-def>
10241022
<class-decl name='mnttab' size-in-bits='256' is-struct='yes' visibility='default' id='1b055409'>
10251023
<data-member access='public' layout-offset-in-bits='0'>
10261024
<var-decl name='mnt_special' type-id='26a90f95' visibility='default'/>
@@ -1130,25 +1128,6 @@
11301128
<typedef-decl name='__blksize_t' type-id='bd54fe1a' id='d3f10a7f'/>
11311129
<typedef-decl name='__blkcnt64_t' type-id='bd54fe1a' id='4e711bf1'/>
11321130
<typedef-decl name='__syscall_slong_t' type-id='bd54fe1a' id='03085adc'/>
1133-
<class-decl name='__locale_struct' size-in-bits='1856' is-struct='yes' visibility='default' id='90cc1ce3'>
1134-
<data-member access='public' layout-offset-in-bits='0'>
1135-
<var-decl name='__locales' type-id='02b72c00' visibility='default'/>
1136-
</data-member>
1137-
<data-member access='public' layout-offset-in-bits='832'>
1138-
<var-decl name='__ctype_b' type-id='31347b7a' visibility='default'/>
1139-
</data-member>
1140-
<data-member access='public' layout-offset-in-bits='896'>
1141-
<var-decl name='__ctype_tolower' type-id='6d60f45d' visibility='default'/>
1142-
</data-member>
1143-
<data-member access='public' layout-offset-in-bits='960'>
1144-
<var-decl name='__ctype_toupper' type-id='6d60f45d' visibility='default'/>
1145-
</data-member>
1146-
<data-member access='public' layout-offset-in-bits='1024'>
1147-
<var-decl name='__names' type-id='39e6f84a' visibility='default'/>
1148-
</data-member>
1149-
</class-decl>
1150-
<typedef-decl name='__locale_t' type-id='f01e1813' id='b7ac9b5f'/>
1151-
<typedef-decl name='locale_t' type-id='b7ac9b5f' id='973a4f8d'/>
11521131
<class-decl name='timespec' size-in-bits='128' is-struct='yes' visibility='default' id='a9c79a1f'>
11531132
<data-member access='public' layout-offset-in-bits='0'>
11541133
<var-decl name='tv_sec' type-id='65eda9c0' visibility='default'/>
@@ -1157,23 +1136,12 @@
11571136
<var-decl name='tv_nsec' type-id='03085adc' visibility='default'/>
11581137
</data-member>
11591138
</class-decl>
1160-
<pointer-type-def type-id='23de8b96' size-in-bits='64' id='38b51b3c'/>
1161-
<pointer-type-def type-id='90cc1ce3' size-in-bits='64' id='f01e1813'/>
1162-
<qualified-type-def type-id='95e97e5e' const='yes' id='2448a865'/>
1163-
<pointer-type-def type-id='2448a865' size-in-bits='64' id='6d60f45d'/>
1164-
<qualified-type-def type-id='8efea9e5' const='yes' id='3beb2af4'/>
1165-
<pointer-type-def type-id='3beb2af4' size-in-bits='64' id='31347b7a'/>
11661139
<pointer-type-def type-id='0c544dc0' size-in-bits='64' id='394fc496'/>
11671140
<pointer-type-def type-id='56fe4a37' size-in-bits='64' id='b6b61d2f'/>
11681141
<qualified-type-def type-id='b6b61d2f' restrict='yes' id='3cad23cd'/>
11691142
<pointer-type-def type-id='1b055409' size-in-bits='64' id='9d424d31'/>
11701143
<pointer-type-def type-id='0bbec9cd' size-in-bits='64' id='62f7a03d'/>
11711144
<qualified-type-def type-id='62f7a03d' restrict='yes' id='f1cadedf'/>
1172-
<class-decl name='__locale_data' is-struct='yes' visibility='default' is-declaration-only='yes' id='23de8b96'/>
1173-
<function-decl name='uselocale' visibility='default' binding='global' size-in-bits='64'>
1174-
<parameter type-id='973a4f8d'/>
1175-
<return type-id='973a4f8d'/>
1176-
</function-decl>
11771145
<function-decl name='getmntent_r' visibility='default' binding='global' size-in-bits='64'>
11781146
<parameter type-id='e75a27e9'/>
11791147
<parameter type-id='3cad23cd'/>
@@ -1185,9 +1153,8 @@
11851153
<parameter type-id='822cd80b'/>
11861154
<return type-id='95e97e5e'/>
11871155
</function-decl>
1188-
<function-decl name='strerror_l' visibility='default' binding='global' size-in-bits='64'>
1156+
<function-decl name='strerror' visibility='default' binding='global' size-in-bits='64'>
11891157
<parameter type-id='95e97e5e'/>
1190-
<parameter type-id='973a4f8d'/>
11911158
<return type-id='26a90f95'/>
11921159
</function-decl>
11931160
<function-decl name='__fprintf_chk' visibility='default' binding='global' size-in-bits='64'>

0 commit comments

Comments
 (0)