github.com/braveheart12/just@v0.8.7/ledger/storage/jetstorage.go (about)

     1  /*
     2   *    Copyright 2019 Insolar Technologies
     3   *
     4   *    Licensed under the Apache License, Version 2.0 (the "License");
     5   *    you may not use this file except in compliance with the License.
     6   *    You may obtain a copy of the License at
     7   *
     8   *        http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   *    Unless required by applicable law or agreed to in writing, software
    11   *    distributed under the License is distributed on an "AS IS" BASIS,
    12   *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   *    See the License for the specific language governing permissions and
    14   *    limitations under the License.
    15   */
    16  
    17  package storage
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"sync"
    23  
    24  	"github.com/ugorji/go/codec"
    25  
    26  	"github.com/insolar/insolar/core"
    27  	"github.com/insolar/insolar/ledger/storage/jet"
    28  )
    29  
    30  // JetStorage provides methods for working with jets
    31  //go:generate minimock -i github.com/insolar/insolar/ledger/storage.JetStorage -o ./ -s _mock.go
    32  type JetStorage interface {
    33  	UpdateJetTree(ctx context.Context, pulse core.PulseNumber, setActual bool, ids ...core.RecordID)
    34  	FindJet(ctx context.Context, pulse core.PulseNumber, id core.RecordID) (*core.RecordID, bool)
    35  	SplitJetTree(ctx context.Context, pulse core.PulseNumber, jetID core.RecordID) (*core.RecordID, *core.RecordID, error)
    36  	CloneJetTree(ctx context.Context, from, to core.PulseNumber) *jet.Tree
    37  	DeleteJetTree(ctx context.Context, pulse core.PulseNumber)
    38  
    39  	AddJets(ctx context.Context, jetIDs ...core.RecordID) error
    40  	GetJets(ctx context.Context) (jet.IDSet, error)
    41  }
    42  
    43  type jetStorage struct {
    44  	DB DBContext `inject:""`
    45  
    46  	trees     map[core.PulseNumber]*jet.Tree
    47  	treesLock sync.RWMutex
    48  
    49  	addJetLock sync.RWMutex
    50  }
    51  
    52  func NewJetStorage() JetStorage {
    53  	return &jetStorage{
    54  		trees: map[core.PulseNumber]*jet.Tree{},
    55  	}
    56  }
    57  
    58  // FindJet finds jet for specified pulse and object.
    59  func (js *jetStorage) FindJet(ctx context.Context, pulse core.PulseNumber, id core.RecordID) (*core.RecordID, bool) {
    60  	js.treesLock.RLock()
    61  
    62  	if t, ok := js.trees[pulse]; ok {
    63  		defer js.treesLock.RUnlock()
    64  		return t.Find(id)
    65  	}
    66  	js.treesLock.RUnlock()
    67  
    68  	js.treesLock.Lock()
    69  	defer js.treesLock.Unlock()
    70  	return js.getJetTree(ctx, pulse).Find(id)
    71  }
    72  
    73  // UpdateJetTree updates jet tree for specified pulse.
    74  func (js *jetStorage) UpdateJetTree(ctx context.Context, pulse core.PulseNumber, setActual bool, ids ...core.RecordID) {
    75  	js.treesLock.Lock()
    76  	defer js.treesLock.Unlock()
    77  
    78  	tree := js.getJetTree(ctx, pulse)
    79  	for _, id := range ids {
    80  		tree.Update(id, setActual)
    81  	}
    82  }
    83  
    84  // SplitJetTree performs jet split and returns resulting jet ids.
    85  func (js *jetStorage) SplitJetTree(
    86  	ctx context.Context, pulse core.PulseNumber, jetID core.RecordID,
    87  ) (*core.RecordID, *core.RecordID, error) {
    88  	js.treesLock.Lock()
    89  	defer js.treesLock.Unlock()
    90  
    91  	tree := js.getJetTree(ctx, pulse)
    92  
    93  	left, right, err := tree.Split(jetID)
    94  	if err != nil {
    95  		return nil, nil, err
    96  	}
    97  
    98  	return left, right, nil
    99  }
   100  
   101  // CloneJetTree copies tree from one pulse to another. Use it to copy past tree into new pulse.
   102  func (js *jetStorage) CloneJetTree(
   103  	ctx context.Context, from, to core.PulseNumber,
   104  ) *jet.Tree {
   105  	js.treesLock.Lock()
   106  	defer js.treesLock.Unlock()
   107  
   108  	tree := js.getJetTree(ctx, from)
   109  
   110  	res := tree.Clone(false)
   111  	js.trees[to] = res
   112  	return res
   113  }
   114  
   115  func (js *jetStorage) DeleteJetTree(
   116  	ctx context.Context, pulse core.PulseNumber,
   117  ) {
   118  	js.treesLock.Lock()
   119  	defer js.treesLock.Unlock()
   120  
   121  	delete(js.trees, pulse)
   122  }
   123  
   124  func (js *jetStorage) getJetTree(ctx context.Context, pulse core.PulseNumber) *jet.Tree {
   125  	if t, ok := js.trees[pulse]; ok {
   126  		return t
   127  	}
   128  
   129  	tree := jet.NewTree(pulse == core.GenesisPulse.PulseNumber)
   130  	js.trees[pulse] = tree
   131  	return tree
   132  }
   133  
   134  // AddJets stores a list of jets of the current node.
   135  func (js *jetStorage) AddJets(ctx context.Context, jetIDs ...core.RecordID) error {
   136  	js.addJetLock.Lock()
   137  	defer js.addJetLock.Unlock()
   138  
   139  	k := prefixkey(scopeIDSystem, []byte{sysJetList})
   140  
   141  	var jets jet.IDSet
   142  	buff, err := js.DB.get(ctx, k)
   143  	if err == nil {
   144  		dec := codec.NewDecoder(bytes.NewReader(buff), &codec.CborHandle{})
   145  		err = dec.Decode(&jets)
   146  		if err != nil {
   147  			return err
   148  		}
   149  	} else if err == core.ErrNotFound {
   150  		jets = jet.IDSet{}
   151  	} else {
   152  		return err
   153  	}
   154  
   155  	for _, id := range jetIDs {
   156  		jets[id] = struct{}{}
   157  	}
   158  	return js.DB.set(ctx, k, jets.Bytes())
   159  }
   160  
   161  // GetJets returns jets of the current node
   162  func (js *jetStorage) GetJets(ctx context.Context) (jet.IDSet, error) {
   163  	js.addJetLock.RLock()
   164  	defer js.addJetLock.RUnlock()
   165  
   166  	k := prefixkey(scopeIDSystem, []byte{sysJetList})
   167  	buff, err := js.DB.get(ctx, k)
   168  	if err != nil {
   169  		return nil, err
   170  	}
   171  
   172  	dec := codec.NewDecoder(bytes.NewReader(buff), &codec.CborHandle{})
   173  	var jets jet.IDSet
   174  	err = dec.Decode(&jets)
   175  	if err != nil {
   176  		return nil, err
   177  	}
   178  
   179  	return jets, nil
   180  }