github.com/uber/kraken@v0.1.4/lib/torrent/scheduler/dispatch/torrent_access_watcher.go (about)

     1  // Copyright (c) 2016-2019 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package dispatch
    15  
    16  import (
    17  	"sync"
    18  	"time"
    19  
    20  	"github.com/uber/kraken/lib/torrent/storage"
    21  	"github.com/andres-erbsen/clock"
    22  )
    23  
    24  // torrentAccessWatcher wraps a storage.Torrent and records when it is written to
    25  // and when it is read from. Read times are measured when piece readers are closed.
    26  type torrentAccessWatcher struct {
    27  	storage.Torrent
    28  	clk       clock.Clock
    29  	mu        sync.Mutex
    30  	lastWrite time.Time
    31  	lastRead  time.Time
    32  }
    33  
    34  func newTorrentAccessWatcher(t storage.Torrent, clk clock.Clock) *torrentAccessWatcher {
    35  	return &torrentAccessWatcher{
    36  		Torrent:   t,
    37  		clk:       clk,
    38  		lastWrite: clk.Now(),
    39  		lastRead:  clk.Now(),
    40  	}
    41  }
    42  
    43  func (w *torrentAccessWatcher) WritePiece(src storage.PieceReader, piece int) error {
    44  	err := w.Torrent.WritePiece(src, piece)
    45  	if err == nil {
    46  		w.touchLastWrite()
    47  	}
    48  	return err
    49  }
    50  
    51  type pieceReaderCloseWatcher struct {
    52  	storage.PieceReader
    53  	w *torrentAccessWatcher
    54  }
    55  
    56  func (w *pieceReaderCloseWatcher) Close() error {
    57  	err := w.PieceReader.Close()
    58  	if err != nil {
    59  		w.w.touchLastRead()
    60  	}
    61  	return err
    62  }
    63  
    64  func (w *torrentAccessWatcher) GetPieceReader(piece int) (storage.PieceReader, error) {
    65  	pr, err := w.Torrent.GetPieceReader(piece)
    66  	if err == nil {
    67  		pr = &pieceReaderCloseWatcher{pr, w}
    68  	}
    69  	return pr, err
    70  }
    71  
    72  func (w *torrentAccessWatcher) touchLastWrite() {
    73  	w.mu.Lock()
    74  	defer w.mu.Unlock()
    75  	w.lastWrite = w.clk.Now()
    76  }
    77  
    78  func (w *torrentAccessWatcher) touchLastRead() {
    79  	w.mu.Lock()
    80  	defer w.mu.Unlock()
    81  	w.lastRead = w.clk.Now()
    82  }
    83  
    84  func (w *torrentAccessWatcher) getLastReadTime() time.Time {
    85  	w.mu.Lock()
    86  	defer w.mu.Unlock()
    87  	return w.lastRead
    88  }
    89  
    90  func (w *torrentAccessWatcher) getLastWriteTime() time.Time {
    91  	w.mu.Lock()
    92  	defer w.mu.Unlock()
    93  	return w.lastWrite
    94  }