github.com/braveheart12/just@v0.8.7/ledger/artifactmanager/hotdatawaiter.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/instrumentation/inslogger"
    25  )
    26  
    27  // HotDataWaiter provides waiting system for a specific jet
    28  // We tend to think, that it will be used for waiting hot-data in handler
    29  // Also, because of the some jet pitfalls, we need to have an instrument
    30  // to handler edge-cases from pulse manager.
    31  // The main case is when a light material executes a jet for more then 1 pulse
    32  // If it happens, we need to stop waiters from raising and waiting
    33  //go:generate minimock -i github.com/insolar/insolar/ledger/storage.HotDataWaiter -o ./ -s _mock.go
    34  type HotDataWaiter interface {
    35  	Wait(ctx context.Context, jetID core.RecordID) error
    36  	Unlock(ctx context.Context, jetID core.RecordID) error
    37  	ThrowTimeout(ctx context.Context)
    38  }
    39  
    40  // HotDataWaiterConcrete is an implementation of HotDataWaiter
    41  type HotDataWaiterConcrete struct {
    42  	lock    sync.Mutex
    43  	waiters map[core.RecordID]waiter
    44  	timeout chan struct{}
    45  }
    46  
    47  type waiter chan struct{}
    48  
    49  func (w waiter) isClosed() bool {
    50  	select {
    51  	case <-w:
    52  		return true
    53  	default:
    54  	}
    55  	return false
    56  }
    57  
    58  // NewHotDataWaiterConcrete is a constructor
    59  func NewHotDataWaiterConcrete() *HotDataWaiterConcrete {
    60  	return &HotDataWaiterConcrete{
    61  		waiters: map[core.RecordID]waiter{},
    62  		timeout: make(chan struct{}),
    63  	}
    64  }
    65  
    66  func (w *HotDataWaiterConcrete) waiterForJet(jetID core.RecordID) waiter {
    67  	if _, ok := w.waiters[jetID]; !ok {
    68  		w.waiters[jetID] = make(waiter)
    69  	}
    70  	return w.waiters[jetID]
    71  }
    72  
    73  // Wait waits for the raising one of two channels.
    74  // If hotDataChannel or timeoutChannel was raised, the method returns error
    75  // Either nil or ErrHotDataTimeout
    76  func (w *HotDataWaiterConcrete) Wait(ctx context.Context, jetID core.RecordID) error {
    77  	w.lock.Lock()
    78  	waiter := w.waiterForJet(jetID)
    79  	timeout := w.timeout
    80  	w.lock.Unlock()
    81  
    82  	select {
    83  	case <-waiter:
    84  		return nil
    85  	case <-timeout:
    86  		return core.ErrHotDataTimeout
    87  	}
    88  }
    89  
    90  // Unlock raises hotDataChannel
    91  func (w *HotDataWaiterConcrete) Unlock(ctx context.Context, jetID core.RecordID) error {
    92  	w.lock.Lock()
    93  	defer w.lock.Unlock()
    94  
    95  	waiter := w.waiterForJet(jetID)
    96  	if waiter.isClosed() {
    97  		return ErrWaiterNotLocked
    98  	}
    99  	close(waiter)
   100  	return nil
   101  }
   102  
   103  // ThrowTimeout raises all timeoutChannel
   104  func (w *HotDataWaiterConcrete) ThrowTimeout(ctx context.Context) {
   105  	w.lock.Lock()
   106  	defer w.lock.Unlock()
   107  
   108  	inslogger.FromContext(ctx).Debug("raising timeout for requests")
   109  	close(w.timeout)
   110  	w.timeout = make(chan struct{})
   111  	w.waiters = map[core.RecordID]waiter{}
   112  }