github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/index/readersAndLiveDocs.go (about) 1 package index 2 3 import ( 4 . "github.com/balzaczyy/golucene/core/codec/spi" 5 "github.com/balzaczyy/golucene/core/store" 6 "github.com/balzaczyy/golucene/core/util" 7 "log" 8 "sync" 9 "sync/atomic" 10 ) 11 12 // index/ReadersAndUpdates.java 13 14 type refCountMixin struct { 15 // Tracks how many consumers are using this instance: 16 _refCount int32 // atomic, 1 17 } 18 19 func newRefCountMixin() *refCountMixin { 20 return &refCountMixin{1} 21 } 22 23 func (rc *refCountMixin) incRef() { 24 assert(atomic.AddInt32(&rc._refCount, 1) > 1) 25 } 26 27 func (rc *refCountMixin) decRef() { 28 assert(atomic.AddInt32(&rc._refCount, -1) >= 0) 29 } 30 31 func (rc *refCountMixin) refCount() int { 32 n := atomic.LoadInt32(&rc._refCount) 33 assert(n >= 0) 34 return int(n) 35 } 36 37 /* 38 Used by IndexWriter to hold open SegmentReaders (for searching or 39 merging), plus pending deletes and updates, for a given segment. 40 */ 41 type ReadersAndUpdates struct { 42 sync.Locker 43 *refCountMixin 44 45 info *SegmentCommitInfo 46 47 writer *IndexWriter 48 49 // Set once (nil, and then maybe set, and never set again) 50 _reader *SegmentReader 51 52 // TODO: it's sometimes wasteful that we hold open two separate SRs 53 // (one for merging one for reading)... maybe just use a single SR? 54 // The gains of not loading the terms index (for merging in the 55 // non-NRT case) are far less now... and if the app has any deletes 56 // it'll open real readers anyway. 57 // Set once (nil, and then maybe set, and never set again) 58 mergeReader *SegmentReader 59 60 // Holds the current shared (readable and writeable) liveDocs. This 61 // is nil when there are no deleted docs, and it's copy-on-write 62 // (cloned whenever we need to change it but it's been shared to an 63 // external NRT reader). 64 _liveDocs util.Bits 65 66 // How many further deletions we;ve doen against 67 // liveDocs vs when we loaded it or last wrote it: 68 _pendingDeleteCount int 69 70 // True if the current liveDOcs is reference dby an external NRT reader: 71 liveDocsShared bool 72 } 73 74 func newReadersAndUpdates(writer *IndexWriter, info *SegmentCommitInfo) *ReadersAndUpdates { 75 return &ReadersAndUpdates{info: info, writer: writer, liveDocsShared: true} 76 } 77 78 func (rld *ReadersAndUpdates) pendingDeleteCount() int { 79 rld.Lock() 80 defer rld.Unlock() 81 return rld._pendingDeleteCount 82 } 83 84 /* 85 Get reader for searching/deleting 86 */ 87 func (rld *ReadersAndUpdates) reader(ctx store.IOContext) (*SegmentReader, error) { 88 panic("not implemented yet") 89 } 90 91 func (rld *ReadersAndUpdates) release(sr *SegmentReader) error { 92 panic("not implemented yet") 93 } 94 95 // NOTE: removes callers ref 96 func (rld *ReadersAndUpdates) dropReaders() error { 97 rld.Lock() 98 defer rld.Unlock() 99 100 // TODO: can we somehow use IOUtils here...? 101 // problem is we are calling .decRef not .close)... 102 err := func() (err error) { 103 defer func() { 104 if rld.mergeReader != nil { 105 log.Printf(" pool.drop info=%v merge rc=%v", rld.info, rld.mergeReader.refCount) 106 defer func() { rld.mergeReader = nil }() 107 err2 := rld.mergeReader.decRef() 108 if err == nil { 109 err = err2 110 } else { 111 log.Printf("Escaped error: %v", err2) 112 } 113 } 114 }() 115 116 if rld._reader != nil { 117 log.Printf(" pool.drop info=%v merge rc=%v", rld.info, rld._reader.refCount) 118 defer func() { rld._reader = nil }() 119 return rld._reader.decRef() 120 } 121 return nil 122 }() 123 if err != nil { 124 return err 125 } 126 rld.decRef() 127 return nil 128 } 129 130 func (rld *ReadersAndUpdates) liveDocs() util.Bits { 131 rld.Lock() 132 defer rld.Unlock() 133 return rld._liveDocs 134 } 135 136 /* 137 Commit live docs (writes new _X_N.del files) and field update (writes 138 new _X_N.del files) to the directory; returns true if it wrote any 139 file and false if there were no new deletes or updates to write: 140 */ 141 func (rld *ReadersAndUpdates) writeLiveDocs(dir store.Directory) (bool, error) { 142 panic("not implemented yet") 143 rld.Lock() 144 defer rld.Unlock() 145 146 log.Printf("rld.writeLiveDocs seg=%v pendingDelCount=%v", rld.info, rld._pendingDeleteCount) 147 if rld._pendingDeleteCount != 0 { 148 // We have new deletes 149 assert(rld._liveDocs.Length() == rld.info.Info.DocCount()) 150 151 // Do this so we can delete any created files on error; this 152 // saves all codecs from having to do it: 153 trackingDir := store.NewTrackingDirectoryWrapper(dir) 154 155 // We can write directly to the actual name (vs to a .tmp & 156 // renaming it) becaues the file is not live until segments file 157 // is written: 158 var success = false 159 defer func() { 160 if !success { 161 // Advance only the nextWriteDelGen so that a 2nd attempt to 162 // write will write to a new file 163 rld.info.AdvanceNextWriteDelGen() 164 165 // Delete any partially created files(s): 166 trackingDir.EachCreatedFiles(func(filename string) { 167 dir.DeleteFile(filename) // ignore error 168 }) 169 } 170 }() 171 172 err := rld.info.Info.Codec().(Codec).LiveDocsFormat().WriteLiveDocs(rld._liveDocs.(util.MutableBits), 173 trackingDir, rld.info, rld._pendingDeleteCount, store.IO_CONTEXT_DEFAULT) 174 if err != nil { 175 return false, err 176 } 177 success = true 178 179 // If we hit an error in the line above (e.g. disk full) then 180 // info's delGen remains pointing to the previous (successfully 181 // written) del docs: 182 rld.info.AdvanceDelGen() 183 rld.info.SetDelCount(rld.info.DelCount() + rld._pendingDeleteCount) 184 assert(rld.info.DelCount() <= rld.info.Info.DocCount()) 185 186 rld._pendingDeleteCount = 0 187 return true, nil 188 } 189 return false, nil 190 } 191 192 /* Writes field updates (new _X_N updates files) to the directory */ 193 func (r *ReadersAndUpdates) writeFieldUpdates(dir store.Directory, 194 dvUpdates *DocValuesFieldUpdatesContainer) error { 195 panic("not implemented yet") 196 } 197 198 func (rld *ReadersAndUpdates) String() string { 199 panic("not implemented yet") 200 }