apache / lucene

Apache Lucene open-source search software
https://lucene.apache.org/
Apache License 2.0
2.71k stars 1.04k forks source link

IndexReader.reopen() [LUCENE-743] #1818

Closed asfimport closed 17 years ago

asfimport commented 17 years ago

This is Robert Engels' implementation of IndexReader.reopen() functionality, as a set of 3 new classes (this was easier for him to implement, but should probably be folded into the core, if this looks good).


Migrated from LUCENE-743 by Otis Gospodnetic (@otisg), 3 votes, resolved Nov 17 2007 Attachments: IndexReaderUtils.java, lucene-743.patch (versions: 3), lucene-743-take10.patch, lucene-743-take2.patch, lucene-743-take3.patch, lucene-743-take4.patch, lucene-743-take5.patch, lucene-743-take6.patch, lucene-743-take7.patch, lucene-743-take8.patch, lucene-743-take9.patch, MyMultiReader.java, MySegmentReader.java, varient-no-isCloneSupported.BROKEN.patch Linked issues:

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

I'm assuming in your example you meant for reader2 and reader3 to also be SegmentReaders?

Yes that's what I meant. Sorry, I didn't make that clear.

Also in your example let's insert missing "reader1.close()" as the very first close? (Else it will never be closed because it's RC never hits 0).

Doesn't what you describe change the semantics of MultiReader.close()?

If you do:

IndexReader reader1 = IndexReader.open(index1);  
IndexReader multiReader1 = new MultiReader(new IndexReader[] {reader1, IndexReader.open(index2)});
multiReader1.close();

then today multiReader1.close() also closes reader1. That's why I consciously omitted reader1.close().

Consequently, if you do

IndexReader reader1 = IndexReader.open(index1);  
IndexReader multiReader1 = new MultiReader(new IndexReader[] {reader1, IndexReader.open(index2)});
IndexReader multiReader2 = new MultiReader(new IndexReader[] {reader1, IndexReader.open(index3)});
multiReader1.close();

then multiReader2 is not usable anymore, because multiReader1.close() closes reader1. But that can be explicitly avoided by the user because it's known that multiReader1 and multiReader2 share the same reader.

Now, with the reopen() code:

IndexReader reader1 = IndexReader.open(index1);  // optimized index, reader1 is a SegmentReader
IndexReader multiReader1 = new MultiReader(new IndexReader[] {reader1, IndexReader.open(index2)});
... // modify index2
IndexReader multiReader2 = multiReader1.reopen();  
// only index2 changed, so multiReader2 uses reader1 and has to increment the refcount of reader1

The user gets a new reader instance from multiReader.reopen(), but can't tell which of the subreaders has been reopened and which are shared. That's why multiReader1.close() should not close reader1 in this case and we need refcounting in order to make this work.

So do you suggest that a MultiReader should increment the refcounts when it is opened as well (in the constructor)? I believe we can implement it like this, but as I said it changes the semantics of MultiReader.close() (and ParallelReader.close() is, I believe, the same). A user would then have to close subreaders manually.

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

If you do:

IndexReader reader1 = IndexReader\.open(index1);  
IndexReader multiReader1 = new MultiReader(new IndexReader[] {reader1, IndexReader\.open(index2)});
multiReader1\.close();

then today multiReader1.close() also closes reader1. That's why I consciously omitted reader1.close().

Ahh, I missed that MultiReader is allowed to close all readers that were passed into it, when it is closed. OK, let's leave reader1.close() out of the example.

It's somewhat "aggressive" of MultiReader/ParallelReader to do that? If you go and use those same sub-readers in other MultiReaders then they closing of the first MultiReader will then break the other ones?

I think we are forced to keep this semantics, for backwards compatibility. But I don't really think MultiReader/ParallelReader should actually be this aggressive. Maybe in the future we can add ctors for MultiReader/ParallelReader that accept a "doClose" boolean to turn this off.

Anyway, it's simple to preserve this semantics with reference counting. It just means that IndexReader / MultiReader do not incref the readers they receive, and, when they are done with those readers, they must call their close(), not decref. Ie they "borrow the reference" that was passed in, rather than incref'ing their own reference, to the child readers.

With that change, plus the change below, your example works fine.

Consequently, if you do

IndexReader reader1 = IndexReader\.open(index1);  
IndexReader multiReader1 = new MultiReader(new IndexReader[] {reader1, IndexReader\.open(index2)});
IndexReader multiReader2 = new MultiReader(new IndexReader[] {reader1, IndexReader\.open(index3)});
multiReader1\.close();

then multiReader2 is not usable anymore, because multiReader1.close() closes reader1. But that can be explicitly avoided by the user because it's known that multiReader1 and multiReader2 share the same reader.

This is why I don't like the semantics we have today – I don't think it's right that the multiReader1.close() breaks multiReader2.

Now, with the reopen() code:

IndexReader reader1 = IndexReader\.open(index1);  // optimized index, reader1 is a SegmentReader
IndexReader multiReader1 = new MultiReader(new IndexReader[] {reader1, IndexReader\.open(index2)});
\.\.\. // modify index2
IndexReader multiReader2 = multiReader1\.reopen();  
// only index2 changed, so multiReader2 uses reader1 and has to increment the refcount of reader1

The user gets a new reader instance from multiReader.reopen(), but can't tell which of the subreaders has been reopened and which are shared. That's why multiReader1.close() should not close reader1 in this case and we need refcounting in order to make this work.

Both of these cases are easy to fix with reference counting: we just have to change ensureOpen() to assert that RC > 0 instead of closed==false. Ie, a reader may still be used as long as its RC is still non-zero.

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

I think we are forced to keep this semantics, for backwards compatibility. But I don't really think MultiReader/ParallelReader should actually be this aggressive. Maybe in the future we can add ctors for MultiReader/ParallelReader that accept a "doClose" boolean to turn this off.

Actually I retract this: it's no longer necessary as long as we change ensureOpen to assert that RC > 0 instead of closed==false.

I think this is actually a nice unexpected side-effect of using reference counting: it resolves this overly aggressive behavior of MultiReader/ParallelReader.

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

With that change, plus the change below, your example works fine.

Two things:

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

  • MultiReader/ParallelReader must not incref the subreaders on open() as you said. But on reopen() it must incref the subreaders that haven't changed and thus are shared with the old MultiReader/ ParallelReader. This further means, that the re-opened MultiReader/ ParallelReader must remember which of the subreaders to decref on close(), right?

Hmm, right. MultiReader/ParallelReader must keep track of whether it should call decref() or close() on each of its child readers, when it itself is closed.

  • If we change ensureOpen() like you suggest, then the user might still be able to use reader1 (in my example), even after reader1.close() was explicitly called. Probably not a big deal?

I think this is OK?

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

I think this is OK?

This was essentially the reason why I suggested to use two refcount values: one to control when to close a reader, and one to control when to close it's (shared) resources in case of SegmentReader. That approach would not alter the behaviour of IndexReader.close(). But I agree that your approach is simpler and I also think it is okay to change ensureOpen() and accept the slight API change.

So I'll go ahead and implement the refcount approach unless anybody objects.

Oh and Mike, thanks for bearing with me :-)

asfimport commented 17 years ago

Yonik Seeley (@yonik) (migrated from JIRA)

What about a new constructor for MultiReader/ParallelReader that implements more sensible semantics (increment refcount on readers passed to it, and decrement on close())?

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

What about a new constructor for MultiReader/ParallelReader that implements more sensible semantics (increment refcount on readers passed to it, and decrement on close())?

Yeah, when reference counting is implemented then such a constructor should be easy to add.

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

Oh and Mike, thanks for bearing with me :-)

Thank you for bearing with me!

What about a new constructor for MultiReader/ParallelReader that implements more sensible semantics (increment refcount on readers passed to it, and decrement on close())?

+1

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

Ok here is the next one :-)...

This patch implements the refCounting as discussed with Mike and Yonik above.

Other changes/improvements/comments:

I also made the changes suggested by Hoss (thanks!):

All unit tests pass.

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

Patch looks great! I'm still working through it but found a few small issues...

It might be good to put a "assert refCount > 0" at various places like decRef(), incRef(), ensureOpen()? That would require changing the constructors to init refCount=1 rather than incRef() it to 1.

I'm seeing a failure in contrib/memory testcase:

    [junit] *********** FILE=./NOTICE.txt
    [junit] Fatal error at query=Apache, file=./NOTICE.txt, anal=org.apache.lucene.analysis.SimpleAnalyzer@341960
    [junit] ------------- ---------------- ---------------
    [junit] Testcase: testMany(org.apache.lucene.index.memory.MemoryIndexTest): Caused an ERROR
    [junit] this IndexReader is closed
    [junit] org.apache.lucene.store.AlreadyClosedException: this IndexReader is closed
    [junit]     at org.apache.lucene.index.IndexReader.ensureOpen(IndexReader.java:158)
    [junit]     at org.apache.lucene.index.IndexReader.termDocs(IndexReader.java:632)
    [junit]     at org.apache.lucene.search.TermQuery$TermWeight.scorer(TermQuery.java:64)
    [junit]     at org.apache.lucene.search.IndexSearcher.search(IndexSearcher.java:143)
    [junit]     at org.apache.lucene.search.Searcher.search(Searcher.java:118)
    [junit]     at org.apache.lucene.search.Searcher.search(Searcher.java:97)
    [junit]     at org.apache.lucene.index.memory.MemoryIndexTest.query(MemoryIndexTest.java:412)
    [junit]     at org.apache.lucene.index.memory.MemoryIndexTest.run(MemoryIndexTest.java:313)
    [junit]     at org.apache.lucene.index.memory.MemoryIndexTest.testMany(MemoryIndexTest.java:234)

I think it's because MemoryIndexReader (private class in MemoryIndex.java) calls super(null) = IndexReader.IndexReader(Directory) in its constructor, which does not initialize the refCount to 1? If I insert incRef() into IndexReader.IndexReader(Directory) constructor, the test passes, but who else is using that constructor (ie will this double-incref in those cases?).

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

OK I think this patch is very close! I finished reviewing it – here's some more feedback:

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

Patch looks great! I'm still working through it but found a few small issues...

Thanks Mike! Very good review and feedback!

It might be good to put a "assert refCount > 0" at various places like...

Agreed. I added those asserts to incRef() and decRef(). I didn't add it to ensureOpen(), because it throws an AlreadyClosedException anyway, and some testcases check if this exception is thrown.

I'm seeing a failure in contrib/memory testcase:

Oups, I fixed this already. I changed the (deprecated) ctr IndexReader.IndexReader(Directory) to call this() which sets the refCount to 1. The test passes then. I made this fix yesterday, I think I just forgot to update the patch file before I submitted it, sorry about this.

  • In multiple places you catch an IOException and undo the attempted re-open, but shouldn't this be a try/finally instead so you also clean up on hitting any unchecked exceptions?

Yes of course! Changed it.

  • I think you need an explicit refCount for the Norm class in SegmentReader.

OK I see. I made this change as well. I also made the change that there is no chain, but one starting SegmentReader which all re-opened ones reference (see below). Now this starting SegmentReader won't close its norms until all other readers that reference it are closed (RC=0), because only then doClose() is called, which calls closeNorms(). Do you see an easy way how to improve this? Hmm, probably I have to definalize IndexReader.incRef() and decRef() and overwrite them in SegmentReader. Then SegmentReader.incRef() would also incRef the norms, SegmentReader.decref() would decref the norms, and somehow a clone that shares references the reader but not the norms (because they changed) would only incref the reader itself, but not the norms... Or do you see an easier way?

  • If you have a long series of reopens, then, all SegmentReaders in the chain will remain alive. So this is a [small] memory leak with time. I think if you changed referencedSegmentReader to always be the starting SegmentReader then this chain is broken

Good point. Ok I changed this and also the test cases that check the refCount values.

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

Looks great! All tests pass for me.

OK I see. I made this change as well. I also made the change that there is no chain, but one starting SegmentReader which all re-opened ones reference (see below). Now this starting SegmentReader won't close its norms until all other readers that reference it are closed (RC=0), because only then doClose() is called, which calls closeNorms(). Do you see an easy way how to improve this?

How about if SegmentReader.close() always calls Norm.decRef(), immediately, for each Norm is has open? EG you could implement doCloseUnsharedResources in SegmentReader and do it there). This way, if the SegmentReader has been closed but it shares resources (and not the Norms) with reopened SegmentReaders then its Norms would all decRef to 0 & be closed.

Also make sure that if a SegmentReader is decRef'd to 0 and close was never called, that also in this case you remember to call Norm.decRef for all open norms.

One more comment: I think you can partially share Norm instances? Eg if I have 2 fields that have norms, but only one of them changed since I opened this SegmentReader, then the reopened SegmentReader could share the Norm instance of the field that didn't change with the old SegmentReader? But right now you're re-loading all the Norms.

Otherwise no more comments!

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

How about if SegmentReader.close() always calls Norm.decRef(), immediately, for each Norm is has open? EG you could implement doCloseUnsharedResources in SegmentReader and do it there). This way,

Hmm I was thinking about this before (that's actually why I put that method in there). But I don't think this is gonna work. For example, let's say we use a MultiReader that has two SegmentReader SR1 and SR2. Now only SR2 changed, we reopen the MR which increases the refCount on SR1, because it shares that SR. Now we close the old MultiReader, which calls close() on SR1. If now SegmentReader.close() calls Norm.decRef(), then it will close the norms even though they are still used by the new MultiReader.

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

One more comment: I think you can partially share Norm instances? Eg

Good idea! Will make the change.

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

Hmm I was thinking about this before (that's actually why I put that method in there). But I don't think this is gonna work. For example, let's say we use a MultiReader that has two SegmentReader SR1 and SR2. Now only SR2 changed, we reopen the MR which increases the refCount on SR1, because it shares that SR. Now we close the old MultiReader, which calls close() on SR1. If now SegmentReader.close() calls Norm.decRef(), then it will close the norms even though they are still used by the new MultiReader.

Ugh, you're right. The challenge is sometimes a reference to SR means "I will use norms" (this is when MultiReader incRefs) but other times it means "I will not use norms" (this is when SR incRefs due to reopen).

OK, I like your original proposal: SR overrides incRef() and incrs its RC as well as the RC for each Norm it's using. Then, in SR's reopenSegment, you carefully incRef the "original" SR without incRef'ing its Norms (except for those Norms you will keep).

Likewise, SR overrides decRef() to decr its RC and RC for each Norm. But, when a reopened SR1.doClose() is called, you must carefully decRef the RD of the original SR but not decRef each of its Norms (except for those you had actually shared).

This way when MR calls SR.incRef/decRef then all Norms and the SR's RC are incr'd/decr'd. But when SR1 shares resources with an original SR it only incr's/decr's the refCount of the SR.

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

OK, I think it's finally working now! :-)

SegmentReader now overwrites incRef() and increments the readers RC, as well as the RCs of all norms. I further added the private method incRefReaderNotNorms() to SegmentReader, which is called in reopenSegment(), because it takes care of incrementing the RCs of all shared norms.

I also added the method doCloseUnsharedResources() to IndexReader, which is a NOOP by default. It is called when a reader is closed, even if its RC > 0. SegmentReader overwrites this method and closes (=decRef) the norms in it. The SegmentReader then remembers that it closed the norms already and won't close them again in doClose(), which is called when its RC finally drops to 0.

I also made the change you suggested, Mike, to only reload the field norms that actually changed. SegmentReader.openNorms() now checks if there is already a norm for a field in the HashTable, and only loads it if it's not there. reopenSegment() puts all norms in the new SegmentReader that haven't changed.

I added some new tests to verify the norms ref counting. All unit tests pass now. So I think this is ready to commit, but I'd feel more comfortable if you could review it again before I commit it.

asfimport commented 17 years ago

Yonik Seeley (@yonik) (migrated from JIRA)

I just did a quick partial review of SegmentReader for thread safety only and ran across some potential issues

There's probably other stuff, but I stopped looking. Since we are sharing things now, every method that was synchronized is now potentially unsafe. Synchronizing on the object being shared is probably a much better strategy now.

This is complex enough that in addition to review, I think we need a good multi-threaded test - 100 or 1000 threads over a ram directory, all changing, querying, retrieving docs, reopening, closing, etc.

asfimport commented 17 years ago

Yonik Seeley (@yonik) (migrated from JIRA)

It also looks like Norm.incRef is used in an unsafe manner (unsynchronized, or synchronized on the reader), and also Norm.decRef() is called inside a synchronized(norms) block, but an individual Norm may be shared across multiple Hashtables, right?

I don't think that norms even needs to be a synchronized Hashtable... it could be changed to a HashMap since it's contents never change, right?

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

OK, reviewed the latest patch:

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

This is complex enough that in addition to review, I think we need a good multi-threaded test - 100 or 1000 threads over a ram directory, all changing, querying, retrieving docs, reopening, closing, etc.

+1

We should fix all the synchronization issues you've found, create this unit test, and then iterate from there.

asfimport commented 17 years ago

Yonik Seeley (@yonik) (migrated from JIRA)

We should fix all the synchronization issues you've found, create this unit test, and then iterate from there.

Or reverse it... write the test first so we have confidence that it can at least uncover some of these issues. The test should do as little synchronization as possible of it's own so it doesn't mask a lack of synchronization in the core. It should be possible to uncover the unsynchronized concurrent use of IndexInput at least, and hopefully some of the refcounting issues too.

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

Or reverse it... write the test first so we have confidence that it can at least uncover some of these issues. The test should do as little synchronization as possible of it's own so it doesn't mask a lack of synchronization in the core. It should be possible to uncover the unsynchronized concurrent use of IndexInput at least, and hopefully some of the refcounting issues too.

Excellent, I agree!

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

I just did a quick partial review of SegmentReader for thread safety only and ran across some potential issues

OK, let's scratch my "ready to commit" comment ;)

A question about thread-safety here. I agree that we must fix all possible problems concerning two or more IndexReaders in read-mode, like the FieldsReader issue.

On the other hand: We're saying that performing write operations on a re-opened reader results in undefined behavior. Some of the issues you mentioned, Yonik, should only apply in case one of the shared readers is used to perform index modifications, right? Then the question is: how much sense does it make to make reopen() thread-safe in the write case then?

So I think the multi-threaded testcase should not perform index modifications using readers involved in a reopen()?

asfimport commented 17 years ago

Yonik Seeley (@yonik) (migrated from JIRA)

Sorry, I hadn't kept up with this issue wrt what was going to be legal (and we should definitely only test what will be legal in the MT test). So that removes the deletedDocs issue I guess.

asfimport commented 17 years ago

Thomas Peuss (migrated from JIRA)

To find concurrency issues with an unit test is hard to do, because your potential problems lie in the time domain and not in the code domain. ;-)

From my experience following things can have impact on the results of such a test:

And be prepared that one time your tests runs through without a problem and on the next run it breaks...

Just my € 0.02

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

Changes in this patch:

Still outstanding:

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

Changes:

The thread-safety test still sometimes fails. The weird thing is that the test verifies that the re-opened readers always return correct results. The only problem is that the refCount value is not always 0 at the end of the test. I'm starting to think that the testcase itself has a problem? Maybe someone else can take a look

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

I think the cause of the intermittant failure in the test is a missing try/finally in doReopen to properly close/decRef everything on exception.

Because of lockless commits, a commit could be in-process while you are re-opening, in which case you could hit an IOexception and you must therefore decRef those norms you had incRef'd (and, close eg the newly opened FieldsReader).

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

> I think the cause of the intermittant failure in the test is a missing > try/finally in doReopen to properly close/decRef everything on > exception.

Awesome! Thanks so much for pointing me there, Mike! I was getting a little suicidal here already ... ;)

I should have read the comment in SegmentReader#initialize more carefully:

    } finally {

      // With lock-less commits, it's entirely possible (and
      // fine) to hit a FileNotFound exception above.  In
      // this case, we want to explicitly close any subset
      // of things that were opened so that we don't have to
      // wait for a GC to do so.
      if (!success) {
        doClose();
      }
    }

While debugging, it's easy to miss such an exception, because SegmentInfos.FindSegmentsFile#run() ignores it. But it's good that it logs such an exception, I just have to remember to print out the infoStream next time.

So it seems that this was indeed the cause for the failing test case. I made the change and so far the tests didn't fail anymore (ran it about 10 times so far). I'll run it another few times on a different JVM and submit an updated patch in a short while if it doesn't fail again.

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

OK, all tests pass now, including the thread-safety test. I ran it several times on different JVMs.

Changes:

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

Awesome! Thanks so much for pointing me there, Mike! I was getting a little suicidal here already ...

No problem, I lost some hairs tracking that one down too!!

OK, latest patch looks good! I love the new threaded unit test.

Only two smallish comments:

asfimport commented 17 years ago

Yonik Seeley (@yonik) (migrated from JIRA)

So how about a public IndexReader.flush() method so that one could also reopen readers that were used for changes?

Usecase:

reader.deleteDocument() reader.flush() writer = new IndexWriter() writer.addDocument() writer.close() reader.reopen() reader.deleteDocument()

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

  • You should also close fieldsReader when referencedSegmentReader != null, right? (in SegmentReader.doClose)

Yes, will do!

  • In the new try/finally in reopenSegment: if you first setup referencedSegmentReader, then can't that finally clause just be clone.decRef() instead of duplicating code for decRef'ing norms, closeNorms(), etc.?

Hmm, what if then in clone.close() an exception is thrown from FieldsReader.close() or singleNormStream.close(). In that case it would not decRef the referenced reader.

Hmm but actually we could change the order in close() so that referencedSegmentReader.decRefReaderNotNorms() is done first even if the following close() operations don't succeed?

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

So how about a public IndexReader.flush() method

Since our goal is it to make IndexReader read-only in the future (#2106), do you really think we need to add this?

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

Hmm but actually we could change the order in close() so that referencedSegmentReader.decRefReaderNotNorms() is done first even if the following close() operations don't succeed?

+1

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

So how about a public IndexReader.flush() method

I think also if we do decide to do this we should open a new issue for it?

asfimport commented 17 years ago

Yonik Seeley (@yonik) (migrated from JIRA)

> Since our goal is it to make IndexReader read-only in the future > (#2106), do you really think we need to add this?

flush() would make reopen() useful in more cases, and #2106 is further off (not Lucene 2.3, right?) Anyway, flush() would be considered a write operation like setNorm() & deleteDocument() and could be deprecated along with them in the future if that's how we decide to go.

> I think also if we do decide to do this we should open a new issue for it?

Yes, that's fine.

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

I think also if we do decide to do this we should open a new issue for it?

+1

I'll open a new issue.

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

Changes:

asfimport commented 17 years ago

Michael McCandless (@mikemccand) (migrated from JIRA)

Patch looks good. Only thing I found was this leftover System.out.println, in SegmentReader.java:

  System.out.println("refCount " + getRefCount());
asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

Thanks for the review, Mike! I'll remove the println.

Ok, I think this patch has been reviewed a bunch of times and should be ready to commit now. I'll wait another day and commit it then if nobody objects.

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

Changes:

I'm going to commit this soon!

asfimport commented 17 years ago

Michael Busch (migrated from JIRA)

Committed! Phew!!!