Skip to content

Commit 3159e0e

Browse files
committed
Add I/O statistics printer
1 parent c72c0a7 commit 3159e0e

File tree

4 files changed

+132
-14
lines changed

4 files changed

+132
-14
lines changed

api/common/config.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,8 @@ type FlagStorage struct {
9696
DebugS3 bool
9797
Foreground bool
9898
LogFile string
99+
100+
StatsInterval time.Duration
99101
}
100102

101103
func (flags *FlagStorage) GetMimeType(fileName string) (retMime *string) {

internal/file.go

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -560,7 +560,7 @@ func (inode *Inode) OpenCacheFD() error {
560560
// Load some inode data into memory
561561
// Must be called with inode.mu taken
562562
// Loaded range should be guarded against eviction by adding it into inode.readRanges
563-
func (inode *Inode) LoadRange(offset uint64, size uint64, readAheadSize uint64, ignoreMemoryLimit bool) (requestErr error) {
563+
func (inode *Inode) LoadRange(offset uint64, size uint64, readAheadSize uint64, ignoreMemoryLimit bool) (miss bool, requestErr error) {
564564

565565
end := offset+readAheadSize
566566
if size > readAheadSize {
@@ -606,7 +606,7 @@ func (inode *Inode) LoadRange(offset uint64, size uint64, readAheadSize uint64,
606606
} else if b.state == BUF_FL_CLEARED {
607607
// Buffer is saved as a part and then removed
608608
// We must complete multipart upload to be able to read it back
609-
return syscall.ESPIPE
609+
return true, syscall.ESPIPE
610610
}
611611
pos = b.offset+b.length
612612
}
@@ -713,7 +713,7 @@ func (inode *Inode) LoadRange(offset uint64, size uint64, readAheadSize uint64,
713713

714714
if len(diskRequests) > 0 {
715715
if err := inode.OpenCacheFD(); err != nil {
716-
return err
716+
return true, err
717717
}
718718
loadedFromDisk := uint64(0)
719719
for i := 0; i < len(diskRequests); i += 2 {
@@ -722,7 +722,7 @@ func (inode *Inode) LoadRange(offset uint64, size uint64, readAheadSize uint64,
722722
data := make([]byte, requestSize)
723723
_, err := inode.DiskCacheFD.ReadAt(data, int64(requestOffset))
724724
if err != nil {
725-
return err
725+
return true, err
726726
}
727727
pos := locateBuffer(inode.buffers, requestOffset)
728728
var ib *FileBuffer
@@ -754,6 +754,7 @@ func (inode *Inode) LoadRange(offset uint64, size uint64, readAheadSize uint64,
754754
return
755755
}
756756

757+
miss = true
757758
end = offset+size
758759
for {
759760
// Check if all buffers are loaded or if there is a read error
@@ -910,8 +911,8 @@ func (inode *Inode) IsRangeLocked(offset uint64, size uint64, onlyFlushing bool)
910911
return false
911912
}
912913

913-
func (inode *Inode) CheckLoadRange(offset, size, readAheadSize uint64, ignoreMemoryLimit bool) error {
914-
err := inode.LoadRange(offset, size, readAheadSize, ignoreMemoryLimit)
914+
func (inode *Inode) CheckLoadRange(offset, size, readAheadSize uint64, ignoreMemoryLimit bool) (bool, error) {
915+
miss, err := inode.LoadRange(offset, size, readAheadSize, ignoreMemoryLimit)
915916
if err == syscall.ESPIPE {
916917
// Finalize multipart upload to get some flushed data back
917918
// We have to flush all parts that extend the file up until the last flushed part
@@ -933,15 +934,15 @@ func (inode *Inode) CheckLoadRange(offset, size, readAheadSize uint64, ignoreMem
933934
err = inode.SyncFile()
934935
inode.mu.Lock()
935936
if err == nil {
936-
err = inode.LoadRange(offset, size, readAheadSize, ignoreMemoryLimit)
937+
_, err = inode.LoadRange(offset, size, readAheadSize, ignoreMemoryLimit)
937938
}
938939
}
939940
inode.pauseWriters--
940941
if inode.readCond != nil {
941942
inode.readCond.Broadcast()
942943
}
943944
}
944-
return err
945+
return miss, err
945946
}
946947

947948
func appendZero(data [][]byte, zeroBuf []byte, zeroLen int) [][]byte {
@@ -1022,7 +1023,6 @@ func (fh *FileHandle) ReadFile(sOffset int64, sLen int64) (data [][]byte, bytesR
10221023
defer fh.inode.UnlockRange(offset, end-offset, false)
10231024

10241025
// Check if anything requires to be loaded from the server
1025-
var requestErr error
10261026
ra := fh.inode.fs.flags.ReadAheadKB*1024
10271027
if fh.seqReadSize >= fh.inode.fs.flags.LargeReadCutoffKB*1024 {
10281028
// Use larger readahead with 'pipelining'
@@ -1038,7 +1038,10 @@ func (fh *FileHandle) ReadFile(sOffset int64, sLen int64) (data [][]byte, bytesR
10381038
if ra+end > maxFileSize {
10391039
ra = 0
10401040
}
1041-
requestErr = fh.inode.CheckLoadRange(offset, end-offset, ra, false)
1041+
miss, requestErr := fh.inode.CheckLoadRange(offset, end-offset, ra, false)
1042+
if !miss {
1043+
atomic.AddInt64(&fh.inode.fs.stats.readHits, 1)
1044+
}
10421045
mappedErr := mapAwsError(requestErr)
10431046
if requestErr != nil {
10441047
err = requestErr
@@ -1676,7 +1679,7 @@ func (inode *Inode) FlushSmallObject() {
16761679
inode.LockRange(0, sz, true)
16771680

16781681
if inode.CacheState == ST_MODIFIED {
1679-
err := inode.LoadRange(0, sz, 0, true)
1682+
_, err := inode.LoadRange(0, sz, 0, true)
16801683
mappedErr := mapAwsError(err)
16811684
if mappedErr == fuse.ENOENT || mappedErr == syscall.ERANGE {
16821685
// Object is deleted or resized remotely (416). Discard local version
@@ -1873,7 +1876,7 @@ func (inode *Inode) FlushPart(part uint64) {
18731876
// Ignore memory limit to not produce a deadlock when we need to free some memory
18741877
// by flushing objects, but we can't flush a part without allocating more memory
18751878
// for read-modify-write...
1876-
err := inode.LoadRange(partOffset, partSize, 0, true)
1879+
_, err := inode.LoadRange(partOffset, partSize, 0, true)
18771880
if err == syscall.ESPIPE {
18781881
// Part is partly evicted, we can't flush it
18791882
return

internal/flags.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,12 @@ func NewApp() (app *cli.App) {
519519
Usage: "Redirect logs to file, 'stderr' (default for foreground) or 'syslog' (default for background).",
520520
Value: "",
521521
},
522+
523+
cli.DurationFlag{
524+
Name: "print-stats",
525+
Value: 30 * time.Second,
526+
Usage: "I/O statistics printing interval. Set to 0 to disable.",
527+
},
522528
}
523529

524530
app = &cli.App{
@@ -699,6 +705,7 @@ func PopulateFlags(c *cli.Context) (ret *FlagStorage) {
699705
DebugS3: c.Bool("debug_s3"),
700706
Foreground: c.Bool("f"),
701707
LogFile: c.String("log-file"),
708+
StatsInterval: c.Duration("print-stats"),
702709
}
703710

704711
flags.PartSizes = parsePartSizes(c.String("part-sizes"))

0 commit comments

Comments
 (0)