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 }