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 }