github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/index/mergeControl.go (about) 1 package index 2 3 import ( 4 "container/list" 5 . "github.com/balzaczyy/golucene/core/codec/spi" 6 "github.com/balzaczyy/golucene/core/util" 7 "sync" 8 ) 9 10 type MergeControl struct { 11 sync.Locker 12 infoStream util.InfoStream 13 14 readerPool *ReaderPool 15 16 // Holds all SegmentInfo instances currently involved in merges 17 mergingSegments map[*SegmentCommitInfo]bool 18 19 pendingMerges *list.List 20 runningMerges map[*OneMerge]bool 21 mergeSignal *sync.Cond 22 23 stopMerges bool 24 } 25 26 func newMergeControl(infoStream util.InfoStream, readerPool *ReaderPool) *MergeControl { 27 lock := &sync.Mutex{} 28 return &MergeControl{ 29 Locker: lock, 30 infoStream: infoStream, 31 readerPool: readerPool, 32 mergingSegments: make(map[*SegmentCommitInfo]bool), 33 pendingMerges: list.New(), 34 runningMerges: make(map[*OneMerge]bool), 35 mergeSignal: sync.NewCond(lock), 36 } 37 } 38 39 // L2272 40 /* 41 Aborts runing merges. Be careful when using this method: when you 42 abort a long-running merge, you lose a lot of work that must later be 43 redone. 44 */ 45 func (mc *MergeControl) abortAllMerges() { 46 mc.Lock() // synchronized 47 defer mc.Unlock() 48 49 mc.stopMerges = true 50 51 // Abort all pending & running merges: 52 for e := mc.pendingMerges.Front(); e != nil; e = e.Next() { 53 merge := e.Value.(*OneMerge) 54 if mc.infoStream.IsEnabled("IW") { 55 mc.infoStream.Message("IW", "now abort pending merge %v", 56 mc.readerPool.segmentsToString(merge.segments)) 57 } 58 merge.abort() 59 mc.mergeFinish(merge) 60 } 61 mc.pendingMerges.Init() 62 63 for merge, _ := range mc.runningMerges { 64 if mc.infoStream.IsEnabled("IW") { 65 mc.infoStream.Message("IW", "now abort running merge %v", 66 mc.readerPool.segmentsToString(merge.segments)) 67 } 68 merge.abort() 69 } 70 71 // These merges periodically check whether they have 72 // been aborted, and stop if so. We wait here to make 73 // sure they all stop. It should not take very long 74 // because the merge threads periodically check if 75 // they are aborted. 76 for len(mc.runningMerges) > 0 { 77 if mc.infoStream.IsEnabled("IW") { 78 mc.infoStream.Message("IW", "now wait for %v running merge(s) to abort", 79 len(mc.runningMerges)) 80 } 81 mc.mergeSignal.Wait() 82 } 83 84 mc.stopMerges = false 85 86 assert(len(mc.mergingSegments) == 0) 87 88 if mc.infoStream.IsEnabled("IW") { 89 mc.infoStream.Message("IW", "all running merges have aborted") 90 } 91 } 92 93 /* 94 Wait for any currently outstanding merges to finish. 95 96 It is guaranteed that any merges started prior to calling this method 97 will have completed once this method completes. 98 */ 99 func (mc *MergeControl) waitForMerges() { 100 mc.Lock() // synchronized 101 defer mc.Unlock() 102 // ensureOpen(false) 103 104 if mc.infoStream.IsEnabled("IW") { 105 mc.infoStream.Message("IW", "waitForMerges") 106 } 107 108 for mc.pendingMerges.Len() > 0 || len(mc.runningMerges) > 0 { 109 mc.mergeSignal.Wait() 110 } 111 112 assert(len(mc.mergingSegments) == 0) 113 114 if mc.infoStream.IsEnabled("IW") { 115 mc.infoStream.Message("IW", "waitForMerges done") 116 } 117 } 118 119 // L3696 120 /* 121 Does finishing for a merge, which is fast but holds the synchronized 122 lock on MergeControl instance. 123 124 Note: it must be externally synchronized or used internally. 125 */ 126 func (mc *MergeControl) mergeFinish(merge *OneMerge) { 127 // forceMerge, addIndexes or abortAllmerges may be waiting on 128 // merges to finish 129 // notifyAll() 130 131 // It's possible we are called twice, eg if there was an error 132 // inside mergeInit() 133 if merge.registerDone { 134 for _, info := range merge.segments { 135 delete(mc.mergingSegments, info) 136 } 137 merge.registerDone = false 138 } 139 140 delete(mc.runningMerges, merge) 141 if len(mc.runningMerges) == 0 { 142 mc.mergeSignal.Signal() 143 } 144 }