Skip to content

Commit 91c42e3

Browse files
committed
Add support for variable length metadata
Signed-off-by: Prasad Ghangal <[email protected]>
1 parent dd68929 commit 91c42e3

File tree

4 files changed

+138
-18
lines changed

4 files changed

+138
-18
lines changed

cmd/hostpathplugin/main.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,11 @@ import (
2525
"path"
2626
"syscall"
2727

28+
"k8s.io/klog/v2"
29+
30+
"github.com/container-storage-interface/spec/lib/go/csi"
2831
"github.com/kubernetes-csi/csi-driver-host-path/internal/proxy"
2932
"github.com/kubernetes-csi/csi-driver-host-path/pkg/hostpath"
30-
"k8s.io/klog/v2"
3133
)
3234

3335
var (
@@ -57,6 +59,7 @@ func main() {
5759
flag.BoolVar(&cfg.EnableControllerModifyVolume, "enable-controller-modify-volume", false, "Enables Controller modify volume feature.")
5860
// TODO: Remove this feature flag and enable SnapshotMetadata service by default once external-snapshot-metadata alpha is released.
5961
flag.BoolVar(&cfg.EnableSnapshotMetadata, "enable-snapshot-metadata", false, "Enables Snapshot Metadata service.")
62+
snapshotMetadataBlockType := flag.String("snapshot-metadata-block-type", "FIXED_LENGTH", "Expected Snapshot Metadata block type in response. Allowed valid types are FIXED_LENGTH or VARIABLE_LENGTH. If not specified, FIXED_LENGTH is used by default.")
6063
flag.Var(&cfg.AcceptedMutableParameterNames, "accepted-mutable-parameter-names", "Comma separated list of parameter names that can be modified on a persistent volume. This is only used when enable-controller-modify-volume is true. If unset, all parameters are mutable.")
6164
flag.BoolVar(&cfg.DisableControllerExpansion, "disable-controller-expansion", false, "Disables Controller volume expansion capability.")
6265
flag.BoolVar(&cfg.DisableNodeExpansion, "disable-node-expansion", false, "Disables Node volume expansion capability.")
@@ -108,6 +111,14 @@ func main() {
108111
cfg.MaxVolumeExpansionSizeNode = cfg.MaxVolumeSize
109112
}
110113

114+
// validate snapshot-metadata-type arg block type
115+
bt, ok := csi.BlockMetadataType_value[*snapshotMetadataBlockType]
116+
if !ok {
117+
fmt.Printf("invalid snapshot-metadata-block-type passed, please pass one of the - FIXED_LENGTH, VARIABLE_LENGTH")
118+
os.Exit(1)
119+
}
120+
cfg.SnapshotMetadataBlockType = csi.BlockMetadataType(bt)
121+
111122
driver, err := hostpath.NewHostPathDriver(cfg)
112123
if err != nil {
113124
fmt.Printf("Failed to initialize driver: %s", err.Error())

pkg/hostpath/hostpath.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ type Config struct {
8282
EnableVolumeExpansion bool
8383
EnableControllerModifyVolume bool
8484
EnableSnapshotMetadata bool
85+
SnapshotMetadataBlockType csi.BlockMetadataType
8586
AcceptedMutableParameterNames StringArray
8687
DisableControllerExpansion bool
8788
DisableNodeExpansion bool

pkg/hostpath/snapshotmetadata.go

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,14 @@ func (hp *hostPath) compareBlocks(ctx context.Context, source, target *os.File,
120120
}
121121
return nil
122122
}
123-
changedBlocks = append(changedBlocks, createBlockMetadata(blockIndex, blockSize))
123+
// if VARIABLE_LENGTH type is enabled, return blocks extend instead of individual blocks.
124+
blockMetadata := createBlockMetadata(blockIndex, blockSize)
125+
if extendBlock(changedBlocks, csi.BlockMetadataType(hp.config.SnapshotMetadataBlockType), blockIndex, blockSize) {
126+
changedBlocks[len(changedBlocks)-1].SizeBytes += blockSize
127+
blockIndex++
128+
continue
129+
}
130+
changedBlocks = append(changedBlocks, blockMetadata)
124131
blockIndex++
125132
continue
126133
}
@@ -143,8 +150,15 @@ func (hp *hostPath) compareBlocks(ctx context.Context, source, target *os.File,
143150
// Compare the two blocks and add result.
144151
// Even if one of the file reaches to end, continue to add block metadata of other file.
145152
if blockChanged(sBuffer[:sourceReadBytes], tBuffer[:targetReadBytes]) {
146-
// TODO: Support for VARIABLE sized block metadata
147-
changedBlocks = append(changedBlocks, createBlockMetadata(blockIndex, blockSize))
153+
blockMetadata := createBlockMetadata(blockIndex, blockSize)
154+
// if VARIABLE_LEGTH type is enabled, check if blocks are adjacent,
155+
// extend the previous block if adjacent blocks found instead of adding new entry.
156+
if extendBlock(changedBlocks, csi.BlockMetadataType(hp.config.SnapshotMetadataBlockType), blockIndex, blockSize) {
157+
changedBlocks[len(changedBlocks)-1].SizeBytes += blockSize
158+
blockIndex++
159+
continue
160+
}
161+
changedBlocks = append(changedBlocks, blockMetadata)
148162
}
149163

150164
blockIndex++
@@ -181,3 +195,18 @@ func createBlockMetadata(blockIndex, blockSize int64) *csi.BlockMetadata {
181195
SizeBytes: blockSize,
182196
}
183197
}
198+
199+
func extendBlock(changedBlocks []*csi.BlockMetadata, metadataType csi.BlockMetadataType, blockIndex, blockSize int64) bool {
200+
blockMetadata := createBlockMetadata(blockIndex, blockSize)
201+
// if VARIABLE_LEGTH type is enabled, check if blocks are adjacent,
202+
// extend the previous block if adjacent blocks found instead of adding new entry.
203+
if len(changedBlocks) < 1 {
204+
return false
205+
}
206+
lastBlock := changedBlocks[len(changedBlocks)-1]
207+
if blockMetadata.ByteOffset == lastBlock.ByteOffset+lastBlock.SizeBytes &&
208+
metadataType == csi.BlockMetadataType_VARIABLE_LENGTH {
209+
return true
210+
}
211+
return false
212+
}

pkg/hostpath/snapshotmetadata_test.go

Lines changed: 93 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,14 +28,15 @@ import (
2828

2929
func TestGetChangedBlockMetadata(t *testing.T) {
3030
testCases := []struct {
31-
name string
32-
sourceFileBlocks int
33-
targetFileBlocks int
34-
changedBlocks []int
35-
startingOffset int64
36-
maxResult int32
37-
expectedResponse []*csi.BlockMetadata
38-
expectErr bool
31+
name string
32+
sourceFileBlocks int
33+
targetFileBlocks int
34+
changedBlocks []int
35+
blockMetadataType csi.BlockMetadataType
36+
startingOffset int64
37+
maxResult int32
38+
expectedResponse []*csi.BlockMetadata
39+
expectErr bool
3940
}{
4041
{
4142
name: "success case",
@@ -211,6 +212,57 @@ func TestGetChangedBlockMetadata(t *testing.T) {
211212
},
212213
expectErr: false,
213214
},
215+
{
216+
name: "success case with variable block sizes",
217+
sourceFileBlocks: 100,
218+
targetFileBlocks: 100,
219+
changedBlocks: []int{3, 4, 5, 6, 7, 47, 48, 49, 51},
220+
blockMetadataType: csi.BlockMetadataType_VARIABLE_LENGTH,
221+
maxResult: 100,
222+
expectedResponse: []*csi.BlockMetadata{
223+
{
224+
ByteOffset: 3 * state.BlockSizeBytes,
225+
SizeBytes: state.BlockSizeBytes * 5,
226+
},
227+
{
228+
ByteOffset: 47 * state.BlockSizeBytes,
229+
SizeBytes: state.BlockSizeBytes * 3,
230+
},
231+
{
232+
ByteOffset: 51 * state.BlockSizeBytes,
233+
SizeBytes: state.BlockSizeBytes,
234+
},
235+
},
236+
expectErr: false,
237+
},
238+
{
239+
name: "success case with starting offset and variable length",
240+
sourceFileBlocks: 100,
241+
targetFileBlocks: 100,
242+
changedBlocks: []int{2, 4, 7, 10, 13, 14, 30, 65},
243+
blockMetadataType: csi.BlockMetadataType_VARIABLE_LENGTH,
244+
startingOffset: 9 * state.BlockSizeBytes,
245+
maxResult: 3,
246+
expectedResponse: []*csi.BlockMetadata{
247+
{
248+
ByteOffset: 10 * state.BlockSizeBytes,
249+
SizeBytes: state.BlockSizeBytes,
250+
},
251+
{
252+
ByteOffset: 13 * state.BlockSizeBytes,
253+
SizeBytes: state.BlockSizeBytes * 2,
254+
},
255+
{
256+
ByteOffset: 30 * state.BlockSizeBytes,
257+
SizeBytes: state.BlockSizeBytes,
258+
},
259+
{
260+
ByteOffset: 65 * state.BlockSizeBytes,
261+
SizeBytes: state.BlockSizeBytes,
262+
},
263+
},
264+
expectErr: false,
265+
},
214266
}
215267

216268
for _, tc := range testCases {
@@ -238,6 +290,7 @@ func TestGetChangedBlockMetadata(t *testing.T) {
238290
MaxVolumeSize: 1024 * 1024 * 1024 * 1024,
239291
EnableTopology: true,
240292
EnableControllerModifyVolume: true,
293+
SnapshotMetadataBlockType: tc.blockMetadataType,
241294
}
242295

243296
hp, err := NewHostPathDriver(cfg)
@@ -322,12 +375,13 @@ func modifyBlock(t *testing.T, file *os.File, blockNumber int, newContent []byte
322375

323376
func TestGetAllocatedBlockMetadata(t *testing.T) {
324377
testCases := []struct {
325-
name string
326-
fileBlocks int
327-
startingOffset int64
328-
maxResult int32
329-
expectedBlocks []int
330-
expectErr bool
378+
name string
379+
fileBlocks int
380+
startingOffset int64
381+
blockMetadataType csi.BlockMetadataType
382+
maxResult int32
383+
expectedBlocks []int
384+
expectErr bool
331385
}{
332386
{
333387
name: "success case",
@@ -350,6 +404,22 @@ func TestGetAllocatedBlockMetadata(t *testing.T) {
350404
expectedBlocks: []int{4, 5, 6, 7, 8, 9},
351405
maxResult: 3,
352406
},
407+
{
408+
name: "success case with variable block types",
409+
fileBlocks: 5,
410+
blockMetadataType: csi.BlockMetadataType_VARIABLE_LENGTH,
411+
maxResult: 100,
412+
expectedBlocks: []int{0},
413+
expectErr: false,
414+
},
415+
{
416+
name: "success case with starting offset and variable length",
417+
fileBlocks: 10,
418+
startingOffset: 4 * state.BlockSizeBytes,
419+
blockMetadataType: csi.BlockMetadataType_VARIABLE_LENGTH,
420+
expectedBlocks: []int{4},
421+
maxResult: 10,
422+
},
353423
}
354424

355425
for _, tc := range testCases {
@@ -371,6 +441,7 @@ func TestGetAllocatedBlockMetadata(t *testing.T) {
371441
MaxVolumeSize: 1024 * 1024 * 1024 * 1024,
372442
EnableTopology: true,
373443
EnableControllerModifyVolume: true,
444+
SnapshotMetadataBlockType: tc.blockMetadataType,
374445
}
375446

376447
hp, err := NewHostPathDriver(cfg)
@@ -403,6 +474,14 @@ func TestGetAllocatedBlockMetadata(t *testing.T) {
403474
if len(tc.expectedBlocks) != len(response) {
404475
t.Fatalf("expected %d changed blocks metadata, got: %d", tc.fileBlocks, len(response))
405476
}
477+
if tc.blockMetadataType == csi.BlockMetadataType_VARIABLE_LENGTH {
478+
expCB := createBlockMetadata(int64(tc.expectedBlocks[0]), state.BlockSizeBytes)
479+
expCB.SizeBytes = int64(tc.fileBlocks-tc.expectedBlocks[0]) * state.BlockSizeBytes
480+
if response[0].String() != expCB.String() {
481+
t.Fatalf("received unexpected block metadata, expected: %s\n, got %s", expCB.String(), response[0].String())
482+
}
483+
return
484+
}
406485
for i := 0; i < len(tc.expectedBlocks); i++ {
407486
expCB := createBlockMetadata(int64(tc.expectedBlocks[i]), state.BlockSizeBytes)
408487
if response[i].String() != expCB.String() {

0 commit comments

Comments
 (0)