Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
Forward map value extractors to HD indexes
This change fixes two issues: 1. The consistency issue: queryable entries returned by HD indexes were unaware of the map value extractors, so it was impossible to extract values provided by the extractors from the returned entries. 2. The performance issue: Extractors.empty is a pretty expensive call and it was performed for every returned entry. According to a slightly modified version of HDIndexPerfTest the throughput is about 2 times higher now. Fixes: hazelcast/hazelcast-enterprise#2109
- Loading branch information
Showing
2 changed files
with
95 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
93 changes: 93 additions & 0 deletions
93
hazelcast/src/test/java/com/hazelcast/map/impl/query/ExtractorsAndIndexesTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
package com.hazelcast.map.impl.query; | ||
|
||
import com.hazelcast.config.Config; | ||
import com.hazelcast.config.InMemoryFormat; | ||
import com.hazelcast.config.MapAttributeConfig; | ||
import com.hazelcast.config.MapIndexConfig; | ||
import com.hazelcast.core.HazelcastInstance; | ||
import com.hazelcast.core.IMap; | ||
import com.hazelcast.query.Predicate; | ||
import com.hazelcast.query.Predicates; | ||
import com.hazelcast.query.extractor.ValueCollector; | ||
import com.hazelcast.query.extractor.ValueExtractor; | ||
import com.hazelcast.spi.properties.GroupProperty; | ||
import com.hazelcast.test.HazelcastParallelParametersRunnerFactory; | ||
import com.hazelcast.test.HazelcastTestSupport; | ||
import com.hazelcast.test.annotation.ParallelTest; | ||
import com.hazelcast.test.annotation.QuickTest; | ||
import org.junit.Test; | ||
import org.junit.experimental.categories.Category; | ||
import org.junit.runner.RunWith; | ||
import org.junit.runners.Parameterized; | ||
|
||
import java.io.Serializable; | ||
import java.util.Collection; | ||
|
||
import static com.hazelcast.query.Predicates.equal; | ||
import static java.util.Arrays.asList; | ||
import static org.junit.Assert.assertEquals; | ||
|
||
@RunWith(Parameterized.class) | ||
@Parameterized.UseParametersRunnerFactory(HazelcastParallelParametersRunnerFactory.class) | ||
@Category({QuickTest.class, ParallelTest.class}) | ||
public class ExtractorsAndIndexesTest extends HazelcastTestSupport { | ||
|
||
@Parameterized.Parameters(name = "format:{0}") | ||
public static Collection<Object[]> parameters() { | ||
return asList(new Object[][]{{InMemoryFormat.OBJECT}, {InMemoryFormat.BINARY}}); | ||
} | ||
|
||
@Parameterized.Parameter | ||
public InMemoryFormat inMemoryFormat; | ||
|
||
@Test | ||
public void testExtractorsAreRespectedByEntriesReturnedFromIndexes() { | ||
String mapName = randomMapName(); | ||
|
||
Config config = new Config(); | ||
config.getMapConfig(mapName).setInMemoryFormat(inMemoryFormat).addMapIndexConfig(new MapIndexConfig("last", true)) | ||
.addMapAttributeConfig(new MapAttributeConfig("generated", Extractor.class.getName())); | ||
config.getNativeMemoryConfig().setEnabled(true); | ||
|
||
config.setProperty(GroupProperty.PARTITION_COUNT.getName(), "1"); | ||
HazelcastInstance instance = createHazelcastInstance(config); | ||
|
||
IMap<Integer, Person> map = instance.getMap(mapName); | ||
populateMap(map); | ||
|
||
// this predicate queries the index | ||
Predicate lastPredicate = equal("last", "last"); | ||
|
||
// this predicate is not indexed and acts on the entries returned from | ||
// the index which must support extractors otherwise this test will fail | ||
Predicate alwaysFirst = equal("generated", "first"); | ||
|
||
Predicate composed = Predicates.and(lastPredicate, alwaysFirst); | ||
|
||
Collection<Person> values = map.values(composed); | ||
assertEquals(100, values.size()); | ||
} | ||
|
||
public static class Person implements Serializable { | ||
public String first; | ||
public String last; | ||
} | ||
|
||
public static class Extractor extends ValueExtractor<Person, Void> { | ||
@SuppressWarnings("unchecked") | ||
@Override | ||
public void extract(Person person, Void aVoid, ValueCollector valueCollector) { | ||
valueCollector.addObject("first"); | ||
} | ||
} | ||
|
||
private void populateMap(IMap<Integer, Person> map) { | ||
for (int i = 0; i < 100; i++) { | ||
Person p = new Person(); | ||
p.first = "first" + i; | ||
p.last = "last"; | ||
map.put(i, p); | ||
} | ||
} | ||
|
||
} |