2020package org .elasticsearch .common .lucene .uid ;
2121
2222import org .apache .lucene .index .IndexReader ;
23- import org .apache .lucene .index .LeafReader ;
2423import org .apache .lucene .index .LeafReaderContext ;
24+ import org .apache .lucene .index .NumericDocValues ;
2525import org .apache .lucene .index .Term ;
2626import org .apache .lucene .util .CloseableThreadLocal ;
2727import org .elasticsearch .common .util .concurrent .ConcurrentCollections ;
28+ import org .elasticsearch .index .mapper .SeqNoFieldMapper ;
2829
2930import java .io .IOException ;
3031import java .util .List ;
3637/** Utility class to resolve the Lucene doc ID, version, seqNo and primaryTerms for a given uid. */
3738public final class VersionsAndSeqNoResolver {
3839
39- static final ConcurrentMap <Object , CloseableThreadLocal <PerThreadIDVersionAndSeqNoLookup >> lookupStates =
40+ static final ConcurrentMap <IndexReader . CacheKey , CloseableThreadLocal <PerThreadIDVersionAndSeqNoLookup [] >> lookupStates =
4041 ConcurrentCollections .newConcurrentMapWithAggressiveConcurrency ();
4142
4243 // Evict this reader from lookupStates once it's closed:
4344 private static final IndexReader .ClosedListener removeLookupState = key -> {
44- CloseableThreadLocal <PerThreadIDVersionAndSeqNoLookup > ctl = lookupStates .remove (key );
45+ CloseableThreadLocal <PerThreadIDVersionAndSeqNoLookup [] > ctl = lookupStates .remove (key );
4546 if (ctl != null ) {
4647 ctl .close ();
4748 }
4849 };
4950
50- private static PerThreadIDVersionAndSeqNoLookup getLookupState (LeafReader reader , String uidField ) throws IOException {
51- IndexReader .CacheHelper cacheHelper = reader .getCoreCacheHelper ();
52- CloseableThreadLocal <PerThreadIDVersionAndSeqNoLookup > ctl = lookupStates .get (cacheHelper .getKey ());
51+ private static PerThreadIDVersionAndSeqNoLookup [] getLookupState (IndexReader reader , String uidField ) throws IOException {
52+ // We cache on the top level
53+ IndexReader .CacheHelper cacheHelper = reader .getReaderCacheHelper ();
54+ CloseableThreadLocal <PerThreadIDVersionAndSeqNoLookup []> ctl = lookupStates .get (cacheHelper .getKey ());
5355 if (ctl == null ) {
5456 // First time we are seeing this reader's core; make a new CTL:
5557 ctl = new CloseableThreadLocal <>();
56- CloseableThreadLocal <PerThreadIDVersionAndSeqNoLookup > other = lookupStates .putIfAbsent (cacheHelper .getKey (), ctl );
58+ CloseableThreadLocal <PerThreadIDVersionAndSeqNoLookup [] > other = lookupStates .putIfAbsent (cacheHelper .getKey (), ctl );
5759 if (other == null ) {
58- // Our CTL won, we must remove it when the core is closed:
60+ // Our CTL won, we must remove it when the reader is closed:
5961 cacheHelper .addClosedListener (removeLookupState );
6062 } else {
6163 // Another thread beat us to it: just use their CTL:
6264 ctl = other ;
6365 }
6466 }
6567
66- PerThreadIDVersionAndSeqNoLookup lookupState = ctl .get ();
68+ PerThreadIDVersionAndSeqNoLookup [] lookupState = ctl .get ();
6769 if (lookupState == null ) {
68- lookupState = new PerThreadIDVersionAndSeqNoLookup (reader , uidField );
70+ lookupState = new PerThreadIDVersionAndSeqNoLookup [reader .leaves ().size ()];
71+ for (LeafReaderContext leaf : reader .leaves ()) {
72+ lookupState [leaf .ord ] = new PerThreadIDVersionAndSeqNoLookup (leaf , uidField );
73+ }
6974 ctl .set (lookupState );
70- } else if (Objects .equals (lookupState .uidField , uidField ) == false ) {
75+ }
76+
77+ if (lookupState .length != reader .leaves ().size ()) {
78+ throw new AssertionError ("Mismatched numbers of leaves: " + lookupState .length + " != " + reader .leaves ().size ());
79+ }
80+
81+ if (lookupState .length > 0 && Objects .equals (lookupState [0 ].uidField , uidField ) == false ) {
7182 throw new AssertionError ("Index does not consistently use the same uid field: ["
72- + uidField + "] != [" + lookupState .uidField + "]" );
83+ + uidField + "] != [" + lookupState [ 0 ] .uidField + "]" );
7384 }
7485
7586 return lookupState ;
@@ -112,17 +123,13 @@ public static class DocIdAndSeqNo {
112123 * </ul>
113124 */
114125 public static DocIdAndVersion loadDocIdAndVersion (IndexReader reader , Term term ) throws IOException {
126+ PerThreadIDVersionAndSeqNoLookup [] lookups = getLookupState (reader , term .field ());
115127 List <LeafReaderContext > leaves = reader .leaves ();
116- if (leaves .isEmpty ()) {
117- return null ;
118- }
119128 // iterate backwards to optimize for the frequently updated documents
120129 // which are likely to be in the last segments
121130 for (int i = leaves .size () - 1 ; i >= 0 ; i --) {
122- LeafReaderContext context = leaves .get (i );
123- LeafReader leaf = context .reader ();
124- PerThreadIDVersionAndSeqNoLookup lookup = getLookupState (leaf , term .field ());
125- DocIdAndVersion result = lookup .lookupVersion (term .bytes (), leaf .getLiveDocs (), context );
131+ PerThreadIDVersionAndSeqNoLookup lookup = lookups [leaves .get (i ).ord ];
132+ DocIdAndVersion result = lookup .lookupVersion (term .bytes ());
126133 if (result != null ) {
127134 return result ;
128135 }
@@ -137,17 +144,13 @@ public static DocIdAndVersion loadDocIdAndVersion(IndexReader reader, Term term)
137144 * </ul>
138145 */
139146 public static DocIdAndSeqNo loadDocIdAndSeqNo (IndexReader reader , Term term ) throws IOException {
147+ PerThreadIDVersionAndSeqNoLookup [] lookups = getLookupState (reader , term .field ());
140148 List <LeafReaderContext > leaves = reader .leaves ();
141- if (leaves .isEmpty ()) {
142- return null ;
143- }
144149 // iterate backwards to optimize for the frequently updated documents
145150 // which are likely to be in the last segments
146151 for (int i = leaves .size () - 1 ; i >= 0 ; i --) {
147- LeafReaderContext context = leaves .get (i );
148- LeafReader leaf = context .reader ();
149- PerThreadIDVersionAndSeqNoLookup lookup = getLookupState (leaf , term .field ());
150- DocIdAndSeqNo result = lookup .lookupSeqNo (term .bytes (), leaf .getLiveDocs (), context );
152+ PerThreadIDVersionAndSeqNoLookup lookup = lookups [leaves .get (i ).ord ];
153+ DocIdAndSeqNo result = lookup .lookupSeqNo (term .bytes ());
151154 if (result != null ) {
152155 return result ;
153156 }
@@ -159,9 +162,13 @@ public static DocIdAndSeqNo loadDocIdAndSeqNo(IndexReader reader, Term term) thr
159162 * Load the primaryTerm associated with the given {@link DocIdAndSeqNo}
160163 */
161164 public static long loadPrimaryTerm (DocIdAndSeqNo docIdAndSeqNo , String uidField ) throws IOException {
162- LeafReader leaf = docIdAndSeqNo .context .reader ();
163- PerThreadIDVersionAndSeqNoLookup lookup = getLookupState (leaf , uidField );
164- long result = lookup .lookUpPrimaryTerm (docIdAndSeqNo .docId , leaf );
165+ NumericDocValues primaryTerms = docIdAndSeqNo .context .reader ().getNumericDocValues (SeqNoFieldMapper .PRIMARY_TERM_NAME );
166+ long result ;
167+ if (primaryTerms != null && primaryTerms .advanceExact (docIdAndSeqNo .docId )) {
168+ result = primaryTerms .longValue ();
169+ } else {
170+ result = 0 ;
171+ }
165172 assert result > 0 : "should always resolve a primary term for a resolved sequence number. primary_term [" + result + "]"
166173 + " docId [" + docIdAndSeqNo .docId + "] seqNo [" + docIdAndSeqNo .seqNo + "]" ;
167174 return result ;
0 commit comments