Skip to content

Commit 389136c

Browse files
Fix issues while truncating the file (#2003)
Co-authored-by: Vikas Bhansali <64532198+vibhansa-msft@users.noreply.github.com> Co-authored-by: vibhansa <vibhansa@microsoft.com>
1 parent 2d74e12 commit 389136c

27 files changed

+693
-252
lines changed

.golangci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,4 +54,4 @@ formatters:
5454
paths:
5555
- third_party$
5656
- builtin$
57-
- examples$
57+
- examples$

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@
33
- Fail file open operation if the file being downloaded by file-cache can not fit in available disk space (either configured by user or computed implicitly by blobfuse). User application will receive ENOSPC (no space left on device) in response to file open call.
44
- Mount will fail if FNS account is mounted as HNS account.
55
- Redirect Stack trace to log file (WORK_DIR/mount_path.pid.trace) instead of console in case of panic for better debuggability.
6+
- Truncating the file in file_cache resulting in OOM panic by go-runtime in some scenarios.
7+
- Open file error(No BlockList error) in block_cache when file is truncated before to less than 256MiB.
8+
- Prevent reusing the same block ID in truncate operation which could lead to issues.
9+
610

711
## 2.5.0 (2025-07-17)
812
**Bug Fixes**

azure-pipeline-templates/verbose-tests.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,20 @@ steps:
221221

222222
#--------------------------------------- Tests: End to end tests with different File Cache configurations ------------------------------------------
223223

224+
- template: e2e-tests-spcl.yml
225+
parameters:
226+
conf_template: azure_key_directio.yaml
227+
config_file: ${{ parameters.config }}
228+
adls: ${{ parameters.adls }}
229+
account_name: ${{ parameters.account_name }}
230+
account_key: ${{ parameters.account_key }}
231+
account_type: ${{ parameters.account_type }}
232+
idstring: "${{ parameters.service }} with File-cache"
233+
distro_name: ${{ parameters.distro_name }}
234+
quick_test: false
235+
verbose_log: ${{ parameters.verbose_log }}
236+
clone: false
237+
224238
- template: e2e-tests-spcl.yml
225239
parameters:
226240
conf_template: azure_key_lru_purge.yaml

common/types.go

Lines changed: 34 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -154,12 +154,11 @@ type LogConfig struct {
154154
Tag string // logging tag which can be either blobfuse2 or bfusemon
155155
}
156156

157-
// Flags for blocks
157+
// Flags for block
158158
const (
159159
BlockFlagUnknown uint16 = iota
160160
DirtyBlock
161161
TruncatedBlock
162-
RemovedBlocks
163162
)
164163

165164
type Block struct {
@@ -181,14 +180,11 @@ func (block *Block) Truncated() bool {
181180
return block.Flags.IsSet(TruncatedBlock)
182181
}
183182

184-
func (block *Block) Removed() bool {
185-
return block.Flags.IsSet(RemovedBlocks)
186-
}
187-
188183
// Flags for block offset list
189184
const (
190-
BolFlagUnknown uint16 = iota
191-
SmallFile
185+
BlobFlagUnknown uint16 = iota
186+
BlobFlagHasNoBlocks // set if the blob does not have any blocks
187+
BlobFlagBlockListModified
192188
)
193189

194190
// list that holds blocks containing ids and corresponding offsets
@@ -200,13 +196,39 @@ type BlockOffsetList struct {
200196
Mtime time.Time
201197
}
202198

203-
// Dirty : Handle is dirty or not
204-
func (bol *BlockOffsetList) SmallFile() bool {
205-
return bol.Flags.IsSet(SmallFile)
199+
func (bol *BlockOffsetList) HasNoBlocks() bool {
200+
return len(bol.BlockList) == 0
201+
}
202+
203+
func (bol *BlockOffsetList) IsBlockListModified() bool {
204+
return bol.Flags.IsSet(BlobFlagBlockListModified)
205+
}
206+
207+
func (bol *BlockOffsetList) ValidateBlockListAgainstFileSize(fileSize int64) bool {
208+
if bol.HasNoBlocks() {
209+
return fileSize == 0
210+
}
211+
if bol.BlockList[len(bol.BlockList)-1].EndIndex != fileSize {
212+
return false
213+
}
214+
return true
215+
}
216+
217+
func (bol *BlockOffsetList) HasAllBlocksWithSameBlockSize() (blockSize int64, ok bool) {
218+
if bol.HasNoBlocks() {
219+
return 0, true
220+
}
221+
blockSize = bol.BlockList[0].EndIndex - bol.BlockList[0].StartIndex
222+
for _, blk := range bol.BlockList {
223+
if blk.EndIndex-blk.StartIndex != blockSize {
224+
return 0, false
225+
}
226+
}
227+
return blockSize, true
206228
}
207229

208230
// return true if item found and index of the item
209-
func (bol BlockOffsetList) BinarySearch(offset int64) (bool, int) {
231+
func (bol *BlockOffsetList) BinarySearch(offset int64) (bool, int) {
210232
lowerBound := 0
211233
size := len(bol.BlockList)
212234
higherBound := size - 1

component/attr_cache/attr_cache.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -494,7 +494,7 @@ func (ac *AttrCache) TruncateFile(options internal.TruncateFileOptions) error {
494494
// no need to truncate the name of the file
495495
value, found := ac.cacheMap[options.Name]
496496
if found && value.valid() && value.exists() {
497-
value.setSize(options.Size)
497+
value.setSize(options.NewSize)
498498
}
499499
// todo: invalidating path here rather than updating with etag
500500
// due to some changes that are required in az storage comp which

component/attr_cache/attr_cache_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ func (suite *attrCacheTestSuite) TestTruncateFile() {
792792
path := "a"
793793
size := 1024
794794

795-
options := internal.TruncateFileOptions{Name: path, Size: int64(size)}
795+
options := internal.TruncateFileOptions{Name: path, NewSize: int64(size)}
796796

797797
// Error
798798
suite.mock.EXPECT().TruncateFile(options).Return(errors.New("Failed to truncate a file"))

component/azstorage/azstorage.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -498,11 +498,11 @@ func (az *AzStorage) GetFileBlockOffsets(options internal.GetFileBlockOffsetsOpt
498498
}
499499

500500
func (az *AzStorage) TruncateFile(options internal.TruncateFileOptions) error {
501-
log.Trace("AzStorage::TruncateFile : %s to %d bytes", options.Name, options.Size)
502-
err := az.storage.TruncateFile(options.Name, options.Size)
501+
log.Trace("AzStorage::TruncateFile : %s to %d bytes", options.Name, options.NewSize)
502+
err := az.storage.TruncateFile(options)
503503

504504
if err == nil {
505-
azStatsCollector.PushEvents(truncateFile, options.Name, map[string]any{size: options.Size})
505+
azStatsCollector.PushEvents(truncateFile, options.Name, map[string]any{size: options.NewSize})
506506
azStatsCollector.UpdateStats(stats_manager.Increment, truncateFile, (int64)(1))
507507
}
508508
return err

0 commit comments

Comments
 (0)