Skip to content

Commit a9a1fec

Browse files
authored
IGNITE-26683 IndexQuery can't use an index until data population completes (#12412)
1 parent b92a02b commit a9a1fec

File tree

6 files changed

+515
-14
lines changed

6 files changed

+515
-14
lines changed

modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/IndexName.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
package org.apache.ignite.internal.cache.query.index;
1919

20+
import java.util.Objects;
2021
import org.jetbrains.annotations.Nullable;
2122

2223
/**
@@ -90,4 +91,20 @@ public String cacheName() {
9091
@Override public String toString() {
9192
return fullName();
9293
}
94+
95+
/** */
96+
@Override public boolean equals(Object o) {
97+
if (!(o instanceof IndexName))
98+
return false;
99+
100+
IndexName name = (IndexName)o;
101+
102+
return Objects.equals(schemaName, name.schemaName) && Objects.equals(tableName, name.tableName)
103+
&& Objects.equals(cacheName, name.cacheName) && Objects.equals(idxName, name.idxName);
104+
}
105+
106+
/** */
107+
@Override public int hashCode() {
108+
return Objects.hash(schemaName, tableName, cacheName, idxName);
109+
}
93110
}

modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/IndexProcessor.java

Lines changed: 90 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,10 @@
2121
import java.util.Collection;
2222
import java.util.Collections;
2323
import java.util.HashMap;
24+
import java.util.HashSet;
2425
import java.util.List;
2526
import java.util.Map;
27+
import java.util.Set;
2628
import java.util.concurrent.locks.ReentrantReadWriteLock;
2729
import org.apache.ignite.IgniteCheckedException;
2830
import org.apache.ignite.IgniteLogger;
@@ -115,6 +117,9 @@ public static void registerIO() {
115117
/** Exclusive lock for DDL operations. */
116118
private final ReentrantReadWriteLock ddlLock = new ReentrantReadWriteLock();
117119

120+
/** Set of index names currently in initial population (null if none). */
121+
private @Nullable Set<IndexName> fillingIdxs;
122+
118123
/**
119124
* @param ctx Kernal context.
120125
*/
@@ -211,15 +216,45 @@ public Index createIndexDynamically(
211216
IndexDefinition definition,
212217
SchemaIndexCacheVisitor cacheVisitor
213218
) {
214-
Index idx = createIndex(cctx, factory, definition);
219+
IndexFactory dynamicFactory = (gcctx, indexDefinition) -> {
220+
Index idx = factory.createIndex(gcctx, indexDefinition);
221+
222+
assert ddlLock.isWriteLockedByCurrentThread();
223+
224+
if (fillingIdxs == null)
225+
fillingIdxs = new HashSet<>();
226+
227+
fillingIdxs.add(indexDefinition.idxName());
228+
229+
return idx;
230+
};
231+
232+
try {
233+
Index idx = createIndex(cctx, dynamicFactory, definition);
215234

216-
// Populate index with cache rows.
217-
cacheVisitor.visit(row -> {
218-
if (idx.canHandle(row))
219-
idx.onUpdate(null, row, false);
220-
});
235+
// Populate index with cache rows.
236+
cacheVisitor.visit(row -> {
237+
if (idx.canHandle(row))
238+
idx.onUpdate(null, row, false);
239+
});
221240

222-
return idx;
241+
return idx;
242+
}
243+
finally {
244+
ddlLock.writeLock().lock();
245+
246+
try {
247+
if (fillingIdxs != null) {
248+
fillingIdxs.remove(definition.idxName());
249+
250+
if (fillingIdxs.isEmpty())
251+
fillingIdxs = null;
252+
}
253+
}
254+
finally {
255+
ddlLock.writeLock().unlock();
256+
}
257+
}
223258
}
224259

225260
/**
@@ -272,8 +307,18 @@ public void removeIndex(IndexName idxName, boolean softDelete) {
272307

273308
Index idx = idxs.remove(idxName.fullName());
274309

275-
if (idx != null)
310+
if (idx != null) {
276311
idx.destroy(softDelete);
312+
313+
if (fillingIdxs != null) {
314+
fillingIdxs.remove(idxName);
315+
316+
if (fillingIdxs.isEmpty())
317+
fillingIdxs = null;
318+
}
319+
320+
}
321+
277322
}
278323
finally {
279324
ddlLock.writeLock().unlock();
@@ -371,16 +416,33 @@ public IndexesRebuildTask idxRebuild() {
371416
* @return Collection of indexes for specified cache.
372417
*/
373418
public Collection<Index> indexes(String cacheName) {
419+
return indexes(cacheName, false);
420+
}
421+
422+
/**
423+
* Returns collection of indexes for specified cache.
424+
*
425+
* @param cacheName Cache name.
426+
* @param skipFilling If {@code true}, indexes that are currently being initially populated are excluded
427+
* from the result; if {@code false}, all known indexes for the cache are returned.
428+
* @return Collection of indexes for specified cache.
429+
*/
430+
431+
public Collection<Index> indexes(String cacheName, boolean skipFilling) {
374432
ddlLock.readLock().lock();
375433

376434
try {
377-
Map<String, Index> idxs = cacheToIdx.get(cacheName);
435+
Map<String, Index> idxMap = cacheToIdx.get(cacheName);
378436

379-
if (idxs == null)
437+
if (idxMap == null)
380438
return Collections.emptyList();
381439

382-
return idxs.values();
440+
List<Index> idxs = new ArrayList<>(idxMap.values());
383441

442+
if (skipFilling && fillingIdxs != null)
443+
idxs.removeIf(idx -> fillingIdxs.contains(idx.indexDefinition().idxName()));
444+
445+
return idxs;
384446
}
385447
finally {
386448
ddlLock.readLock().unlock();
@@ -394,9 +456,26 @@ public Collection<Index> indexes(String cacheName) {
394456
* @return Index for specified index name or {@code null} if not found.
395457
*/
396458
public @Nullable Index index(IndexName idxName) {
459+
return index(idxName, false);
460+
}
461+
462+
/**
463+
* Returns index for specified name.
464+
*
465+
* @param idxName Index name.
466+
* @param skipFilling If {@code true}, returns {@code null} when the index is currently being initially
467+
* populated and therefore should be skipped; if {@code false}, returns the index if present.
468+
* @return Index for specified index name or {@code null} if not found (or skipped due to population when
469+
* {@code skipFilling} is {@code true}).
470+
*/
471+
472+
public @Nullable Index index(IndexName idxName, boolean skipFilling) {
397473
ddlLock.readLock().lock();
398474

399475
try {
476+
if (skipFilling && fillingIdxs != null && fillingIdxs.contains(idxName))
477+
return null;
478+
400479
Map<String, Index> idxs = cacheToIdx.get(idxName.cacheName());
401480

402481
if (idxs == null)

modules/core/src/main/java/org/apache/ignite/internal/cache/query/index/IndexQueryProcessor.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,14 +217,14 @@ private SortedSegmentedIndex findSortedIndex(GridCacheContext<?, ?> cctx, IndexQ
217217
* @throws IgniteCheckedException If index not found or specified index doesn't match query criteria.
218218
*/
219219
private SortedSegmentedIndex indexByName(IndexName idxName, final Map<String, String> criteriaFlds) throws IgniteCheckedException {
220-
SortedSegmentedIndex idx = assertSortedIndex(idxProc.index(idxName));
220+
SortedSegmentedIndex idx = assertSortedIndex(idxProc.index(idxName, true));
221221

222222
if (idx == null && !QueryUtils.PRIMARY_KEY_INDEX.equals(idxName.idxName())) {
223223
String normIdxName = QueryUtils.normalizeObjectName(idxName.idxName(), false);
224224

225225
idxName = new IndexName(idxName.cacheName(), idxName.schemaName(), idxName.tableName(), normIdxName);
226226

227-
idx = assertSortedIndex(idxProc.index(idxName));
227+
idx = assertSortedIndex(idxProc.index(idxName, true));
228228
}
229229

230230
if (idx == null)
@@ -245,7 +245,7 @@ private SortedSegmentedIndex indexByCriteria(
245245
final Map<String, String> criteriaFlds,
246246
String tableName
247247
) throws IgniteCheckedException {
248-
Collection<Index> idxs = idxProc.indexes(cctx.name());
248+
Collection<Index> idxs = idxProc.indexes(cctx.name(), true);
249249

250250
for (Index idx: idxs) {
251251
SortedSegmentedIndex sortedIdx = assertSortedIndex(idx);

0 commit comments

Comments
 (0)