Skip to content

Commit 69e7097

Browse files
committed
Added inline_max, to optionally limit the size of inlined files
Inlined files live in metadata and decrease storage requirements, but may be limited to improve metadata-related performance. This is especially important given the current plague of metadata performance. Though decreasing inline_max may make metadata more dense and increase block usage, so it's important to benchmark if optimizing for speed. The underlying limits of inlined files haven't changed: 1. Inlined files need to fit in RAM, so <= cache_size 2. Inlined files need to fit in a single attr, so <= attr_max 3. Inlined files need to fit in 1/8 of a block to avoid metadata overflow issues, this is after limiting by metadata_max, so <= min(metadata_max, block_size)/8 By default, the largest possible inline_max is used. This preserves backwards compatibility and is probably a good default for most use cases. This does have the awkward effect of requiring inline_max=-1 to indicate disabled inlined files, but I don't think there's a good way around this.
1 parent c733d9e commit 69e7097

File tree

7 files changed

+79
-25
lines changed

7 files changed

+79
-25
lines changed

lfs.c

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3502,11 +3502,7 @@ static lfs_ssize_t lfs_file_flushedwrite(lfs_t *lfs, lfs_file_t *file,
35023502
lfs_size_t nsize = size;
35033503

35043504
if ((file->flags & LFS_F_INLINE) &&
3505-
lfs_max(file->pos+nsize, file->ctz.size) >
3506-
lfs_min(0x3fe, lfs_min(
3507-
lfs->cfg->cache_size,
3508-
(lfs->cfg->metadata_max ?
3509-
lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) {
3505+
lfs_max(file->pos+nsize, file->ctz.size) > lfs->inline_max) {
35103506
// inline file doesn't fit anymore
35113507
int err = lfs_file_outline(lfs, file);
35123508
if (err) {
@@ -3703,10 +3699,7 @@ static int lfs_file_rawtruncate(lfs_t *lfs, lfs_file_t *file, lfs_off_t size) {
37033699
lfs_off_t oldsize = lfs_file_rawsize(lfs, file);
37043700
if (size < oldsize) {
37053701
// revert to inline file?
3706-
if (size <= lfs_min(0x3fe, lfs_min(
3707-
lfs->cfg->cache_size,
3708-
(lfs->cfg->metadata_max ?
3709-
lfs->cfg->metadata_max : lfs->cfg->block_size) / 8))) {
3702+
if (size <= lfs->inline_max) {
37103703
// flush+seek to head
37113704
lfs_soff_t res = lfs_file_rawseek(lfs, file, 0, LFS_SEEK_SET);
37123705
if (res < 0) {
@@ -4215,6 +4208,27 @@ static int lfs_init(lfs_t *lfs, const struct lfs_config *cfg) {
42154208

42164209
LFS_ASSERT(lfs->cfg->metadata_max <= lfs->cfg->block_size);
42174210

4211+
LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1
4212+
|| lfs->cfg->inline_max <= lfs->cfg->cache_size);
4213+
LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1
4214+
|| lfs->cfg->inline_max <= lfs->attr_max);
4215+
LFS_ASSERT(lfs->cfg->inline_max == (lfs_size_t)-1
4216+
|| lfs->cfg->inline_max <= ((lfs->cfg->metadata_max)
4217+
? lfs->cfg->metadata_max
4218+
: lfs->cfg->block_size)/8);
4219+
lfs->inline_max = lfs->cfg->inline_max;
4220+
if (lfs->inline_max == (lfs_size_t)-1) {
4221+
lfs->inline_max = 0;
4222+
} else if (lfs->inline_max == 0) {
4223+
lfs->inline_max = lfs_min(
4224+
lfs->cfg->cache_size,
4225+
lfs_min(
4226+
lfs->attr_max,
4227+
((lfs->cfg->metadata_max)
4228+
? lfs->cfg->metadata_max
4229+
: lfs->cfg->block_size)/8));
4230+
}
4231+
42184232
// setup default state
42194233
lfs->root[0] = LFS_BLOCK_NULL;
42204234
lfs->root[1] = LFS_BLOCK_NULL;
@@ -4438,6 +4452,9 @@ static int lfs_rawmount(lfs_t *lfs, const struct lfs_config *cfg) {
44384452
}
44394453

44404454
lfs->attr_max = superblock.attr_max;
4455+
4456+
// we also need to update inline_max in case attr_max changed
4457+
lfs->inline_max = lfs_min(lfs->inline_max, lfs->attr_max);
44414458
}
44424459

44434460
// this is where we get the block_count from disk if block_count=0

lfs.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,15 @@ struct lfs_config {
264264
// Defaults to block_size when zero.
265265
lfs_size_t metadata_max;
266266

267+
// Optional upper limit on inlined files in bytes. Inlined files live in
268+
// metadata and decrease storage requirements, but may be limited to
269+
// improve metadata-related performance. Must be <= cache_size, <=
270+
// attr_max, and <= block_size/8. Defaults to the largest possible
271+
// inline_size when zero.
272+
//
273+
// Set to -1 to disable inlined files.
274+
lfs_size_t inline_max;
275+
267276
#ifdef LFS_MULTIVERSION
268277
// On-disk version to use when writing in the form of 16-bit major version
269278
// + 16-bit minor version. This limiting metadata to what is supported by
@@ -443,6 +452,7 @@ typedef struct lfs {
443452
lfs_size_t name_max;
444453
lfs_size_t file_max;
445454
lfs_size_t attr_max;
455+
lfs_size_t inline_max;
446456

447457
#ifdef LFS_MIGRATE
448458
struct lfs1 *lfs1;

runners/bench_runner.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,6 +1321,7 @@ void perm_run(
13211321
.block_cycles = BLOCK_CYCLES,
13221322
.cache_size = CACHE_SIZE,
13231323
.lookahead_size = LOOKAHEAD_SIZE,
1324+
.inline_max = INLINE_MAX,
13241325
};
13251326

13261327
struct lfs_emubd_config bdcfg = {

runners/bench_runner.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -95,11 +95,12 @@ intmax_t bench_define(size_t define);
9595
#define BLOCK_COUNT_i 5
9696
#define CACHE_SIZE_i 6
9797
#define LOOKAHEAD_SIZE_i 7
98-
#define BLOCK_CYCLES_i 8
99-
#define ERASE_VALUE_i 9
100-
#define ERASE_CYCLES_i 10
101-
#define BADBLOCK_BEHAVIOR_i 11
102-
#define POWERLOSS_BEHAVIOR_i 12
98+
#define INLINE_MAX_i 8
99+
#define BLOCK_CYCLES_i 9
100+
#define ERASE_VALUE_i 10
101+
#define ERASE_CYCLES_i 11
102+
#define BADBLOCK_BEHAVIOR_i 12
103+
#define POWERLOSS_BEHAVIOR_i 13
103104

104105
#define READ_SIZE bench_define(READ_SIZE_i)
105106
#define PROG_SIZE bench_define(PROG_SIZE_i)
@@ -109,6 +110,7 @@ intmax_t bench_define(size_t define);
109110
#define BLOCK_COUNT bench_define(BLOCK_COUNT_i)
110111
#define CACHE_SIZE bench_define(CACHE_SIZE_i)
111112
#define LOOKAHEAD_SIZE bench_define(LOOKAHEAD_SIZE_i)
113+
#define INLINE_MAX bench_define(INLINE_MAX_i)
112114
#define BLOCK_CYCLES bench_define(BLOCK_CYCLES_i)
113115
#define ERASE_VALUE bench_define(ERASE_VALUE_i)
114116
#define ERASE_CYCLES bench_define(ERASE_CYCLES_i)
@@ -124,14 +126,15 @@ intmax_t bench_define(size_t define);
124126
BENCH_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1))\
125127
BENCH_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
126128
BENCH_DEF(LOOKAHEAD_SIZE, 16) \
129+
BENCH_DEF(INLINE_MAX, 0) \
127130
BENCH_DEF(BLOCK_CYCLES, -1) \
128131
BENCH_DEF(ERASE_VALUE, 0xff) \
129132
BENCH_DEF(ERASE_CYCLES, 0) \
130133
BENCH_DEF(BADBLOCK_BEHAVIOR, LFS_EMUBD_BADBLOCK_PROGERROR) \
131134
BENCH_DEF(POWERLOSS_BEHAVIOR, LFS_EMUBD_POWERLOSS_NOOP)
132135

133136
#define BENCH_GEOMETRY_DEFINE_COUNT 4
134-
#define BENCH_IMPLICIT_DEFINE_COUNT 13
137+
#define BENCH_IMPLICIT_DEFINE_COUNT 14
135138

136139

137140
#endif

runners/test_runner.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,7 @@ static void run_powerloss_none(
13461346
.block_cycles = BLOCK_CYCLES,
13471347
.cache_size = CACHE_SIZE,
13481348
.lookahead_size = LOOKAHEAD_SIZE,
1349+
.inline_max = INLINE_MAX,
13491350
#ifdef LFS_MULTIVERSION
13501351
.disk_version = DISK_VERSION,
13511352
#endif
@@ -1422,6 +1423,7 @@ static void run_powerloss_linear(
14221423
.block_cycles = BLOCK_CYCLES,
14231424
.cache_size = CACHE_SIZE,
14241425
.lookahead_size = LOOKAHEAD_SIZE,
1426+
.inline_max = INLINE_MAX,
14251427
#ifdef LFS_MULTIVERSION
14261428
.disk_version = DISK_VERSION,
14271429
#endif
@@ -1515,6 +1517,7 @@ static void run_powerloss_log(
15151517
.block_cycles = BLOCK_CYCLES,
15161518
.cache_size = CACHE_SIZE,
15171519
.lookahead_size = LOOKAHEAD_SIZE,
1520+
.inline_max = INLINE_MAX,
15181521
#ifdef LFS_MULTIVERSION
15191522
.disk_version = DISK_VERSION,
15201523
#endif
@@ -1606,6 +1609,7 @@ static void run_powerloss_cycles(
16061609
.block_cycles = BLOCK_CYCLES,
16071610
.cache_size = CACHE_SIZE,
16081611
.lookahead_size = LOOKAHEAD_SIZE,
1612+
.inline_max = INLINE_MAX,
16091613
#ifdef LFS_MULTIVERSION
16101614
.disk_version = DISK_VERSION,
16111615
#endif
@@ -1795,6 +1799,7 @@ static void run_powerloss_exhaustive(
17951799
.block_cycles = BLOCK_CYCLES,
17961800
.cache_size = CACHE_SIZE,
17971801
.lookahead_size = LOOKAHEAD_SIZE,
1802+
.inline_max = INLINE_MAX,
17981803
#ifdef LFS_MULTIVERSION
17991804
.disk_version = DISK_VERSION,
18001805
#endif

runners/test_runner.h

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -88,12 +88,13 @@ intmax_t test_define(size_t define);
8888
#define BLOCK_COUNT_i 5
8989
#define CACHE_SIZE_i 6
9090
#define LOOKAHEAD_SIZE_i 7
91-
#define BLOCK_CYCLES_i 8
92-
#define ERASE_VALUE_i 9
93-
#define ERASE_CYCLES_i 10
94-
#define BADBLOCK_BEHAVIOR_i 11
95-
#define POWERLOSS_BEHAVIOR_i 12
96-
#define DISK_VERSION_i 13
91+
#define INLINE_MAX_i 8
92+
#define BLOCK_CYCLES_i 9
93+
#define ERASE_VALUE_i 10
94+
#define ERASE_CYCLES_i 11
95+
#define BADBLOCK_BEHAVIOR_i 12
96+
#define POWERLOSS_BEHAVIOR_i 13
97+
#define DISK_VERSION_i 14
9798

9899
#define READ_SIZE TEST_DEFINE(READ_SIZE_i)
99100
#define PROG_SIZE TEST_DEFINE(PROG_SIZE_i)
@@ -103,6 +104,7 @@ intmax_t test_define(size_t define);
103104
#define BLOCK_COUNT TEST_DEFINE(BLOCK_COUNT_i)
104105
#define CACHE_SIZE TEST_DEFINE(CACHE_SIZE_i)
105106
#define LOOKAHEAD_SIZE TEST_DEFINE(LOOKAHEAD_SIZE_i)
107+
#define INLINE_MAX TEST_DEFINE(INLINE_MAX_i)
106108
#define BLOCK_CYCLES TEST_DEFINE(BLOCK_CYCLES_i)
107109
#define ERASE_VALUE TEST_DEFINE(ERASE_VALUE_i)
108110
#define ERASE_CYCLES TEST_DEFINE(ERASE_CYCLES_i)
@@ -119,6 +121,7 @@ intmax_t test_define(size_t define);
119121
TEST_DEF(BLOCK_COUNT, ERASE_COUNT/lfs_max(BLOCK_SIZE/ERASE_SIZE,1)) \
120122
TEST_DEF(CACHE_SIZE, lfs_max(64,lfs_max(READ_SIZE,PROG_SIZE))) \
121123
TEST_DEF(LOOKAHEAD_SIZE, 16) \
124+
TEST_DEF(INLINE_MAX, 0) \
122125
TEST_DEF(BLOCK_CYCLES, -1) \
123126
TEST_DEF(ERASE_VALUE, 0xff) \
124127
TEST_DEF(ERASE_CYCLES, 0) \
@@ -127,7 +130,7 @@ intmax_t test_define(size_t define);
127130
TEST_DEF(DISK_VERSION, 0)
128131

129132
#define TEST_GEOMETRY_DEFINE_COUNT 4
130-
#define TEST_IMPLICIT_DEFINE_COUNT 14
133+
#define TEST_IMPLICIT_DEFINE_COUNT 15
131134

132135

133136
#endif

tests/test_files.toml

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
[cases.test_files_simple]
3+
defines.INLINE_MAX = [0, -1, 8]
34
code = '''
45
lfs_t lfs;
56
lfs_format(&lfs, cfg) => 0;
@@ -25,6 +26,7 @@ code = '''
2526
[cases.test_files_large]
2627
defines.SIZE = [32, 8192, 262144, 0, 7, 8193]
2728
defines.CHUNKSIZE = [31, 16, 33, 1, 1023]
29+
defines.INLINE_MAX = [0, -1, 8]
2830
code = '''
2931
lfs_t lfs;
3032
lfs_format(&lfs, cfg) => 0;
@@ -67,6 +69,7 @@ code = '''
6769
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
6870
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
6971
defines.CHUNKSIZE = [31, 16, 1]
72+
defines.INLINE_MAX = [0, -1, 8]
7073
code = '''
7174
lfs_t lfs;
7275
lfs_format(&lfs, cfg) => 0;
@@ -152,6 +155,7 @@ code = '''
152155
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
153156
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
154157
defines.CHUNKSIZE = [31, 16, 1]
158+
defines.INLINE_MAX = [0, -1, 8]
155159
code = '''
156160
lfs_t lfs;
157161
lfs_format(&lfs, cfg) => 0;
@@ -232,6 +236,7 @@ code = '''
232236
defines.SIZE1 = [32, 8192, 131072, 0, 7, 8193]
233237
defines.SIZE2 = [32, 8192, 131072, 0, 7, 8193]
234238
defines.CHUNKSIZE = [31, 16, 1]
239+
defines.INLINE_MAX = [0, -1, 8]
235240
code = '''
236241
lfs_t lfs;
237242
lfs_format(&lfs, cfg) => 0;
@@ -303,6 +308,7 @@ code = '''
303308
[cases.test_files_reentrant_write]
304309
defines.SIZE = [32, 0, 7, 2049]
305310
defines.CHUNKSIZE = [31, 16, 65]
311+
defines.INLINE_MAX = [0, -1, 8]
306312
reentrant = true
307313
code = '''
308314
lfs_t lfs;
@@ -354,11 +360,20 @@ code = '''
354360
[cases.test_files_reentrant_write_sync]
355361
defines = [
356362
# append (O(n))
357-
{MODE='LFS_O_APPEND', SIZE=[32, 0, 7, 2049], CHUNKSIZE=[31, 16, 65]},
363+
{MODE='LFS_O_APPEND',
364+
SIZE=[32, 0, 7, 2049],
365+
CHUNKSIZE=[31, 16, 65],
366+
INLINE_MAX=[0, -1, 8]},
358367
# truncate (O(n^2))
359-
{MODE='LFS_O_TRUNC', SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
368+
{MODE='LFS_O_TRUNC',
369+
SIZE=[32, 0, 7, 200],
370+
CHUNKSIZE=[31, 16, 65],
371+
INLINE_MAX=[0, -1, 8]},
360372
# rewrite (O(n^2))
361-
{MODE=0, SIZE=[32, 0, 7, 200], CHUNKSIZE=[31, 16, 65]},
373+
{MODE=0,
374+
SIZE=[32, 0, 7, 200],
375+
CHUNKSIZE=[31, 16, 65],
376+
INLINE_MAX=[0, -1, 8]},
362377
]
363378
reentrant = true
364379
code = '''

0 commit comments

Comments
 (0)