Skip to content

Commit

Permalink
Merge pull request #1018 from andyzhangx/volume-stat-cache-1.21
Browse files Browse the repository at this point in the history
[release-1.21] fix: add VolumeStats cache to avoid massive statfs calls
  • Loading branch information
andyzhangx authored Sep 14, 2023
2 parents 3951e9e + 1602df8 commit bc58abe
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 2 deletions.
10 changes: 10 additions & 0 deletions pkg/blob/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ type DriverOptions struct {
MountPermissions uint64
KubeAPIQPS float64
KubeAPIBurst int
VolStatsCacheExpireInMinutes int
}

// Driver implements all interfaces of CSI drivers
Expand Down Expand Up @@ -203,6 +204,8 @@ type Driver struct {
dataPlaneAPIVolCache *azcache.TimedCache
// a timed cache storing account search history (solve account list throttling issue)
accountSearchCache *azcache.TimedCache
// a timed cache storing volume stats <volumeID, volumeStats>
volStatsCache *azcache.TimedCache
}

// NewDriver Creates a NewCSIDriver object. Assumes vendor version is equal to driver version &
Expand Down Expand Up @@ -240,6 +243,13 @@ func NewDriver(options *DriverOptions) *Driver {
if d.dataPlaneAPIVolCache, err = azcache.NewTimedcache(10*time.Minute, getter); err != nil {
klog.Fatalf("%v", err)
}

if options.VolStatsCacheExpireInMinutes <= 0 {
options.VolStatsCacheExpireInMinutes = 10 // default expire in 10 minutes
}
if d.volStatsCache, err = azcache.NewTimedcache(time.Duration(options.VolStatsCacheExpireInMinutes)*time.Minute, getter); err != nil {
klog.Fatalf("%v", err)
}
return &d
}

Expand Down
1 change: 1 addition & 0 deletions pkg/blob/blob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func TestNewDriver(t *testing.T) {
fakedriver.Version = driverVersion
fakedriver.accountSearchCache = driver.accountSearchCache
fakedriver.dataPlaneAPIVolCache = driver.dataPlaneAPIVolCache
fakedriver.volStatsCache = driver.volStatsCache
assert.Equal(t, driver, fakedriver)
}

Expand Down
23 changes: 21 additions & 2 deletions pkg/blob/nodeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"time"

volumehelper "sigs.k8s.io/blob-csi-driver/pkg/util"
azcache "sigs.k8s.io/cloud-provider-azure/pkg/cache"

"github.com/Azure/azure-sdk-for-go/storage"
"github.com/container-storage-interface/spec/lib/go/csi"
Expand Down Expand Up @@ -475,13 +476,26 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS
return nil, status.Error(codes.InvalidArgument, "NodeGetVolumeStats volume path was empty")
}

// check if the volume stats is cached
cache, err := d.volStatsCache.Get(req.VolumeId, azcache.CacheReadTypeDefault)
if err != nil {
return nil, status.Errorf(codes.Internal, err.Error())
}
if cache != nil {
resp := cache.(csi.NodeGetVolumeStatsResponse)
klog.V(6).Infof("NodeGetVolumeStats: volume stats for volume %s path %s is cached", req.VolumeId, req.VolumePath)
return &resp, nil
}

if _, err := os.Lstat(req.VolumePath); err != nil {
if os.IsNotExist(err) {
return nil, status.Errorf(codes.NotFound, "path %s does not exist", req.VolumePath)
}
return nil, status.Errorf(codes.Internal, "failed to stat file %s: %v", req.VolumePath, err)
}

klog.V(6).Infof("NodeGetVolumeStats: begin to get VolumeStats on volume %s path %s", req.VolumeId, req.VolumePath)

volumeMetrics, err := volume.NewMetricsStatFS(req.VolumePath).GetMetrics()
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get metrics: %v", err)
Expand Down Expand Up @@ -513,7 +527,7 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS
return nil, status.Errorf(codes.Internal, "failed to transform disk inodes used(%v)", volumeMetrics.InodesUsed)
}

return &csi.NodeGetVolumeStatsResponse{
resp := &csi.NodeGetVolumeStatsResponse{
Usage: []*csi.VolumeUsage{
{
Unit: csi.VolumeUsage_BYTES,
Expand All @@ -528,7 +542,12 @@ func (d *Driver) NodeGetVolumeStats(ctx context.Context, req *csi.NodeGetVolumeS
Used: inodesUsed,
},
},
}, nil
}

klog.V(6).Infof("NodeGetVolumeStats: volume stats for volume %s path %s is %v", req.VolumeId, req.VolumePath, resp)
// cache the volume stats per volume
d.volStatsCache.Set(req.VolumeId, *resp)
return resp, nil
}

// ensureMountPoint: create mount point if not exists
Expand Down

0 comments on commit bc58abe

Please sign in to comment.