github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/inode/payload.go (about)

     1  package inode
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  
     7  	"github.com/swiftstack/ProxyFS/evtlog"
     8  	"github.com/swiftstack/ProxyFS/logger"
     9  	"github.com/swiftstack/ProxyFS/stats"
    10  
    11  	"github.com/swiftstack/cstruct"
    12  	"github.com/swiftstack/sortedmap"
    13  )
    14  
    15  // For DirType inodes, our payload tree-map is from basenames to inode numbers.
    16  // For FileType inodes, our payload tree-map is from file offsets to file extents.
    17  
    18  // The signature of the pack/unpack methods says that failure is not an option
    19  // (which is OK because it's reasonable to expect a well-defined data structure to
    20  // have a well-defined serialization/deserialization), which is why our unpack
    21  // methods have so many panic codepaths (that we expect to never run).
    22  
    23  type treeNodeLoadable struct {
    24  	inode *inMemoryInodeStruct
    25  }
    26  
    27  func (tnl *treeNodeLoadable) GetNode(objectNumber uint64, objectOffset uint64, objectLength uint64) (nodeByteSlice []byte, err error) {
    28  	var (
    29  		inodeNumberAdordnedWithSnapShotID uint64
    30  		objectNumberAdordedWithSnapShotID uint64
    31  	)
    32  
    33  	inodeNumberAdordnedWithSnapShotID = tnl.inode.volume.headhunterVolumeHandle.SnapShotIDAndNonceEncode(tnl.inode.snapShotID, uint64(tnl.inode.InodeNumber))
    34  	objectNumberAdordedWithSnapShotID = tnl.inode.volume.headhunterVolumeHandle.SnapShotIDAndNonceEncode(tnl.inode.snapShotID, objectNumber)
    35  
    36  	if 0 != objectOffset {
    37  		err = fmt.Errorf("*treeNodeLoadable.GetNode(): Unexpected (non-zero) objectOffset (%v)", objectOffset)
    38  		return
    39  	}
    40  
    41  	stats.IncrementOperations(&stats.DirFileBPlusTreeNodeFaults)
    42  	evtlog.Record(evtlog.FormatDirFileBPlusTreeNodeFault, tnl.inode.volume.volumeName, inodeNumberAdordnedWithSnapShotID, objectNumberAdordedWithSnapShotID)
    43  
    44  	nodeByteSlice, err = tnl.inode.volume.headhunterVolumeHandle.GetBPlusTreeObject(objectNumberAdordedWithSnapShotID)
    45  
    46  	if (nil == err) && (uint64(len(nodeByteSlice)) != objectLength) {
    47  		err = fmt.Errorf("*treeNodeLoadable.GetNode(): Requested objectLength (%v) != Actual objectLength (%v)", objectLength, len(nodeByteSlice))
    48  		return
    49  	}
    50  
    51  	return
    52  }
    53  
    54  func (tnl *treeNodeLoadable) PutNode(nodeByteSlice []byte) (objectNumber uint64, objectOffset uint64, err error) {
    55  	objectNumber = tnl.inode.volume.headhunterVolumeHandle.FetchNonce()
    56  
    57  	objectOffset = 0
    58  
    59  	err = tnl.inode.volume.headhunterVolumeHandle.PutBPlusTreeObject(objectNumber, nodeByteSlice)
    60  
    61  	return
    62  }
    63  
    64  func (tnl *treeNodeLoadable) DiscardNode(objectNumber uint64, objectOffset uint64, objectLength uint64) (err error) {
    65  	logger.Tracef("inode.Discardnode(): volume '%s' inode %d: "+
    66  		"root Object %016X  discarding Object %016X  len %d",
    67  		tnl.inode.volume.volumeName, tnl.inode.onDiskInodeV1Struct.InodeNumber,
    68  		tnl.inode.onDiskInodeV1Struct.PayloadObjectNumber,
    69  		objectNumber, objectLength)
    70  
    71  	if 0 != objectOffset {
    72  		err = fmt.Errorf("*treeNodeLoadable.DiscardNode(): Unexpected (non-zero) objectOffset (%v)", objectOffset)
    73  		return
    74  	}
    75  
    76  	// Tell Headhunter we are done with this persisted node
    77  
    78  	err = tnl.inode.volume.headhunterVolumeHandle.DeleteBPlusTreeObject(objectNumber)
    79  
    80  	return
    81  }
    82  
    83  type fileInodeCallbacks struct {
    84  	treeNodeLoadable
    85  }
    86  
    87  func (c *fileInodeCallbacks) DumpKey(key sortedmap.Key) (keyAsString string, err error) {
    88  	keyAsUint64, ok := key.(uint64)
    89  	if !ok {
    90  		err = fmt.Errorf("fileInodeCallbacks.DumpKey() could not parse key as a uint64")
    91  		return
    92  	}
    93  
    94  	keyAsString = fmt.Sprintf("0x%016X", keyAsUint64)
    95  
    96  	err = nil
    97  	return
    98  }
    99  
   100  func (c *fileInodeCallbacks) DumpValue(value sortedmap.Value) (valueAsString string, err error) {
   101  	valueAsFileExtentPtr, ok := value.(*fileExtentStruct)
   102  	if !ok {
   103  		err = fmt.Errorf("fileInodeCallbacks.DumpValue() could not parse key as a *fileExtent")
   104  		return
   105  	}
   106  
   107  	valueAsString = fmt.Sprintf("@%p: %#v", valueAsFileExtentPtr, valueAsFileExtentPtr)
   108  
   109  	err = nil
   110  	return
   111  }
   112  
   113  func (c *fileInodeCallbacks) PackKey(key sortedmap.Key) (packedKey []byte, err error) {
   114  	packedKey, err = cstruct.Pack(key, sortedmap.OnDiskByteOrder)
   115  	return
   116  }
   117  
   118  func (c *fileInodeCallbacks) PackValue(value sortedmap.Value) (packedValue []byte, err error) {
   119  	fileExtent, ok := value.(*fileExtentStruct)
   120  	if !ok {
   121  		err = fmt.Errorf("PackValue() arg is not a *fileExtentStruct")
   122  		return
   123  	}
   124  	packedValue, err = cstruct.Pack(fileExtent, sortedmap.OnDiskByteOrder)
   125  	if nil != err {
   126  		return
   127  	}
   128  	if uint64(len(packedValue)) != globals.fileExtentStructSize {
   129  		err = fmt.Errorf("PackValue() should have produced len(packedValue) == %v", globals.fileExtentStructSize)
   130  	}
   131  	return
   132  }
   133  
   134  func (c *fileInodeCallbacks) UnpackKey(payloadData []byte) (key sortedmap.Key, bytesConsumed uint64, err error) {
   135  	var fileOffset uint64
   136  	bytesConsumed, err = cstruct.Unpack(payloadData, &fileOffset, sortedmap.OnDiskByteOrder)
   137  	if nil != err {
   138  		return
   139  	}
   140  	key = fileOffset
   141  	return
   142  }
   143  
   144  func (c *fileInodeCallbacks) UnpackValue(payloadData []byte) (value sortedmap.Value, bytesConsumed uint64, err error) {
   145  	if uint64(len(payloadData)) < globals.fileExtentStructSize {
   146  		err = fmt.Errorf("UnpackValue() arg not big enough to encode fileExtentStruct")
   147  		return
   148  	}
   149  	valueAsFileExtentPtr := &fileExtentStruct{}
   150  	_, err = cstruct.Unpack(payloadData, valueAsFileExtentPtr, sortedmap.OnDiskByteOrder)
   151  	if nil != err {
   152  		return
   153  	}
   154  	value = valueAsFileExtentPtr
   155  	bytesConsumed = globals.fileExtentStructSize
   156  	err = nil
   157  	return
   158  }
   159  
   160  type dirInodeCallbacks struct {
   161  	treeNodeLoadable
   162  }
   163  
   164  func (c *dirInodeCallbacks) DumpKey(key sortedmap.Key) (keyAsString string, err error) {
   165  	keyAsString, ok := key.(string)
   166  
   167  	if ok {
   168  		err = nil
   169  	} else {
   170  		err = fmt.Errorf("dirInodeCallbacks.DumpKey() could not parse key as a string")
   171  	}
   172  
   173  	return
   174  }
   175  
   176  func (c *dirInodeCallbacks) DumpValue(value sortedmap.Value) (valueAsString string, err error) {
   177  	valueAsUint64, ok := value.(InodeNumber)
   178  	if !ok {
   179  		err = fmt.Errorf("dirInodeCallbacks.DumpValue() could not parse value as a uint64")
   180  		return
   181  	}
   182  
   183  	valueAsString = fmt.Sprintf("0x%016X", valueAsUint64)
   184  
   185  	err = nil
   186  	return
   187  }
   188  
   189  func (c *dirInodeCallbacks) PackKey(key sortedmap.Key) (packedKey []byte, err error) {
   190  	basename, ok := key.(string)
   191  	if !ok {
   192  		err = fmt.Errorf("PackKey() arg not a string")
   193  		return
   194  	}
   195  	packedKey = []byte(basename)
   196  	packedKey = append(packedKey, 0) // null terminator
   197  	err = nil
   198  	return
   199  }
   200  
   201  func (c *dirInodeCallbacks) PackValue(value sortedmap.Value) (packedValue []byte, err error) {
   202  	valueAsInodeNumber, ok := value.(InodeNumber)
   203  	if !ok {
   204  		err = fmt.Errorf("PackValue() arg is not an InodeNumber")
   205  		return
   206  	}
   207  	valueAsUint64 := uint64(valueAsInodeNumber)
   208  	packedValue, err = cstruct.Pack(valueAsUint64, sortedmap.OnDiskByteOrder)
   209  	return
   210  }
   211  
   212  func (c *dirInodeCallbacks) UnpackKey(payloadData []byte) (key sortedmap.Key, bytesConsumed uint64, err error) {
   213  	basenameAndRemainderBytes := bytes.SplitN(payloadData, []byte{0}, 2)
   214  	basenameBytes := basenameAndRemainderBytes[0]
   215  	basename := string(basenameBytes)
   216  	key = basename
   217  	bytesConsumed = uint64(len(basenameBytes) + 1)
   218  	err = nil
   219  	return
   220  }
   221  
   222  func (c *dirInodeCallbacks) UnpackValue(payloadData []byte) (value sortedmap.Value, bytesConsumed uint64, err error) {
   223  	var valueAsUint64 uint64
   224  	bytesConsumed, err = cstruct.Unpack(payloadData, &valueAsUint64, sortedmap.OnDiskByteOrder)
   225  	if nil != err {
   226  		return
   227  	}
   228  	value = InodeNumber(valueAsUint64)
   229  	bytesConsumed = 8
   230  	return
   231  }