github.com/bcskill/bcschain/v3@v3.4.9-beta2/ethdb/table.go (about)

     1  package ethdb
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"fmt"
     7  	"os"
     8  	"path/filepath"
     9  	"sort"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/bcskill/bcschain/v3/common"
    14  	"github.com/bcskill/bcschain/v3/log"
    15  )
    16  
    17  // Table represents key/value storage for a particular data type.
    18  // Contains zero or more segments that are separated by partitioner.
    19  type Table struct {
    20  	mu          sync.RWMutex
    21  	active      string                 // active segment name
    22  	ldbSegments map[string]*LDBSegment // writable segments
    23  	segments    *SegmentSet            // all segments
    24  
    25  	Name        string
    26  	Path        string
    27  	Partitioner Partitioner
    28  
    29  	MinMutableSegmentCount int
    30  	MinCompactionAge       time.Duration
    31  
    32  	// Maximum number of segments that can be opened at once.
    33  	MaxOpenSegmentCount int
    34  
    35  	SegmentOpener    SegmentOpener
    36  	SegmentCompactor SegmentCompactor
    37  }
    38  
    39  // NewTable returns a new instance of Table.
    40  func NewTable(name, path string, partitioner Partitioner) *Table {
    41  	return &Table{
    42  		Name:        name,
    43  		Path:        path,
    44  		Partitioner: partitioner,
    45  
    46  		MinMutableSegmentCount: DefaultMinMutableSegmentCount,
    47  		MinCompactionAge:       DefaultMinCompactionAge,
    48  		MaxOpenSegmentCount:    DefaultMaxOpenSegmentCount,
    49  
    50  		SegmentOpener:    NewFileSegmentOpener(),
    51  		SegmentCompactor: NewFileSegmentCompactor(),
    52  	}
    53  }
    54  
    55  // Open initializes the table and all existing segments.
    56  func (t *Table) Open() error {
    57  	t.ldbSegments = make(map[string]*LDBSegment)
    58  	t.segments = NewSegmentSet(t.MaxOpenSegmentCount)
    59  
    60  	if err := os.MkdirAll(t.Path, 0777); err != nil {
    61  		return err
    62  	}
    63  
    64  	names, err := t.SegmentOpener.ListSegmentNames(t.Path, t.Name)
    65  	if err != nil {
    66  		log.Error("Cannot list segment names", "path", t.Path, "name", t.Name, "err", err)
    67  		return err
    68  	}
    69  
    70  	for _, name := range names {
    71  		path := filepath.Join(t.Path, name)
    72  
    73  		// Determine the segment file type.
    74  		typ, err := SegmentFileType(path)
    75  		if err == ErrInvalidSegmentType {
    76  			log.Warn("Invalid segment type, skipping", "path", path, "name", name, "err", err)
    77  			continue
    78  		} else if err != nil && !os.IsNotExist(err) {
    79  			return err
    80  		}
    81  
    82  		// Open appropriate segment type.
    83  		switch typ {
    84  		case SegmentLDB1:
    85  			ldbSegment := NewLDBSegment(name, path)
    86  			if err := ldbSegment.Open(); err != nil {
    87  				log.Error("Cannot open ldb segment", "path", path, "name", name, "err", err)
    88  				t.Close()
    89  				return err
    90  			}
    91  			t.ldbSegments[name] = ldbSegment
    92  
    93  		default:
    94  			segment, err := t.SegmentOpener.OpenSegment(t.Name, name, path)
    95  			if err == ErrSegmentTypeUnknown {
    96  				log.Info("unknown segment type, skipping", "filename", name)
    97  				continue
    98  			} else if err != nil {
    99  				log.Error("Cannot open ethdb segment", "path", path, "table", t.Name, "name", name, "err", err)
   100  				return err
   101  			}
   102  			t.segments.Add(segment)
   103  		}
   104  
   105  		// Set as active if it has the highest lexicographical name.
   106  		if name > t.active {
   107  			t.active = name
   108  		}
   109  	}
   110  	return nil
   111  }
   112  
   113  // Close closes all segments within the table.
   114  func (t *Table) Close() error {
   115  	for _, segment := range t.ldbSegments {
   116  		if err := segment.Close(); err != nil {
   117  			log.Error("Failed to close leveldb segment", "path", segment.Path(), "name", segment.Name(), "error", err)
   118  		}
   119  	}
   120  	if t.segments != nil {
   121  		t.segments.Close()
   122  	}
   123  	return nil
   124  }
   125  
   126  // ActiveSegmentName the name of the current active segment.
   127  func (t *Table) ActiveSegmentName() string {
   128  	t.mu.RLock()
   129  	defer t.mu.RUnlock()
   130  	return t.active
   131  }
   132  
   133  // ActiveSegment returns the active segment.
   134  func (t *Table) ActiveSegment() MutableSegment {
   135  	t.mu.RLock()
   136  	defer t.mu.RUnlock()
   137  	return t.ldbSegments[t.active]
   138  }
   139  
   140  // SegmentPath returns the path of the named segment.
   141  func (t *Table) SegmentPath(name string) string {
   142  	return filepath.Join(t.Path, name)
   143  }
   144  
   145  // AcquireSegment returns a segment by name. Returns nil if segment does not exist.
   146  // Must call ReleaseSegment when finished with the segment.
   147  func (t *Table) AcquireSegment(name string) (Segment, error) {
   148  	t.mu.RLock()
   149  	defer t.mu.RUnlock()
   150  
   151  	if s := t.ldbSegments[name]; s != nil {
   152  		return s, nil
   153  	}
   154  	return t.segments.Acquire(name)
   155  }
   156  
   157  // ReleaseSegment releases a given segment.
   158  func (t *Table) ReleaseSegment(s Segment) {
   159  	switch s.(type) {
   160  	case *LDBSegment:
   161  		return
   162  	default:
   163  		t.segments.Release()
   164  	}
   165  }
   166  
   167  // SegmentNames a sorted list of all segments names.
   168  func (t *Table) SegmentNames() []string {
   169  	t.mu.RLock()
   170  	defer t.mu.RUnlock()
   171  
   172  	a := make([]string, 0, len(t.ldbSegments)+t.segments.Len())
   173  	for _, s := range t.ldbSegments {
   174  		a = append(a, s.Name())
   175  	}
   176  	for _, s := range t.segments.Slice() {
   177  		a = append(a, s.Name())
   178  	}
   179  	sort.Strings(a)
   180  	return a
   181  }
   182  
   183  // SegmentsSlice returns a sorted slice of all segments.
   184  func (t *Table) SegmentSlice() []Segment {
   185  	t.mu.RLock()
   186  	defer t.mu.RUnlock()
   187  	return t.segmentSlice()
   188  }
   189  
   190  func (t *Table) segmentSlice() []Segment {
   191  	a := make([]Segment, 0, len(t.ldbSegments)+t.segments.Len())
   192  	for _, s := range t.ldbSegments {
   193  		a = append(a, s)
   194  	}
   195  	for _, s := range t.segments.Slice() {
   196  		a = append(a, s)
   197  	}
   198  	SortSegments(a)
   199  	return a
   200  }
   201  
   202  func (t *Table) ldbSegmentSlice() []*LDBSegment {
   203  	a := make([]*LDBSegment, 0, len(t.ldbSegments))
   204  	for _, s := range t.ldbSegments {
   205  		a = append(a, s)
   206  	}
   207  	sort.Slice(a, func(i, j int) bool { return a[i].Name() < a[j].Name() })
   208  	return a
   209  }
   210  
   211  // CreateSegmentIfNotExists returns a mutable segment by name.
   212  // Creates a new segment if it does not exist.
   213  func (t *Table) CreateSegmentIfNotExists(ctx context.Context, name string) (*LDBSegment, error) {
   214  	t.mu.RLock()
   215  	if s := t.ldbSegments[name]; s != nil {
   216  		t.mu.RUnlock()
   217  		return s, nil
   218  	}
   219  	t.mu.RUnlock()
   220  
   221  	t.mu.Lock()
   222  	defer t.mu.Unlock()
   223  
   224  	// Recheck under write lock.
   225  	if s := t.ldbSegments[name]; s != nil {
   226  		return s, nil
   227  	}
   228  
   229  	// Uncompact segment if it has already become compacted.
   230  	if t.segments.Contains(name) {
   231  		return t.uncompact(ctx, name)
   232  	}
   233  
   234  	// Ensure segment name can become active.
   235  	if name < t.active {
   236  		log.Error("cannot new non-active create segment", "name", name, "active", t.active)
   237  		return nil, ErrImmutableSegment
   238  	}
   239  
   240  	// Create new mutable segment.
   241  	ldbSegment := NewLDBSegment(name, t.SegmentPath(name))
   242  	if err := ldbSegment.Open(); err != nil {
   243  		return nil, err
   244  	}
   245  	t.ldbSegments[name] = ldbSegment
   246  
   247  	// Set as active segment.
   248  	t.active = name
   249  
   250  	// Compact under lock.
   251  	// TODO(benbjohnson): Run compaction in background if too slow.
   252  	if err := t.compact(ctx); err != nil {
   253  		return nil, err
   254  	}
   255  
   256  	return ldbSegment, nil
   257  }
   258  
   259  // Has returns true if key exists in the table.
   260  func (t *Table) Has(key []byte) (bool, error) {
   261  	name := t.Partitioner.Partition(key)
   262  	s, err := t.AcquireSegment(name)
   263  	if err != nil {
   264  		return false, err
   265  	} else if s == nil {
   266  		return false, common.ErrNotFound
   267  	}
   268  	defer t.ReleaseSegment(s)
   269  	return s.Has(key)
   270  }
   271  
   272  // Get returns the value associated with key.
   273  func (t *Table) Get(key []byte) ([]byte, error) {
   274  	name := t.Partitioner.Partition(key)
   275  	s, err := t.AcquireSegment(name)
   276  	if err != nil {
   277  		return nil, err
   278  	} else if s == nil {
   279  		return nil, nil
   280  	}
   281  	defer t.ReleaseSegment(s)
   282  	return s.Get(key)
   283  }
   284  
   285  // Put associates a value with key.
   286  func (t *Table) Put(key, value []byte) error {
   287  	// Ignore if value is the same.
   288  	if v, err := t.Get(key); err != nil && err != common.ErrNotFound {
   289  		return err
   290  	} else if bytes.Equal(v, value) {
   291  		return nil
   292  	}
   293  
   294  	s, err := t.CreateSegmentIfNotExists(context.TODO(), t.Partitioner.Partition(key))
   295  	if err != nil {
   296  		return err
   297  	}
   298  	return s.Put(key, value)
   299  }
   300  
   301  // Delete removes key from the database.
   302  func (t *Table) Delete(key []byte) error {
   303  	s, err := t.AcquireSegment(t.Partitioner.Partition(key))
   304  	if err != nil {
   305  		return err
   306  	} else if s == nil {
   307  		return nil
   308  	}
   309  	defer t.ReleaseSegment(s)
   310  
   311  	switch s := s.(type) {
   312  	case MutableSegment:
   313  		return s.Delete(key)
   314  	default:
   315  		return ErrImmutableSegment
   316  	}
   317  }
   318  
   319  func (t *Table) NewBatch() common.Batch {
   320  	return &tableBatch{table: t, batches: make(map[string]*ldbSegmentBatch)}
   321  }
   322  
   323  // Compact converts LDB segments into immutable file segments.
   324  func (t *Table) Compact(ctx context.Context) error {
   325  	t.mu.Lock()
   326  	defer t.mu.Unlock()
   327  	return t.compact(ctx)
   328  }
   329  
   330  func (t *Table) compact(ctx context.Context) error {
   331  	// Retrieve LDB segments. Exit if too few mutable segments.
   332  	ldbSegmentSlice := t.ldbSegmentSlice()
   333  	if len(ldbSegmentSlice) < t.MinMutableSegmentCount {
   334  		return nil
   335  	}
   336  
   337  	for _, ldbSegment := range ldbSegmentSlice[:len(ldbSegmentSlice)-t.MinMutableSegmentCount] {
   338  		startTime := time.Now()
   339  
   340  		if fi, err := os.Stat(ldbSegment.Path()); err != nil {
   341  			return err
   342  		} else if time.Since(fi.ModTime()) < t.MinCompactionAge {
   343  			log.Debug("LDB segment too young, skipping compaction", "table", t.Name, "name", ldbSegment.Name(), "elapsed", time.Since(startTime))
   344  			continue
   345  		}
   346  
   347  		newSegment, err := t.SegmentCompactor.CompactSegment(ctx, t.Name, ldbSegment)
   348  		if err != nil {
   349  			return err
   350  		}
   351  		t.segments.Add(newSegment)
   352  		delete(t.ldbSegments, ldbSegment.Name())
   353  
   354  		log.Info("Compacted segment", "table", t.Name, "name", ldbSegment.Name(), "elapsed", time.Since(startTime))
   355  	}
   356  	return nil
   357  }
   358  
   359  // uncompact converts an immutable segment to a mutable segment.
   360  func (t *Table) uncompact(ctx context.Context, name string) (*LDBSegment, error) {
   361  	startTime := time.Now()
   362  
   363  	s, err := t.segments.Acquire(name)
   364  	if err != nil {
   365  		return nil, err
   366  	}
   367  	defer t.segments.Release()
   368  
   369  	ldbSegment, err := t.SegmentCompactor.UncompactSegment(ctx, t.Name, s)
   370  	if err != nil {
   371  		return nil, err
   372  	}
   373  	t.ldbSegments[name] = ldbSegment
   374  	t.segments.Remove(ctx, name)
   375  
   376  	log.Info("Uncompacted segment", "table", t.Name, "name", name, "elapsed", time.Since(startTime))
   377  
   378  	return ldbSegment, nil
   379  }
   380  
   381  type tableBatch struct {
   382  	table   *Table
   383  	batches map[string]*ldbSegmentBatch
   384  	size    int
   385  }
   386  
   387  func (b *tableBatch) Put(key, value []byte) error {
   388  	// Ignore if value is the same.
   389  	if v, err := b.table.Get(key); err != nil && err != common.ErrNotFound {
   390  		return err
   391  	} else if bytes.Equal(v, value) {
   392  		return nil
   393  	}
   394  
   395  	name := b.table.Partitioner.Partition(key)
   396  	ldbSegment, err := b.table.CreateSegmentIfNotExists(context.TODO(), name)
   397  	if err != nil {
   398  		log.Error("tableBatch.Put: error", "table", b.table.Name, "segment", name, "key", fmt.Sprintf("%x", key))
   399  		return err
   400  	}
   401  
   402  	sb := b.batches[name]
   403  	if sb == nil {
   404  		sb = ldbSegment.newBatch()
   405  		b.batches[name] = sb
   406  	}
   407  	if err := sb.Put(key, value); err != nil {
   408  		return err
   409  	}
   410  	b.size += len(value)
   411  	return nil
   412  }
   413  
   414  func (b *tableBatch) Delete(key []byte) error {
   415  	// Ignore if value doesn't exist.
   416  	if _, err := b.table.Get(key); err == common.ErrNotFound {
   417  		return nil
   418  	} else if err != nil {
   419  		return err
   420  	}
   421  
   422  	name := b.table.Partitioner.Partition(key)
   423  	ldbSegment, err := b.table.CreateSegmentIfNotExists(context.TODO(), name)
   424  	if err != nil {
   425  		log.Error("tableBatch.Delete: error", "table", b.table.Name, "segment", name, "key", fmt.Sprintf("%x", key))
   426  		return err
   427  	}
   428  
   429  	sb := b.batches[name]
   430  	if sb == nil {
   431  		sb = ldbSegment.newBatch()
   432  		b.batches[name] = sb
   433  	}
   434  	if err := sb.Delete(key); err != nil {
   435  		return err
   436  	}
   437  	return nil
   438  }
   439  
   440  func (b *tableBatch) Write() error {
   441  	for _, sb := range b.batches {
   442  		if err := sb.Write(); err != nil {
   443  			return err
   444  		}
   445  	}
   446  	return nil
   447  }
   448  
   449  func (b *tableBatch) ValueSize() int {
   450  	return b.size
   451  }
   452  
   453  func (b *tableBatch) Reset() {
   454  	for _, sb := range b.batches {
   455  		sb.Reset()
   456  	}
   457  	b.size = 0
   458  }