ec_locate.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package erasure_coding
  2. import (
  3. "github.com/seaweedfs/seaweedfs/weed/storage/types"
  4. )
  5. type Interval struct {
  6. BlockIndex int // the index of the block in either the large blocks or the small blocks
  7. InnerBlockOffset int64
  8. Size types.Size
  9. IsLargeBlock bool // whether the block is a large block or a small block
  10. LargeBlockRowsCount int
  11. }
  12. func LocateData(largeBlockLength, smallBlockLength int64, shardDatSize int64, offset int64, size types.Size) (intervals []Interval) {
  13. blockIndex, isLargeBlock, nLargeBlockRows, innerBlockOffset := locateOffset(largeBlockLength, smallBlockLength, shardDatSize, offset)
  14. for size > 0 {
  15. interval := Interval{
  16. BlockIndex: blockIndex,
  17. InnerBlockOffset: innerBlockOffset,
  18. IsLargeBlock: isLargeBlock,
  19. LargeBlockRowsCount: int(nLargeBlockRows),
  20. }
  21. blockRemaining := largeBlockLength - innerBlockOffset
  22. if !isLargeBlock {
  23. blockRemaining = smallBlockLength - innerBlockOffset
  24. }
  25. if int64(size) <= blockRemaining {
  26. interval.Size = size
  27. intervals = append(intervals, interval)
  28. return
  29. }
  30. interval.Size = types.Size(blockRemaining)
  31. intervals = append(intervals, interval)
  32. size -= interval.Size
  33. blockIndex += 1
  34. if isLargeBlock && blockIndex == interval.LargeBlockRowsCount*DataShardsCount {
  35. isLargeBlock = false
  36. blockIndex = 0
  37. }
  38. innerBlockOffset = 0
  39. }
  40. return
  41. }
  42. func locateOffset(largeBlockLength, smallBlockLength int64, shardDatSize int64, offset int64) (blockIndex int, isLargeBlock bool, nLargeBlockRows int64, innerBlockOffset int64) {
  43. largeRowSize := largeBlockLength * DataShardsCount
  44. nLargeBlockRows = (shardDatSize-1)/ largeBlockLength
  45. // if offset is within the large block area
  46. if offset < nLargeBlockRows*largeRowSize {
  47. isLargeBlock = true
  48. blockIndex, innerBlockOffset = locateOffsetWithinBlocks(largeBlockLength, offset)
  49. return
  50. }
  51. isLargeBlock = false
  52. offset -= nLargeBlockRows * largeRowSize
  53. blockIndex, innerBlockOffset = locateOffsetWithinBlocks(smallBlockLength, offset)
  54. return
  55. }
  56. func locateOffsetWithinBlocks(blockLength int64, offset int64) (blockIndex int, innerBlockOffset int64) {
  57. blockIndex = int(offset / blockLength)
  58. innerBlockOffset = offset % blockLength
  59. return
  60. }
  61. func (interval Interval) ToShardIdAndOffset(largeBlockSize, smallBlockSize int64) (ShardId, int64) {
  62. ecFileOffset := interval.InnerBlockOffset
  63. rowIndex := interval.BlockIndex / DataShardsCount
  64. if interval.IsLargeBlock {
  65. ecFileOffset += int64(rowIndex) * largeBlockSize
  66. } else {
  67. ecFileOffset += int64(interval.LargeBlockRowsCount)*largeBlockSize + int64(rowIndex)*smallBlockSize
  68. }
  69. ecFileIndex := interval.BlockIndex % DataShardsCount
  70. return ShardId(ecFileIndex), ecFileOffset
  71. }