From ef160a9c5464f1afefbb94873d50667edbfdb0dd Mon Sep 17 00:00:00 2001 From: Nick Craig-Wood Date: Thu, 21 Dec 2023 11:49:56 +0000 Subject: [PATCH] squashfs: cache the last block decompressed in the file for 10x speedup Before this change, we would spend an awful lot of CPU time reading and decompressing the same block to only read a small part from it. This change caches the last block used in the file handle and for typical block sizes used in reads this makes a 10x difference in throughput. --- filesystem/squashfs/file.go | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/filesystem/squashfs/file.go b/filesystem/squashfs/file.go index e7c5790c..1b77d969 100644 --- a/filesystem/squashfs/file.go +++ b/filesystem/squashfs/file.go @@ -13,10 +13,12 @@ import ( // include all of the data type File struct { *extendedFile - isReadWrite bool - isAppend bool - offset int64 - filesystem *FileSystem + isReadWrite bool + isAppend bool + offset int64 + filesystem *FileSystem + blockLocation int64 // the position of the last block decompressed + block []byte // the actual last block decompressed } // Read reads up to len(b) bytes from the File. @@ -99,9 +101,19 @@ func (fl *File) Read(b []byte) (int, error) { if int64(block.size) > fs.blocksize { return read, fmt.Errorf("unexpected block.size=%d > fs.blocksize=%d", block.size, fs.blocksize) } - input, err := fs.readBlock(location, block.compressed, block.size) - if err != nil { - return read, fmt.Errorf("error reading data block %d from squashfs: %v", i, err) + var input []byte + if fl.blockLocation == location && fl.block != nil { + // Read last block from cache + input = fl.block + } else { + var err error + input, err = fs.readBlock(location, block.compressed, block.size) + if err != nil { + return read, fmt.Errorf("error reading data block %d from squashfs: %v", i, err) + } + // Cache the last block + fl.blockLocation = location + fl.block = input } outputBlock(input) }