|
156 | 156 | import java.io.Closeable; |
157 | 157 | import java.io.IOException; |
158 | 158 | import java.io.PrintStream; |
| 159 | +import java.lang.invoke.MethodHandles; |
| 160 | +import java.lang.invoke.VarHandle; |
159 | 161 | import java.nio.channels.ClosedByInterruptException; |
160 | 162 | import java.nio.charset.StandardCharsets; |
161 | 163 | import java.util.ArrayList; |
@@ -413,7 +415,6 @@ public IndexShard( |
413 | 415 | this.refreshFieldHasValueListener = new RefreshFieldHasValueListener(); |
414 | 416 | this.relativeTimeInNanosSupplier = relativeTimeInNanosSupplier; |
415 | 417 | this.indexCommitListener = indexCommitListener; |
416 | | - this.fieldInfos = FieldInfos.EMPTY; |
417 | 418 | } |
418 | 419 |
|
419 | 420 | public ThreadPool getThreadPool() { |
@@ -1011,12 +1012,26 @@ private Engine.IndexResult applyIndexOperation( |
1011 | 1012 | return index(engine, operation); |
1012 | 1013 | } |
1013 | 1014 |
|
1014 | | - public void setFieldInfos(FieldInfos fieldInfos) { |
1015 | | - this.fieldInfos = fieldInfos; |
| 1015 | + private static final VarHandle FIELD_INFOS; |
| 1016 | + |
| 1017 | + static { |
| 1018 | + try { |
| 1019 | + FIELD_INFOS = MethodHandles.lookup().findVarHandle(IndexShard.class, "fieldInfos", FieldInfos.class); |
| 1020 | + } catch (Exception e) { |
| 1021 | + throw new ExceptionInInitializerError(e); |
| 1022 | + } |
1016 | 1023 | } |
1017 | 1024 |
|
1018 | 1025 | public FieldInfos getFieldInfos() { |
1019 | | - return fieldInfos; |
| 1026 | + var res = fieldInfos; |
| 1027 | + if (res == null) { |
| 1028 | + // don't replace field infos loaded via the refresh listener to avoid overwriting the field with an older version of the |
| 1029 | + // field infos when racing with a refresh |
| 1030 | + var read = loadFieldInfos(); |
| 1031 | + var existing = (FieldInfos) FIELD_INFOS.compareAndExchange(this, null, read); |
| 1032 | + return existing == null ? read : existing; |
| 1033 | + } |
| 1034 | + return res; |
1020 | 1035 | } |
1021 | 1036 |
|
1022 | 1037 | public static Engine.Index prepareIndex( |
@@ -4067,16 +4082,21 @@ public void beforeRefresh() {} |
4067 | 4082 |
|
4068 | 4083 | @Override |
4069 | 4084 | public void afterRefresh(boolean didRefresh) { |
4070 | | - if (enableFieldHasValue && (didRefresh || fieldInfos == FieldInfos.EMPTY)) { |
4071 | | - try (Engine.Searcher hasValueSearcher = getEngine().acquireSearcher("field_has_value")) { |
4072 | | - setFieldInfos(FieldInfos.getMergedFieldInfos(hasValueSearcher.getIndexReader())); |
4073 | | - } catch (AlreadyClosedException ignore) { |
4074 | | - // engine is closed - no updated FieldInfos is fine |
4075 | | - } |
| 4085 | + if (enableFieldHasValue && (didRefresh || fieldInfos == null)) { |
| 4086 | + FIELD_INFOS.setRelease(IndexShard.this, loadFieldInfos()); |
4076 | 4087 | } |
4077 | 4088 | } |
4078 | 4089 | } |
4079 | 4090 |
|
| 4091 | + private FieldInfos loadFieldInfos() { |
| 4092 | + try (Engine.Searcher hasValueSearcher = getEngine().acquireSearcher("field_has_value")) { |
| 4093 | + return FieldInfos.getMergedFieldInfos(hasValueSearcher.getIndexReader()); |
| 4094 | + } catch (AlreadyClosedException ignore) { |
| 4095 | + // engine is closed - no update to FieldInfos is fine |
| 4096 | + } |
| 4097 | + return FieldInfos.EMPTY; |
| 4098 | + } |
| 4099 | + |
4080 | 4100 | /** |
4081 | 4101 | * Returns the shard-level field stats, which includes the number of segments in the latest NRT reader of this shard |
4082 | 4102 | * and the total number of fields across those segments. |
|
0 commit comments