github.com/braveheart12/just@v0.8.7/ledger/artifactmanager/descriptors.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 artifactmanager
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"github.com/pkg/errors"
    24  
    25  	"github.com/insolar/insolar/core"
    26  	"github.com/insolar/insolar/core/message"
    27  	"github.com/insolar/insolar/core/reply"
    28  )
    29  
    30  // CodeDescriptor represents meta info required to fetch all code data.
    31  type CodeDescriptor struct {
    32  	code        []byte
    33  	machineType core.MachineType
    34  	ref         core.RecordRef
    35  
    36  	ctx context.Context
    37  }
    38  
    39  // Ref returns reference to represented code record.
    40  func (d *CodeDescriptor) Ref() *core.RecordRef {
    41  	return &d.ref
    42  }
    43  
    44  // MachineType returns code machine type for represented code.
    45  func (d *CodeDescriptor) MachineType() core.MachineType {
    46  	return d.machineType
    47  }
    48  
    49  // Code returns code data.
    50  func (d *CodeDescriptor) Code() ([]byte, error) {
    51  	return d.code, nil
    52  }
    53  
    54  // ObjectDescriptor represents meta info required to fetch all object data.
    55  type ObjectDescriptor struct {
    56  	ctx context.Context
    57  	am  *LedgerArtifactManager
    58  
    59  	head         core.RecordRef
    60  	state        core.RecordID
    61  	prototype    *core.RecordRef
    62  	isPrototype  bool
    63  	childPointer *core.RecordID // can be nil.
    64  	memory       []byte
    65  	parent       core.RecordRef
    66  }
    67  
    68  // IsPrototype determines if the object is a prototype.
    69  func (d *ObjectDescriptor) IsPrototype() bool {
    70  	return d.isPrototype
    71  }
    72  
    73  // Code returns code reference.
    74  func (d *ObjectDescriptor) Code() (*core.RecordRef, error) {
    75  	if !d.IsPrototype() {
    76  		return nil, errors.New("object is not a prototype")
    77  	}
    78  	if d.prototype == nil {
    79  		return nil, errors.New("object has no code")
    80  	}
    81  	return d.prototype, nil
    82  }
    83  
    84  // Prototype returns prototype reference.
    85  func (d *ObjectDescriptor) Prototype() (*core.RecordRef, error) {
    86  	if d.IsPrototype() {
    87  		return nil, errors.New("object is not an instance")
    88  	}
    89  	if d.prototype == nil {
    90  		return nil, errors.New("object has no prototype")
    91  	}
    92  	return d.prototype, nil
    93  }
    94  
    95  // HeadRef returns reference to represented object record.
    96  func (d *ObjectDescriptor) HeadRef() *core.RecordRef {
    97  	return &d.head
    98  }
    99  
   100  // StateID returns reference to object state record.
   101  func (d *ObjectDescriptor) StateID() *core.RecordID {
   102  	return &d.state
   103  }
   104  
   105  // ChildPointer returns the latest child for this object.
   106  func (d *ObjectDescriptor) ChildPointer() *core.RecordID {
   107  	return d.childPointer
   108  }
   109  
   110  // Memory fetches latest memory of the object known to storage.
   111  func (d *ObjectDescriptor) Memory() []byte {
   112  	return d.memory
   113  }
   114  
   115  // Children returns object's children references.
   116  func (d *ObjectDescriptor) Children(pulse *core.PulseNumber) (core.RefIterator, error) {
   117  	return d.am.GetChildren(d.ctx, d.head, pulse)
   118  }
   119  
   120  // Parent returns object's parent.
   121  func (d *ObjectDescriptor) Parent() *core.RecordRef {
   122  	return &d.parent
   123  }
   124  
   125  // ChildIterator is used to iterate over objects children. During iteration children refs will be fetched from remote
   126  // source (parent object).
   127  //
   128  // Data can be fetched only from Active Executor (AE), although children references can be stored on other nodes.
   129  // To cope with this, we have a token system. Every time AE doesn't have data and asked for it, it will issue a token
   130  // that will allow requester to fetch data from a different node. This node will return all children references it has,
   131  // after which the requester has to go to AE again to fetch a new token. It will then be redirected to another node.
   132  // E.i. children fetching happens like this:
   133  // [R = requester, AE = active executor, LE = any light executor that has data, H = heavy executor]
   134  // 1. R (get children 0 ... ) -> AE
   135  // 2. AE (children 0 ... 3) -> R
   136  // 3. R (get children 4 ...) -> AE
   137  // 4. AE (redirect to LE) -> R
   138  // 5. R (get children 4 ...) -> LE
   139  // 6. LE (children 4 ... 5) -> R
   140  // 7. R (get children 6 ...) -> AE
   141  // 8. AE (redirect to H) -> R
   142  // 9. R (get children 6 ...) -> H
   143  // 10. H (children 6 ... 15 EOF) -> R
   144  type ChildIterator struct {
   145  	ctx         context.Context
   146  	senderChain Sender
   147  	parent      core.RecordRef
   148  	chunkSize   int
   149  	fromPulse   *core.PulseNumber
   150  	fromChild   *core.RecordID
   151  	buff        []core.RecordRef
   152  	buffIndex   int
   153  	canFetch    bool
   154  }
   155  
   156  // NewChildIterator creates new child iterator.
   157  func NewChildIterator(
   158  	ctx context.Context,
   159  	senderChain Sender,
   160  	parent core.RecordRef,
   161  	fromPulse *core.PulseNumber,
   162  	chunkSize int,
   163  ) (*ChildIterator, error) {
   164  	iter := ChildIterator{
   165  		ctx:         ctx,
   166  		senderChain: senderChain,
   167  		parent:      parent,
   168  		fromPulse:   fromPulse,
   169  		chunkSize:   chunkSize,
   170  		canFetch:    true,
   171  	}
   172  	err := iter.fetch()
   173  	if err != nil {
   174  		return nil, err
   175  	}
   176  	return &iter, nil
   177  }
   178  
   179  // HasNext checks if any elements left in iterator.
   180  func (i *ChildIterator) HasNext() bool {
   181  	return i.hasInBuffer() || i.canFetch
   182  }
   183  
   184  // Next returns next element.
   185  func (i *ChildIterator) Next() (*core.RecordRef, error) {
   186  	// Get element from buffer.
   187  	if !i.hasInBuffer() && i.canFetch {
   188  		err := i.fetch()
   189  		if err != nil {
   190  			return nil, err
   191  		}
   192  	}
   193  
   194  	ref := i.nextFromBuffer()
   195  	if ref == nil {
   196  		return nil, errors.New("failed to retrieve a child from buffer")
   197  	}
   198  
   199  	return ref, nil
   200  }
   201  
   202  func (i *ChildIterator) nextFromBuffer() *core.RecordRef {
   203  	if !i.hasInBuffer() {
   204  		return nil
   205  	}
   206  	ref := i.buff[i.buffIndex]
   207  	i.buffIndex++
   208  	return &ref
   209  }
   210  
   211  func (i *ChildIterator) fetch() error {
   212  	if !i.canFetch {
   213  		return errors.New("failed to fetch a children chunk")
   214  	}
   215  
   216  	genericReply, err := i.senderChain(i.ctx, &message.GetChildren{
   217  		Parent:    i.parent,
   218  		FromPulse: i.fromPulse,
   219  		FromChild: i.fromChild,
   220  		Amount:    i.chunkSize,
   221  	}, nil)
   222  	if err != nil {
   223  		return err
   224  	}
   225  	rep, ok := genericReply.(*reply.Children)
   226  	if !ok {
   227  		return fmt.Errorf("unexpected reply: %#v", genericReply)
   228  	}
   229  
   230  	if rep.NextFrom == nil {
   231  		i.canFetch = false
   232  	}
   233  	i.buff = rep.Refs
   234  	i.buffIndex = 0
   235  	i.fromChild = rep.NextFrom
   236  
   237  	return nil
   238  }
   239  
   240  func (i *ChildIterator) hasInBuffer() bool {
   241  	return i.buffIndex < len(i.buff)
   242  }