github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/utils/dbutil/autocompact/compacter.go (about)

     1  package autocompact
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  
     7  	"github.com/unicornultrafoundation/go-u2u/common"
     8  )
     9  
    10  type ContainerI interface {
    11  	Add(key []byte, size uint64)
    12  	Merge(c ContainerI)
    13  	Error() error
    14  	Reset()
    15  	Size() uint64
    16  	Ranges() []Range
    17  }
    18  
    19  type Range struct {
    20  	minKey []byte
    21  	maxKey []byte
    22  }
    23  
    24  // MonotonicContainer implements tracking of compaction ranges in cases when keys are inserted as series of monotonic ranges
    25  type MonotonicContainer struct {
    26  	forward bool
    27  	ranges  []Range
    28  	size    uint64
    29  	err     error
    30  }
    31  
    32  type DevnullContainer struct{}
    33  
    34  func (d DevnullContainer) Add(key []byte, size uint64) {}
    35  
    36  func (d DevnullContainer) Merge(c ContainerI) {}
    37  
    38  func (d DevnullContainer) Error() error {
    39  	return nil
    40  }
    41  
    42  func (d DevnullContainer) Reset() {
    43  
    44  }
    45  
    46  func (d DevnullContainer) Size() uint64 {
    47  	return 0
    48  }
    49  
    50  func (d DevnullContainer) Ranges() []Range {
    51  	return []Range{}
    52  }
    53  
    54  func NewForwardCont() ContainerI {
    55  	return &MonotonicContainer{
    56  		forward: true,
    57  	}
    58  }
    59  
    60  func NewBackwardsCont() ContainerI {
    61  	return &MonotonicContainer{
    62  		forward: false,
    63  	}
    64  }
    65  
    66  func NewDevnullCont() ContainerI {
    67  	return DevnullContainer{}
    68  }
    69  
    70  func (m *MonotonicContainer) addRange(key []byte) {
    71  	m.ranges = append(m.ranges, Range{
    72  		minKey: common.CopyBytes(key),
    73  		maxKey: common.CopyBytes(key),
    74  	})
    75  }
    76  
    77  func (m *MonotonicContainer) Add(key []byte, size uint64) {
    78  	m.size += size
    79  	if len(m.ranges) == 0 {
    80  		m.addRange(key)
    81  	}
    82  	// extend the last range if it's a monotonic addition or start new range otherwise
    83  	l := len(m.ranges) - 1
    84  	if m.forward {
    85  		if bytes.Compare(key, m.ranges[l].maxKey) >= 0 {
    86  			m.ranges[l].maxKey = common.CopyBytes(key)
    87  		} else {
    88  			m.addRange(key)
    89  		}
    90  	} else {
    91  		if bytes.Compare(key, m.ranges[l].minKey) <= 0 {
    92  			m.ranges[l].minKey = common.CopyBytes(key)
    93  		} else {
    94  			m.addRange(key)
    95  		}
    96  	}
    97  }
    98  
    99  func (m *MonotonicContainer) Merge(c ContainerI) {
   100  	if err := c.Error(); err != nil {
   101  		m.err = err
   102  	}
   103  
   104  	for _, r := range c.Ranges() {
   105  		if m.forward {
   106  			m.Add(r.minKey, 0)
   107  			m.Add(r.maxKey, 0)
   108  		} else {
   109  			m.Add(r.maxKey, 0)
   110  			m.Add(r.minKey, 0)
   111  		}
   112  	}
   113  	m.size += c.Size()
   114  }
   115  
   116  func (m *MonotonicContainer) Error() error {
   117  	if m.err != nil {
   118  		return m.err
   119  	}
   120  	if len(m.ranges) > 2 {
   121  		return errors.New("too many compaction ranges, it's likely that dataset isn't monotonic enough")
   122  	}
   123  	return nil
   124  }
   125  
   126  func (m *MonotonicContainer) Reset() {
   127  	m.ranges = nil
   128  	m.size = 0
   129  }
   130  
   131  func (m *MonotonicContainer) Size() uint64 {
   132  	return m.size
   133  }
   134  
   135  func (m *MonotonicContainer) Ranges() []Range {
   136  	return m.ranges
   137  }