Skip to content

Commit 5886923

Browse files
ajclarkamadvance
authored andcommitted
Add bandwidth limit feature --bw-limit
1 parent 15a5fac commit 5886923

File tree

19 files changed

+205
-5
lines changed

19 files changed

+205
-5
lines changed

HISTORY

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
SnapRAID HISTORY
22
================
33

4+
12.5 2025/XX
5+
============
6+
* Add a bandwidth limit option --bw-limit [Allan Clark]
7+
48
12.4 2025/01
59
============
610
* Avoid a warning about function pointer conversion. No functional changes.

Makefile.am

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ snapraid_SOURCES = \
2525
tommyds/tommy.c \
2626
cmdline/snapraid.c \
2727
cmdline/io.c \
28+
cmdline/bw.c \
2829
cmdline/util.c \
2930
cmdline/stream.c \
3031
cmdline/support.c \
@@ -78,6 +79,7 @@ noinst_HEADERS = \
7879
cmdline/portable.h \
7980
cmdline/snapraid.h \
8081
cmdline/io.h \
82+
cmdline/bw.h \
8183
cmdline/util.h \
8284
cmdline/stream.h \
8385
cmdline/support.h \
@@ -237,7 +239,7 @@ if HAVE_THREAD_CHECKER
237239
mv bench/disk3/a/9* bench/disk6/a
238240
$(TESTENV) ./mktest$(EXEEXT) change 2 500 bench/disk2/b/* bench/disk3/b/*
239241
# Sync again
240-
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync
242+
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) sync --bw-limit 1M
241243
# Other commands that uses threads
242244
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) test-rewrite
243245
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) scrub -p full
@@ -288,7 +290,7 @@ endif
288290
if HAVE_POSIX
289291
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(PAR1) pool
290292
endif
291-
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check
293+
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) check --bw-limit 1M
292294
$(TESTENV) ./snapraid$(EXEEXT) $(CHECKFLAGS) -c $(CONF) -a check
293295
#### CONTROLLED ####
294296
$(MSG) Filesystem allocation test

cmdline/bw.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
* Copyright (C) 2016 Andrea Mazzoleni
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#include "portable.h"
19+
20+
#include "bw.h"
21+
22+
void bw_init(struct snapraid_bw* bw, uint64_t limit)
23+
{
24+
bw->limit = limit;
25+
bw->total = 0;
26+
bw->start = tick_ms();
27+
}
28+
29+
void bw_limit(struct snapraid_bw* bw, uint64_t bytes)
30+
{
31+
if (!bw || bw->limit == 0)
32+
return;
33+
34+
uint64_t elapsed = tick_ms() - bw->start;
35+
uint64_t done;
36+
uint64_t eta;
37+
38+
done = __atomic_add_fetch(&bw->total, bytes, __ATOMIC_SEQ_CST);
39+
40+
eta = done * 1000 / bw->limit;
41+
42+
if (eta > elapsed) {
43+
eta -= elapsed;
44+
usleep(eta * 1000);
45+
}
46+
}

cmdline/bw.h

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* Copyright (C) 2016 Andrea Mazzoleni
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
#ifndef __BW_H
19+
#define __BW_H
20+
21+
#include "state.h"
22+
#include "support.h"
23+
24+
/**
25+
* Bandwidth limiting
26+
*/
27+
struct snapraid_bw {
28+
uint64_t limit; /**< Bandwidth limit in bytes per second */
29+
uint64_t total; /**< Remaining bytes allowed in current second */
30+
uint64_t start; /**< Time when to reset the bandwidth counter */
31+
};
32+
33+
/**
34+
* Initialize the bandwidth limit
35+
*/
36+
void bw_init(struct snapraid_bw* bw, uint64_t limit);
37+
38+
/**
39+
* Limit IO bandwidth to stay within the configured limit.
40+
* If no limit is set, returns immediately.
41+
* Otherwise sleeps as needed to maintain the rate limit.
42+
*/
43+
void bw_limit(struct snapraid_bw* bw, uint64_t bytes);
44+
45+
#endif

cmdline/check.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -888,9 +888,20 @@ static int state_check_process(struct snapraid_state* state, int fix, struct sna
888888
char esc_buffer[ESC_MAX];
889889
char esc_buffer_alt[ESC_MAX];
890890
bit_vect_t* block_enabled;
891+
struct snapraid_bw bw;
891892

892893
handle = handle_mapping(state, &diskmax);
893894

895+
/* initialize the bandwith context */
896+
bw_init(&bw, state->opt.bwlimit);
897+
898+
/* share the bandwidth context with all handles */
899+
for (j = 0; j < diskmax; ++j)
900+
handle[j].bw = &bw;
901+
for (j = 0; j < state->level; ++j)
902+
if (parity[j])
903+
parity[j]->bw = &bw;
904+
894905
/* we need 1 * data + 2 * parity + 1 * zero */
895906
buffermax = diskmax + 2 * state->level + 1;
896907

@@ -2085,4 +2096,3 @@ int state_check(struct snapraid_state* state, int fix, block_off_t blockstart, b
20852096
return -1;
20862097
return 0;
20872098
}
2088-

cmdline/fnmatch.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ extern "C" {
4747
#undef FNM_PATHNAME
4848
#undef FNM_NOESCAPE
4949
#undef FNM_PERIOD
50+
#undef FNM_LEADING_DIR
51+
#undef FNM_CASEFOLD
5052

5153
/* Bits set in the FLAGS argument to `fnmatch'. */
5254
#define FNM_PATHNAME (1 << 0) /* No wildcard can ever match `/'. */

cmdline/handle.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,8 @@ int handle_read(struct snapraid_handle* handle, block_off_t file_pos, unsigned c
261261

262262
count = 0;
263263
do {
264+
bw_limit(handle->bw, block_size - count);
265+
264266
/* read the full block to support O_DIRECT */
265267
read_ret = pread(handle->f, block_buffer + count, block_size - count, offset + count);
266268
if (read_ret < 0) {
@@ -372,6 +374,7 @@ struct snapraid_handle* handle_mapping(struct snapraid_state* state, unsigned* h
372374
handle[j].file = 0;
373375
handle[j].f = -1;
374376
handle[j].valid_size = 0;
377+
handle[j].bw = 0;
375378
}
376379

377380
/* set the vector */

cmdline/handle.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
#include "state.h"
2222
#include "support.h"
23+
#include "bw.h"
2324

2425
/****************************************************************************/
2526
/* handle */
@@ -33,6 +34,7 @@ struct snapraid_handle {
3334
struct advise_struct advise; /**< Advise information. */
3435
data_off_t valid_size; /**< Size of the valid data. */
3536
int created; /**< If the file was created, otherwise it was already existing. */
37+
struct snapraid_bw* bw; /**< Context for bandwidth limiting. */
3638
};
3739

3840
/**

cmdline/io.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,15 @@ void io_init(struct snapraid_io* io, struct snapraid_state* state,
877877

878878
io->state = state;
879879

880+
/* initialize bandwidth limiting */
881+
bw_init(&io->bw, state->opt.bwlimit);
882+
883+
/* set IO context in handles */
884+
for (i = 0; i < handle_max; ++i)
885+
handle_map[i].bw = &io->bw;
886+
for (i = 0; i < parity_handle_max; ++i)
887+
parity_handle_map[i].bw = &io->bw;
888+
880889
#if HAVE_THREAD
881890
if (io_cache == 0) {
882891
/* default is 16 MiB of cache */

cmdline/io.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,11 @@ struct snapraid_io {
288288
* Counts the error happening in the writers.
289289
*/
290290
int writer_error[IO_WRITER_ERROR_MAX];
291+
292+
/**
293+
* Bandwidth
294+
*/
295+
struct snapraid_bw bw;
291296
};
292297

293298
/**

0 commit comments

Comments
 (0)