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  }