|
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() { |
@@ -1015,12 +1016,26 @@ private Engine.IndexResult applyIndexOperation( |
1015 | 1016 | return index(engine, operation); |
1016 | 1017 | } |
1017 | 1018 |
|
1018 | | - public void setFieldInfos(FieldInfos fieldInfos) { |
1019 | | - this.fieldInfos = fieldInfos; |
| 1019 | + private static final VarHandle FIELD_INFOS; |
| 1020 | + |
| 1021 | + static { |
| 1022 | + try { |
| 1023 | + FIELD_INFOS = MethodHandles.lookup().findVarHandle(IndexShard.class, "fieldInfos", FieldInfos.class); |
| 1024 | + } catch (Exception e) { |
| 1025 | + throw new ExceptionInInitializerError(e); |
| 1026 | + } |
1020 | 1027 | } |
1021 | 1028 |
|
1022 | 1029 | public FieldInfos getFieldInfos() { |
1023 | | - return fieldInfos; |
| 1030 | + var res = fieldInfos; |
| 1031 | + if (res == null) { |
| 1032 | + // don't replace field infos loaded via the refresh listener to avoid overwriting the field with an older version of the |
| 1033 | + // field infos when racing with a refresh |
| 1034 | + var read = loadFieldInfos(); |
| 1035 | + var existing = (FieldInfos) FIELD_INFOS.compareAndExchange(this, null, read); |
| 1036 | + return existing == null ? read : existing; |
| 1037 | + } |
| 1038 | + return res; |
1024 | 1039 | } |
1025 | 1040 |
|
1026 | 1041 | public static Engine.Index prepareIndex( |
@@ -4114,16 +4129,21 @@ public void beforeRefresh() {} |
4114 | 4129 |
|
4115 | 4130 | @Override |
4116 | 4131 | public void afterRefresh(boolean didRefresh) { |
4117 | | - if (enableFieldHasValue && (didRefresh || fieldInfos == FieldInfos.EMPTY)) { |
4118 | | - try (Engine.Searcher hasValueSearcher = getEngine().acquireSearcher("field_has_value")) { |
4119 | | - setFieldInfos(FieldInfos.getMergedFieldInfos(hasValueSearcher.getIndexReader())); |
4120 | | - } catch (AlreadyClosedException ignore) { |
4121 | | - // engine is closed - no updated FieldInfos is fine |
4122 | | - } |
| 4132 | + if (enableFieldHasValue && (didRefresh || fieldInfos == null)) { |
| 4133 | + FIELD_INFOS.setRelease(IndexShard.this, loadFieldInfos()); |
4123 | 4134 | } |
4124 | 4135 | } |
4125 | 4136 | } |
4126 | 4137 |
|
| 4138 | + private FieldInfos loadFieldInfos() { |
| 4139 | + try (Engine.Searcher hasValueSearcher = getEngine().acquireSearcher("field_has_value")) { |
| 4140 | + return FieldInfos.getMergedFieldInfos(hasValueSearcher.getIndexReader()); |
| 4141 | + } catch (AlreadyClosedException ignore) { |
| 4142 | + // engine is closed - no update to FieldInfos is fine |
| 4143 | + } |
| 4144 | + return FieldInfos.EMPTY; |
| 4145 | + } |
| 4146 | + |
4127 | 4147 | /** |
4128 | 4148 | * Returns the shard-level field stats, which includes the number of segments in the latest NRT reader of this shard |
4129 | 4149 | * and the total number of fields across those segments. |
|
0 commit comments