Skip to content

Commit 4190aa0

Browse files
committed
Do not return ENOMEM to readers by default, allow them to exceed the memory limit. May be turned back with --use-enomem
1 parent cfb618d commit 4190aa0

File tree

5 files changed

+39
-20
lines changed

5 files changed

+39
-20
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ on:
88
jobs:
99

1010
build:
11-
runs-on: ubuntu-latest
11+
runs-on: ubuntu-22.04
1212
steps:
1313
- uses: actions/checkout@v2
1414

README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -204,10 +204,12 @@ GeeseFS uses RAM for two purposes:
204204

205205
However, that means that more than 10 processes trying to read large files
206206
at the same time may exceed the memory limit by requesting more than 1000 MB
207-
of buffers and in that case GeeseFS will return ENOMEM errors to some of them.
207+
of buffers. Starting with v0.43.0, GeeseFS allows it, but you may turn this
208+
off by using mount option `--use-enomem`, which will make GeeseFS prevent
209+
exceeding memory limit and return ENOMEM errors to some of the processes instead.
208210

209-
You can overcome this problem by either raising `--memory-limit` (for example
210-
to 4 GB) or lowering `--read-ahead-large` (for example to 20 MB).
211+
The other way to overcome this problem is to either raise `--memory-limit` (for
212+
example to 4 GB) or reduce `--read-ahead-large` (for example to 20 MB).
211213

212214
## Maximizing Throughput
213215

core/cfg/config.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ type FlagStorage struct {
5757

5858
// Tuning
5959
MemoryLimit uint64
60+
UseEnomem bool
6061
EntryLimit int
6162
GCInterval uint64
6263
Cheap bool

core/cfg/flags.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,11 @@ MISC OPTIONS:
340340
Value: 1000,
341341
},
342342

343+
cli.BoolFlag{
344+
Name: "use-enomem",
345+
Usage: "Return ENOMEM errors to applications when trying to read too many large files in parallel",
346+
},
347+
343348
cli.IntFlag{
344349
Name: "entry-limit",
345350
Usage: "Maximum metadata entries to cache in memory (1 entry uses ~1 KB of memory)",
@@ -824,6 +829,7 @@ func PopulateFlags(c *cli.Context) (ret *FlagStorage) {
824829

825830
// Tuning,
826831
MemoryLimit: uint64(1024 * 1024 * c.Int("memory-limit")),
832+
UseEnomem: c.Bool("use-enomem"),
827833
EntryLimit: c.Int("entry-limit"),
828834
GCInterval: uint64(1024 * 1024 * c.Int("gc-interval")),
829835
Cheap: c.Bool("cheap"),

core/file.go

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -146,16 +146,20 @@ func (fh *FileHandle) WriteFile(offset int64, data []byte, copyData bool) (err e
146146
}
147147

148148
// Try to reserve space without the inode lock
149-
err = fh.inode.fs.bufferPool.Use(int64(len(data)), false)
150-
if err != nil {
151-
return err
149+
if fh.inode.fs.flags.UseEnomem {
150+
err = fh.inode.fs.bufferPool.Use(int64(len(data)), false)
151+
if err != nil {
152+
return err
153+
}
152154
}
153155

154156
fh.inode.mu.Lock()
155157

156158
if fh.inode.CacheState == ST_DELETED || fh.inode.CacheState == ST_DEAD {
157159
// Oops, it's a deleted file. We don't support changing invisible files
158-
fh.inode.fs.bufferPool.Use(-int64(len(data)), false)
160+
if fh.inode.fs.flags.UseEnomem {
161+
fh.inode.fs.bufferPool.Use(-int64(len(data)), false)
162+
}
159163
fh.inode.mu.Unlock()
160164
return syscall.ENOENT
161165
}
@@ -187,7 +191,9 @@ func (fh *FileHandle) WriteFile(offset int64, data []byte, copyData bool) (err e
187191
fh.inode.mu.Unlock()
188192

189193
// Correct memory usage
190-
if allocated != int64(len(data)) {
194+
if !fh.inode.fs.flags.UseEnomem {
195+
fh.inode.fs.bufferPool.Use(allocated, true)
196+
} else if allocated != int64(len(data)) {
191197
err = fh.inode.fs.bufferPool.Use(allocated-int64(len(data)), true)
192198
}
193199

@@ -330,15 +336,17 @@ func (inode *Inode) LoadRange(offset, size uint64, readAheadSize uint64, ignoreM
330336

331337
func (inode *Inode) retryRead(cloud StorageBackend, key string, offset, size uint64, ignoreMemoryLimit bool) {
332338
// Maybe free some buffers first
333-
err := inode.fs.bufferPool.Use(int64(size), ignoreMemoryLimit)
334-
if err != nil {
335-
log.Errorf("Error reading %v +%v of %v: %v", offset, size, key, err)
336-
inode.mu.Lock()
337-
inode.readError = err
338-
inode.buffers.RemoveLoading(offset, size)
339-
inode.mu.Unlock()
340-
inode.readCond.Broadcast()
341-
return
339+
if inode.fs.flags.UseEnomem {
340+
err := inode.fs.bufferPool.Use(int64(size), ignoreMemoryLimit)
341+
if err != nil {
342+
log.Errorf("Error reading %v +%v of %v: %v", offset, size, key, err)
343+
inode.mu.Lock()
344+
inode.readError = err
345+
inode.buffers.RemoveLoading(offset, size)
346+
inode.mu.Unlock()
347+
inode.readCond.Broadcast()
348+
return
349+
}
342350
}
343351
inode.mu.Lock()
344352
inode.LockRange(offset, size, false)
@@ -348,7 +356,7 @@ func (inode *Inode) retryRead(cloud StorageBackend, key string, offset, size uin
348356
// is temporarily unavailable (err would be io.EOF in that case)
349357
allocated := int64(0)
350358
curOffset, curSize := offset, size
351-
err = ReadBackoff(inode.fs.flags, func(attempt int) error {
359+
err := ReadBackoff(inode.fs.flags, func(attempt int) error {
352360
alloc, done, err := inode.sendRead(cloud, key, curOffset, curSize)
353361
if err != nil && shouldRetry(err) {
354362
s3Log.Warnf("Error reading %v +%v of %v (attempt %v): %v", curOffset, curSize, key, attempt, err)
@@ -358,7 +366,9 @@ func (inode *Inode) retryRead(cloud StorageBackend, key string, offset, size uin
358366
allocated += alloc
359367
return err
360368
})
361-
if allocated != int64(size) {
369+
if !inode.fs.flags.UseEnomem {
370+
inode.fs.bufferPool.Use(int64(allocated), true)
371+
} else if allocated != int64(size) {
362372
inode.fs.bufferPool.Use(int64(allocated)-int64(size), true)
363373
}
364374
inode.mu.Lock()

0 commit comments

Comments
 (0)