github.com/balzaczyy/golucene@v0.0.0-20151210033525-d0be9ee89713/core/index/directoryReader.go (about) 1 package index 2 3 import ( 4 "bytes" 5 "fmt" 6 "github.com/balzaczyy/golucene/core/store" 7 "github.com/balzaczyy/golucene/core/util" 8 // "io" 9 "errors" 10 "strings" 11 ) 12 13 const DEFAULT_TERMS_INDEX_DIVISOR = 1 14 15 type DirectoryReader interface { 16 IndexReader 17 // doOpenIfChanged() error 18 // doOpenIfChanged(c IndexCommit) error 19 // doOpenIfChanged(w IndexWriter, c IndexCommit) error 20 Version() int64 21 IsCurrent() bool 22 } 23 24 type DirectoryReaderImpl struct { 25 *BaseCompositeReader 26 directory store.Directory 27 } 28 29 func newDirectoryReader(spi BaseCompositeReaderSPI, directory store.Directory, segmentReaders []AtomicReader) *DirectoryReaderImpl { 30 // log.Printf("Initializing DirectoryReader with %v segment readers...", len(segmentReaders)) 31 readers := make([]IndexReader, len(segmentReaders)) 32 for i, v := range segmentReaders { 33 readers[i] = v 34 } 35 return &DirectoryReaderImpl{ 36 BaseCompositeReader: newBaseCompositeReader(spi, readers), 37 directory: directory, 38 } 39 } 40 41 func OpenDirectoryReader(directory store.Directory) (r DirectoryReader, err error) { 42 return openStandardDirectoryReader(directory, nil, DEFAULT_TERMS_INDEX_DIVISOR) 43 } 44 45 /* 46 Returns true if an index likely exists at the specified directory. Note that 47 if a corrupt index exists, or if an index in the process of committing 48 */ 49 func IsIndexExists(directory store.Directory) (ok bool, err error) { 50 // LUCENE-2812, LUCENE-2727, LUCENE-4738: this logic will 51 // return true in cases that should arguably be false, 52 // such as only IW.prepareCommit has been called, or a 53 // corrupt first commit, but it's too deadly to make 54 // this logic "smarter" and risk accidentally returning 55 // false due to various cases like file description 56 // exhaustion, access denied, etc., because in that 57 // case IndexWriter may delete the entire index. It's 58 // safer to err towards "index exists" than try to be 59 // smart about detecting not-yet-fully-committed or 60 // corrupt indices. This means that IndexWriter will 61 // throw an exception on such indices and the app must 62 // resolve the situation manually: 63 var files []string 64 files, err = directory.ListAll() 65 if _, ok := err.(*store.NoSuchDirectoryError); ok { 66 // Directory does not exist --> no index exists 67 return false, nil 68 } else if err != nil { 69 return false, err 70 } 71 return IsIndexFileExists(files), nil 72 } 73 74 /* No lock is required */ 75 func IsIndexFileExists(files []string) bool { 76 // Defensive: maybe a Directory impl returns null 77 // instead of throwing NoSuchDirectoryException: 78 if files != nil { 79 prefix := INDEX_FILENAME_SEGMENTS + "_" 80 for _, file := range files { 81 if strings.HasPrefix(file, prefix) || file == INDEX_FILENAME_SEGMENTS_GEN { 82 return true 83 } 84 } 85 } 86 return false 87 } 88 89 type StandardDirectoryReader struct { 90 *DirectoryReaderImpl 91 writer *IndexWriter // NRT 92 segmentInfos *SegmentInfos 93 } 94 95 // TODO support IndexWriter 96 func newStandardDirectoryReader(directory store.Directory, readers []AtomicReader, 97 sis *SegmentInfos, termInfosIndexDivisor int, applyAllDeletes bool) *StandardDirectoryReader { 98 // log.Printf("Initializing StandardDirectoryReader with %v sub readers...", len(readers)) 99 ans := &StandardDirectoryReader{segmentInfos: sis} 100 ans.DirectoryReaderImpl = newDirectoryReader(ans, directory, readers) 101 return ans 102 } 103 104 func openStandardDirectoryReader(directory store.Directory, 105 commit IndexCommit, termInfosIndexDivisor int) (r DirectoryReader, err error) { 106 // log.Print("Initializing SegmentsFile...") 107 obj, err := NewFindSegmentsFile(directory, func(segmentFileName string) (interface{}, error) { 108 sis := &SegmentInfos{} 109 err := sis.Read(directory, segmentFileName) 110 if err != nil { 111 return nil, err 112 } 113 // log.Printf("Found %v segments...", len(sis.Segments)) 114 readers := make([]AtomicReader, len(sis.Segments)) 115 for i := len(sis.Segments) - 1; i >= 0; i-- { 116 sr, err := NewSegmentReader(sis.Segments[i], termInfosIndexDivisor, store.IO_CONTEXT_READ) 117 if err != nil { 118 for _, r := range readers { 119 if r != nil { 120 util.CloseWhileSuppressingError(r) 121 } 122 } 123 return nil, err 124 } 125 readers[i] = sr 126 } 127 // log.Printf("Obtained %v SegmentReaders.", len(readers)) 128 return newStandardDirectoryReader(directory, readers, sis, termInfosIndexDivisor, false), nil 129 }).run(commit) 130 if err != nil { 131 return nil, err 132 } 133 return obj.(*StandardDirectoryReader), err 134 } 135 136 func (r *StandardDirectoryReader) String() string { 137 var buf bytes.Buffer 138 buf.WriteString("StandardDirectoryReader(") 139 segmentsFile := r.segmentInfos.SegmentsFileName() 140 if segmentsFile != "" { 141 fmt.Fprintf(&buf, "%v:%v", segmentsFile, r.segmentInfos.version) 142 } 143 // if r.writer != nil { 144 // fmt.Fprintf(w, "%v", r.writer) 145 // } 146 for _, v := range r.getSequentialSubReaders() { 147 fmt.Fprintf(&buf, " %v", v) 148 } 149 buf.WriteString(")") 150 return buf.String() 151 } 152 153 func (r *StandardDirectoryReader) Version() int64 { 154 r.ensureOpen() 155 return r.segmentInfos.version 156 } 157 158 func (r *StandardDirectoryReader) IsCurrent() bool { 159 r.ensureOpen() 160 // if writer == nill || writer.IsClosed() { 161 // Fully read the segments file: this ensures that it's 162 // completely written so that if 163 // IndexWriter.prepareCommit has been called (but not 164 // yet commit), then the reader will still see itself as 165 // current: 166 sis := SegmentInfos{} 167 sis.ReadAll(r.directory) 168 169 // we loaded SegmentInfos from the directory 170 return sis.version == r.segmentInfos.version 171 // } else { 172 // return writer.nrtIsCurrent(r.segmentInfos) 173 // } 174 } 175 176 func (r *StandardDirectoryReader) doClose() error { 177 var firstErr error 178 for _, r := range r.getSequentialSubReaders() { 179 // try to close each reader, even if an error is returned 180 func() { 181 defer func() { 182 if err := recover(); err != nil && firstErr == nil { 183 if s, ok := err.(string); ok { 184 firstErr = errors.New(s) 185 } else { 186 firstErr = errors.New(fmt.Sprintf("%v", err)) 187 } 188 } 189 }() 190 r.decRef() 191 }() 192 } 193 194 if w := r.writer; w != nil { 195 panic("not implemented yet") 196 // Since we just closed, writer may now be able to delete unused files: 197 w.deletePendingFiles() 198 } 199 200 return firstErr 201 }