Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
dd8542b
Allow unused FieldsProducers and DocValuesProducers to be unloaded
magibney Oct 10, 2025
e89c1a5
add test
magibney Oct 10, 2025
7420c74
fix tests -- mostly around Directory closing
magibney Oct 10, 2025
b6fabe6
allow backing val to be GC'd
magibney Oct 14, 2025
a1d1185
safer one-time set of external refqueue handling
magibney Oct 14, 2025
4e76298
reorder field assignments in Unloader ctor (NPE, etc.)
magibney Oct 15, 2025
826da66
Unloader ctor should hold a ref to prevent immediate collection
magibney Oct 15, 2025
4946d5c
also unload PointsReader
magibney Oct 16, 2025
e77fb9b
sysprop-configurable totally disable unloading
magibney Oct 17, 2025
dee742d
must incRef before derivative refs
magibney Oct 20, 2025
b14f3e1
use explicit method to prevent dead ref GC
magibney Oct 20, 2025
c236ad0
always track the _raw_ instance
magibney Oct 20, 2025
8950ded
fix regression where shared objects were tracked
magibney Oct 23, 2025
232b9d5
make lucene.unload.parallelRefQueueCount sysprop-configurable (power …
magibney Oct 24, 2025
1f9eef3
make lucene.unload.assignRefQueueByThread sysprop-configurable (defau…
magibney Oct 24, 2025
2becf0b
place refs in a pre-tracking "holding area"
magibney Oct 28, 2025
c0fd643
add all available sysprops to defaults-tests.gradle
magibney Oct 28, 2025
bbd92fc
Ref should extent PhantomReference, not WeakReference
magibney Oct 29, 2025
3518392
Only directly track top-level objects
magibney Oct 30, 2025
7c76dfc
do ref-tracking on an arbitrary resource-associated sentinel object
magibney Oct 30, 2025
33842e1
remove the "holding" concept
magibney Oct 31, 2025
42f945d
reduce num of refs?
magibney Oct 31, 2025
7c3a368
checkpoint before excising refqueue stuff
magibney Oct 31, 2025
9f9aeda
we don't actually need refcounts -- much simpler
magibney Oct 31, 2025
f5723d4
remove unused args
magibney Nov 3, 2025
63d4ae0
allow helper-controlled deferral of unloading
magibney Nov 4, 2025
aa4f3c8
support disabling "adaptive defer"
magibney Nov 4, 2025
eb89ad8
measuring time since last access makes no sense on initial load (mess…
magibney Nov 4, 2025
b21c134
fix typo in sysprop name
magibney Nov 4, 2025
454a430
expose time parsing method publicly
magibney Nov 10, 2025
46e1d72
add public method javaodocs
magibney Nov 18, 2025
d37e17b
support per-format disabling of unloading
magibney Nov 18, 2025
f16d509
move Unloader invocation to PerFieldPostingsFormat and PerFieldDocVal…
magibney Nov 19, 2025
c55f071
temporary commit for evaluting reload paths
magibney Nov 19, 2025
a180020
more nuanced disabling of unloading
magibney Nov 21, 2025
0c25238
CFS is the wrong heuristic for unload enable
magibney Nov 21, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/gradle-precommit.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ jobs:
uses: ./.github/actions/gradle-caches

- name: Run gradle check (without tests)
run: ./gradlew check -x test -Ptask.times=true --max-workers 2
run: ./gradlew check -x test -Ptask.times=true --max-workers 2 -x :lucene:analysis.tests:renderJavadoc -x :lucene:distribution.tests:renderJavadoc -x :lucene:analysis:morfologik.tests:renderJavadoc

# This runs all tests without any other validation checks.
tests:
Expand Down Expand Up @@ -74,7 +74,7 @@ jobs:
uses: ./.github/actions/gradle-caches

- name: Run gradle tests
run: ./gradlew test "-Ptask.times=true" --max-workers 2
run: ./gradlew test "-Ptask.times=true" -Plucene.unload.executorPerDirectory=true -Plucene.unload.ttl=1 -Plucene.unload.initial=0 --max-workers 2

- name: Echo settings
run: cat gradle.properties
4 changes: 4 additions & 0 deletions gradle/testing/defaults-tests.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ allprojects {
// completes.
// [propName: 'tests.foo', value: "bar", description: "Sets foo in tests."],
testOptions = [
[propName: 'lucene.unload.executorPerDirectory', value: false, description: "Directory instances supply their own unloading executor"],
[propName: 'lucene.unload.ttl', value: '60m', description: "Time since last use at which a resource becomes eligible for unloading"],
[propName: 'lucene.unload.initial', value: '1m', description: "Extra time allotted for first resource use after load/reload"],
[propName: 'lucene.unload.disable', value: 'false', description: "Disables resource unloading"],
// asserts, debug output.
[propName: 'tests.verbose', value: false, description: "Enables verbose mode (emits full test outputs immediately)."],
[propName: 'tests.workDir',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedNumericDocValues;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.Unloader;
import org.apache.lucene.util.IOUtils;

/**
Expand Down Expand Up @@ -300,9 +301,17 @@ public FieldsReader(final SegmentReadState readState) throws IOException {
String segmentSuffix =
getFullSegmentSuffix(readState.segmentSuffix, getSuffix(formatName, suffix));
if (!formats.containsKey(segmentSuffix)) {
formats.put(
segmentSuffix,
format.fieldsProducer(new SegmentReadState(readState, segmentSuffix)));
SegmentReadState srs = new SegmentReadState(readState, segmentSuffix);
DocValuesProducer dvp;
if (format instanceof Unloader.UnloadAware
&& ((Unloader.UnloadAware) format).disableUnload(srs)) {
dvp = format.fieldsProducer(srs);
} else {
dvp =
Unloader.docValuesProducer(
() -> format.fieldsProducer(srs), srs.segmentInfo.dir, srs);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Incorrect directory access in PerFieldDocValuesFormat

The code accesses srs.segmentInfo.dir to pass a Directory to Unloader.docValuesProducer(), but SegmentInfo does not have a dir property. This should be srs.directory instead, matching the usage pattern in PerFieldPostingsFormat.java line 334. This will cause an AttributeError or similar runtime exception.

Fix in Cursor Fix in Web

}
formats.put(segmentSuffix, dvp);
}
fields.put(fieldName, formats.get(segmentSuffix));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.apache.lucene.index.SegmentReadState;
import org.apache.lucene.index.SegmentWriteState;
import org.apache.lucene.index.Terms;
import org.apache.lucene.index.Unloader;
import org.apache.lucene.util.CollectionUtil;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.MergedIterator;
Expand Down Expand Up @@ -323,9 +324,16 @@ public FieldsReader(final SegmentReadState readState) throws IOException {
PostingsFormat format = PostingsFormat.forName(formatName);
String segmentSuffix = getSuffix(formatName, suffix);
if (!formats.containsKey(segmentSuffix)) {
formats.put(
segmentSuffix,
format.fieldsProducer(new SegmentReadState(readState, segmentSuffix)));
SegmentReadState srs = new SegmentReadState(readState, segmentSuffix);
FieldsProducer fp;
if (format instanceof Unloader.UnloadAware
&& ((Unloader.UnloadAware) format).disableUnload(srs)) {
fp = format.fieldsProducer(srs);
} else {
fp =
Unloader.fieldsProducer(() -> format.fieldsProducer(srs), srs.directory, srs);
}
formats.put(segmentSuffix, fp);
}
fields.put(fieldName, formats.get(segmentSuffix));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import org.apache.lucene.codecs.FieldsProducer;
import org.apache.lucene.codecs.KnnVectorsReader;
import org.apache.lucene.codecs.NormsProducer;
import org.apache.lucene.codecs.PointsFormat;
import org.apache.lucene.codecs.PointsReader;
import org.apache.lucene.codecs.PostingsFormat;
import org.apache.lucene.codecs.StoredFieldsReader;
Expand Down Expand Up @@ -149,7 +150,14 @@ protected TermVectorsReader initialValue() {
}

if (coreFieldInfos.hasPointValues()) {
pointsReader = codec.pointsFormat().fieldsReader(segmentReadState);
PointsFormat pf = codec.pointsFormat();
if (pf instanceof Unloader.UnloadAware
&& ((Unloader.UnloadAware) pf).disableUnload(segmentReadState)) {
pointsReader = pf.fieldsReader(segmentReadState);
} else {
pointsReader =
Unloader.pointsReader(() -> pf.fieldsReader(segmentReadState), dir, segmentReadState);
}
} else {
pointsReader = null;
}
Expand Down
Loading