-
Notifications
You must be signed in to change notification settings - Fork 25.6k
Load FieldInfos from store if not yet initialised through a refresh on IndexShard #125650
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
1199310
b98920e
fdd7f33
4addc41
b822d40
d392f4f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
pr: 125650 | ||
summary: Load `FieldInfos` from store if not yet initialised through a refresh on | ||
`IndexShard` | ||
area: Search | ||
type: bug | ||
issues: | ||
- 125483 |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -158,6 +158,8 @@ | |
import java.io.Closeable; | ||
import java.io.IOException; | ||
import java.io.PrintStream; | ||
import java.lang.invoke.MethodHandles; | ||
import java.lang.invoke.VarHandle; | ||
import java.nio.channels.ClosedByInterruptException; | ||
import java.nio.charset.StandardCharsets; | ||
import java.util.ArrayList; | ||
|
@@ -427,7 +429,6 @@ public IndexShard( | |
this.refreshFieldHasValueListener = new RefreshFieldHasValueListener(); | ||
this.relativeTimeInNanosSupplier = relativeTimeInNanosSupplier; | ||
this.indexCommitListener = indexCommitListener; | ||
this.fieldInfos = FieldInfos.EMPTY; | ||
} | ||
|
||
public ThreadPool getThreadPool() { | ||
|
@@ -1029,12 +1030,26 @@ private Engine.IndexResult applyIndexOperation( | |
return index(engine, operation); | ||
} | ||
|
||
public void setFieldInfos(FieldInfos fieldInfos) { | ||
this.fieldInfos = fieldInfos; | ||
private static final VarHandle FIELD_INFOS; | ||
|
||
static { | ||
try { | ||
FIELD_INFOS = MethodHandles.lookup().findVarHandle(IndexShard.class, "fieldInfos", FieldInfos.class); | ||
} catch (Exception e) { | ||
throw new ExceptionInInitializerError(e); | ||
} | ||
} | ||
|
||
public FieldInfos getFieldInfos() { | ||
return fieldInfos; | ||
var res = fieldInfos; | ||
if (res == null) { | ||
// don't replace field infos loaded via the refresh listener to avoid overwriting the field with an older version of the | ||
// field infos when racing with a refresh | ||
var read = loadFieldInfos(); | ||
var existing = (FieldInfos) FIELD_INFOS.compareAndExchange(this, null, read); | ||
return existing == null ? read : existing; | ||
} | ||
return res; | ||
} | ||
|
||
public static Engine.Index prepareIndex( | ||
|
@@ -4266,16 +4281,21 @@ public void beforeRefresh() {} | |
|
||
@Override | ||
public void afterRefresh(boolean didRefresh) { | ||
if (enableFieldHasValue && (didRefresh || fieldInfos == FieldInfos.EMPTY)) { | ||
try (Engine.Searcher hasValueSearcher = getEngine().acquireSearcher("field_has_value")) { | ||
setFieldInfos(FieldInfos.getMergedFieldInfos(hasValueSearcher.getIndexReader())); | ||
} catch (AlreadyClosedException ignore) { | ||
// engine is closed - no updated FieldInfos is fine | ||
} | ||
if (enableFieldHasValue && (didRefresh || fieldInfos == null)) { | ||
FIELD_INFOS.setRelease(IndexShard.this, loadFieldInfos()); | ||
} | ||
} | ||
} | ||
|
||
private FieldInfos loadFieldInfos() { | ||
try (Engine.Searcher hasValueSearcher = getEngine().acquireSearcher("field_has_value")) { | ||
return FieldInfos.getMergedFieldInfos(hasValueSearcher.getIndexReader()); | ||
} catch (AlreadyClosedException ignore) { | ||
// engine is closed - no update to3 FieldInfos is fine | ||
|
||
} | ||
return FieldInfos.EMPTY; | ||
} | ||
|
||
/** | ||
* Returns the shard-level field stats, which includes the number of segments in the latest NRT reader of this shard | ||
* and the total number of fields across those segments. | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ | |
|
||
package org.elasticsearch.xpack.searchablesnapshots; | ||
|
||
import org.elasticsearch.action.fieldcaps.FieldCapabilitiesResponse; | ||
import org.elasticsearch.action.index.IndexRequestBuilder; | ||
import org.elasticsearch.action.search.SearchRequest; | ||
import org.elasticsearch.action.search.SearchType; | ||
|
@@ -125,5 +126,9 @@ public void testKeywordSortedQueryOnFrozen() throws Exception { | |
assertThat(searchResponse.getTotalShards(), equalTo(20)); | ||
assertThat(searchResponse.getHits().getTotalHits().value(), equalTo(4L)); | ||
}); | ||
|
||
// check that field_caps empty field filtering works as well | ||
FieldCapabilitiesResponse response = client().prepareFieldCaps(mountedIndices).setFields("*").setincludeEmptyFields(false).get(); | ||
assertNotNull(response.getField("keyword")); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wonder if it makes sense to add the same test to the N-2 indices related tests for indices that are imported as verified read-only. We know the fix addresses the same issue for them too, but it'd be safer to have a specific test for them? These tests are under There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ++ definitely. Let me try something, maybe I can get the full field caps suite running for searchable snapshots and there somehow, would be really nice to have coverage across all the implementations that play tricks on the engine :) |
||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah this is a bit I don't like about VarHandle, and I'd normally prefer an
Atomic...
for the CAS operation for readability.However, the tradeoff here is pretty sweet as we avoid creating (a potential alternative) one
Atomic...
instance for everyIndexShard
in order to wrap thefieldInfos
giving us a sweet memory saving.Nicely done ! :)