github.com/braveheart12/just@v0.8.7/ledger/artifactmanager/artifactmanager_senders.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 "sync" 22 23 "github.com/insolar/insolar/core" 24 "github.com/insolar/insolar/core/message" 25 "github.com/insolar/insolar/core/reply" 26 "github.com/insolar/insolar/instrumentation/inslogger" 27 "github.com/insolar/insolar/ledger/storage" 28 "github.com/pkg/errors" 29 "go.opencensus.io/stats" 30 ) 31 32 // ledgerArtifactSenders is a some kind of a middleware layer 33 // it contains cache meta-data for calls 34 type ledgerArtifactSenders struct { 35 cacheLock sync.Mutex 36 caches map[string]*cacheEntry 37 } 38 39 type cacheEntry struct { 40 sync.Mutex 41 reply core.Reply 42 } 43 44 func newLedgerArtifactSenders() *ledgerArtifactSenders { 45 return &ledgerArtifactSenders{ 46 caches: map[string]*cacheEntry{}, 47 } 48 } 49 50 // cachedSender is using for caching replies 51 func (m *ledgerArtifactSenders) cachedSender(scheme core.PlatformCryptographyScheme) PreSender { 52 return func(sender Sender) Sender { 53 return func(ctx context.Context, msg core.Message, options *core.MessageSendOptions) (core.Reply, error) { 54 55 msgHash := string(scheme.IntegrityHasher().Hash(message.ToBytes(msg))) 56 57 m.cacheLock.Lock() 58 entry, ok := m.caches[msgHash] 59 if !ok { 60 entry = &cacheEntry{} 61 m.caches[msgHash] = entry 62 } 63 m.cacheLock.Unlock() 64 65 entry.Lock() 66 defer entry.Unlock() 67 68 if entry.reply != nil { 69 return entry.reply, nil 70 } 71 72 response, err := sender(ctx, msg, options) 73 if err != nil { 74 return nil, err 75 } 76 77 entry.reply = response 78 return response, err 79 } 80 } 81 } 82 83 // followRedirectSender is using for redirecting responses with delegation token 84 func followRedirectSender(bus core.MessageBus) PreSender { 85 return func(sender Sender) Sender { 86 return func(ctx context.Context, msg core.Message, options *core.MessageSendOptions) (core.Reply, error) { 87 rep, err := sender(ctx, msg, options) 88 if err != nil { 89 return nil, err 90 } 91 92 if r, ok := rep.(core.RedirectReply); ok { 93 stats.Record(ctx, statRedirects.M(1)) 94 95 redirected := r.Redirected(msg) 96 inslogger.FromContext(ctx).Debugf("redirect reciever=%v", r.GetReceiver()) 97 98 rep, err = bus.Send(ctx, redirected, &core.MessageSendOptions{ 99 Token: r.GetToken(), 100 Receiver: r.GetReceiver(), 101 }) 102 if err != nil { 103 return nil, err 104 } 105 if _, ok := rep.(core.RedirectReply); ok { 106 return nil, errors.New("double redirects are forbidden") 107 } 108 return rep, nil 109 } 110 111 return rep, err 112 } 113 } 114 } 115 116 // retryJetSender is using for refreshing jet-tree, if destination has no idea about a jet from message 117 func retryJetSender(jetStorage storage.JetStorage) PreSender { 118 return func(sender Sender) Sender { 119 return func(ctx context.Context, msg core.Message, options *core.MessageSendOptions) (core.Reply, error) { 120 retries := jetMissRetryCount 121 for retries > 0 { 122 rep, err := sender(ctx, msg, options) 123 if err != nil { 124 return nil, err 125 } 126 127 if r, ok := rep.(*reply.JetMiss); ok { 128 129 jetStorage.UpdateJetTree(ctx, r.Pulse, true, r.JetID) 130 } else { 131 return rep, err 132 } 133 134 retries-- 135 } 136 137 return nil, errors.New("failed to find jet (retry limit exceeded on client)") 138 } 139 } 140 }