/* Constructs a new IndexWriter per the settings given in conf. If you want to make "live" changes to this writer instance, use Config(). NOTE: after this writer is created, the given configuration instance cannot be passed to another writer. If you intend to do so, you should clone it beforehand. */ func NewIndexWriter(d store.Directory, conf *IndexWriterConfig) (w *IndexWriter, err error) { ans := &IndexWriter{ Locker: &sync.Mutex{}, ClosingControl: newClosingControl(), segmentsToMerge: make(map[*SegmentInfoPerCommit]bool), mergeExceptions: make([]*OneMerge, 0), doAfterFlush: func() error { return nil }, doBeforeFlush: func() error { return nil }, commitLock: &sync.Mutex{}, fullFlushLock: &sync.Mutex{}, config: newLiveIndexWriterConfigFrom(conf), directory: d, analyzer: conf.analyzer, infoStream: conf.infoStream, mergePolicy: conf.mergePolicy, mergeScheduler: conf.mergeScheduler, codec: conf.codec, bufferedDeletesStream: newBufferedDeletesStream(conf.infoStream), poolReaders: conf.readerPooling, writeLock: d.MakeLock(WRITE_LOCK_NAME), } ans.readerPool = newReaderPool(ans) ans.MergeControl = newMergeControl(conf.infoStream, ans.readerPool) conf.setIndexWriter(ans) ans.mergePolicy.SetIndexWriter(ans) // obtain write lock if ok, err := ans.writeLock.ObtainWithin(conf.writeLockTimeout); !ok || err != nil { if err != nil { return nil, err } return nil, errors.New(fmt.Sprintf("Index locked for write: %v", ans.writeLock)) } var success bool = false defer func() { if !success { if ans.infoStream.IsEnabled("IW") { ans.infoStream.Message("IW", "init: hit exception on init; releasing write lock") } ans.writeLock.Release() // don't mask the original exception ans.writeLock = nil } }() var create bool switch conf.openMode { case OPEN_MODE_CREATE: create = true case OPEN_MODE_APPEND: create = false default: // CREATE_OR_APPEND - create only if an index does not exist ok, err := IsIndexExists(d) if err != nil { return nil, err } create = !ok } // If index is too old, reading the segments will return // IndexFormatTooOldError ans.segmentInfos = &SegmentInfos{} var initialIndexExists bool = true if create { // Try to read first. This is to allow create against an index // that's currently open for searching. In this case we write the // next segments_N file with no segments: err = ans.segmentInfos.ReadAll(d) if err == nil { ans.segmentInfos.Clear() } else { // Likely this means it's a fresh directory initialIndexExists = false err = nil } // Record that we have a change (zero out all segments) pending: ans.changed() } else { err = ans.segmentInfos.ReadAll(d) if err != nil { return } if commit := conf.commit; commit != nil { // Swap out all segments, but, keep metadta in SegmentInfos, // like version & generation, to preserve write-once. This is // important if readers are open against the future commit // points. assert2(commit.Directory() == d, "IndexCommit's directory doesn't match my directory") oldInfos := &SegmentInfos{} ans.segmentInfos.replace(oldInfos) ans.changed() ans.infoStream.Message("IW", "init: loaded commit '%v'", commit.SegmentsFileName()) } } ans.rollbackSegments = ans.segmentInfos.createBackupSegmentInfos() // start with previous field numbers, but new FieldInfos ans.globalFieldNumberMap, err = ans.fieldNumberMap() if err != nil { return } ans.config.flushPolicy.init(ans.config) ans.docWriter = newDocumentsWriter(ans, ans.config, d) ans.eventQueue = ans.docWriter.events // Default deleter (for backwards compatibility) is // KeepOnlyLastCommitDeleter: ans.deleter, err = newIndexFileDeleter(d, conf.delPolicy, ans.segmentInfos, ans.infoStream, ans, initialIndexExists) if err != nil { return } if ans.deleter.startingCommitDeleted { // Deletion policy deleted the "head" commit point. We have to // mark outsef as changed so that if we are closed w/o any // further changes we write a new segments_N file. ans.changed() } if ans.infoStream.IsEnabled("IW") { ans.infoStream.Message("IW", "init: create=%v", create) ans.messageState() } success = true return ans, nil }