github.com/matrixorigin/matrixone@v1.2.0/pkg/fileservice/io_merger.go (about) 1 // Copyright 2023 Matrix Origin 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 15 package fileservice 16 17 import ( 18 "sync" 19 "time" 20 21 "github.com/matrixorigin/matrixone/pkg/logutil" 22 metric "github.com/matrixorigin/matrixone/pkg/util/metric/v2" 23 "go.uber.org/zap" 24 ) 25 26 type IOMergeKey struct { 27 Path string 28 Offset int64 29 End int64 30 Policy Policy 31 } 32 33 type IOMerger struct { 34 flying sync.Map // IOMergeKey -> chan struct{} 35 } 36 37 func NewIOMerger() *IOMerger { 38 return &IOMerger{} 39 } 40 41 var slowIOWaitDuration = time.Second * 10 42 43 func (i *IOMerger) waitFunc(key IOMergeKey, ch chan struct{}) func() { 44 metric.IOMergerCounterWait.Add(1) 45 return func() { 46 t0 := time.Now() 47 defer func() { 48 metric.IOMergerDurationWait.Observe(time.Since(t0).Seconds()) 49 }() 50 for { 51 timer := time.NewTimer(slowIOWaitDuration) 52 select { 53 case <-ch: 54 timer.Stop() 55 return 56 case <-timer.C: 57 logutil.Warn("wait io for too long", 58 zap.Any("wait", time.Since(t0)), 59 zap.Any("key", key), 60 ) 61 } 62 } 63 } 64 } 65 66 func (i *IOMerger) Merge(key IOMergeKey) (done func(), wait func()) { 67 if v, ok := i.flying.Load(key); ok { 68 // wait 69 return nil, i.waitFunc(key, v.(chan struct{})) 70 } 71 72 // try initiate 73 ch := make(chan struct{}) 74 v, loaded := i.flying.LoadOrStore(key, ch) 75 if loaded { 76 // not the first request, wait 77 return nil, i.waitFunc(key, v.(chan struct{})) 78 } 79 80 // initiated 81 metric.IOMergerCounterInitiate.Add(1) 82 t0 := time.Now() 83 return func() { 84 defer func() { 85 metric.IOMergerDurationInitiate.Observe(time.Since(t0).Seconds()) 86 }() 87 i.flying.Delete(key) 88 close(ch) 89 }, nil 90 } 91 92 func (i *IOVector) ioMergeKey() IOMergeKey { 93 key := IOMergeKey{ 94 Path: i.FilePath, 95 Policy: i.Policy, 96 } 97 min, max, readFull := i.readRange() 98 if readFull { 99 return key 100 } 101 if min != nil { 102 key.Offset = *min 103 } 104 if max != nil { 105 key.End = *max 106 } 107 return key 108 }