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  }