在没有查询索引的字段上的事务期间运行Gemfire查询

时间:2016-09-30 10:55:40

标签: gemfire geode

我们在gemfire 客户端中的GF交易期间查询区域中的字段时会看到以下异常。

java.lang.ClassCastException: com.gemstone.gemfire.internal.cache.EntrySnapshot cannot be cast to com.gemstone.gemfire.internal.cache.LocalRegion$NonTXEntry

at com.gemstone.gemfire.internal.cache.EntriesSet$EntriesIterator.moveNext(EntriesSet.java:183) 
at com.gemstone.gemfire.internal.cache.EntriesSet$EntriesIterator.<init>(EntriesSet.java:121) 
at com.gemstone.gemfire.internal.cache.EntriesSet.iterator(EntriesSet.java:85) 
at com.gemstone.gemfire.cache.query.internal.ResultsCollectionWrapper.iterator(ResultsCollectionWrapper.java:181) 
at com.gemstone.gemfire.cache.query.internal.QRegion.iterator(QRegion.java:225) 
at com.gemstone.gemfire.cache.query.internal.CompiledSelect.doNestedIterations(CompiledSelect.java:712) 
at com.gemstone.gemfire.cache.query.internal.CompiledSelect.doIterationEvaluate(CompiledSelect.java:577) 
at com.gemstone.gemfire.cache.query.internal.CompiledSelect.evaluate(CompiledSelect.java:413) 
at com.gemstone.gemfire.cache.query.internal.DefaultQuery.executeUsingContext(DefaultQuery.java:529) 
at com.gemstone.gemfire.cache.query.internal.DefaultQuery.execute(DefaultQuery.java:365)

根据我们的反复试验,只有在符合以下条件时才会发生

  1. 交易 正在运行: 即调用gemfireCache.getCacheTransactionManager().begin()然后执行查询

  2. 不为查询/字段创建功能索引: 即,在init

  3. 期间未在特定字段上调用QueryService.createIndex(String, String, String)

    3。 where条件在区域数据中有字段可以为null : 即如果运行"SELECT * FROM /REGIONNAME WHERE fieldName = $1",如果fieldName在某些条目中为空,则抛出上述异常,否则,它就没事了。

    我们使用从QueryService.newQuery("SELECT * FROM /REGIONNAME WHERE fieldName = $1")获取的编译查询。如果我没有错,则查询服务是本地的,不在服务器上运行查询。

    我们正在使用Gemfire 8.2.1

    如果您需要更多信息,请在下方发表评论。

    ---更新05/12/2016 ---

    最后花些时间整理一个简单的测试用例来说明问题:

    我使用JUnit启动流程,这只是个人习惯。第一个测试用例在端口40001上启动具有共址定位器的服务器

    第二个测试用例启动客户端进程并在事务中运行没有索引的查询。

    public class GemfireQueryInTXTest {
    
    @Test
    public void startServer() throws Exception {
        Properties props = new Properties();
        System.setProperty("gemfirePropertyFile", "query_in_tx/gfserver-query-in-tx.properties");
        String file = DistributedSystem.getPropertyFileURL().getFile();
        props.load(new FileReader(file));
    
        Cache cache = new CacheFactory(props).create();
        RegionFactory<String, ValueEntry> factory = cache
                .<String, ValueEntry>createRegionFactory("REPLICATE")
                .setKeyConstraint(String.class)
                .setValueConstraint(ValueEntry.class);
    
        Region<String, ValueEntry> valueEntryRegion = factory.create("VALUEENTRY");
    
        valueEntryRegion.put("first", new ValueEntry("firstEntry", "NotNull"));
        valueEntryRegion.put("second", new ValueEntry("secondEntry", null));
    
        CacheServer server = cache.addCacheServer();
        server.setPort(40000);
    
        server.start();
    
        Thread.sleep(1000000L);
    }
    
    @Test
    public void testRunningQueryDuringTransactionOnNullableField() throws Exception {
        Properties props = new Properties();
        System.setProperty("gemfirePropertyFile", "query_in_tx/gemfire-query-in-tx.properties");
        String file = DistributedSystem.getPropertyFileURL().getFile();
        props.load(new FileReader(file));
    
        ClientCache cache = new ClientCacheFactory(props).create();
        ClientRegionFactory<String, ValueEntry> factory = cache
                .<String, ValueEntry>createClientRegionFactory("DEFAULT")
                .setKeyConstraint(String.class)
                .setValueConstraint(ValueEntry.class);
    
        Region<String, ValueEntry> valueEntryRegion = factory.create("VALUEENTRY");
        valueEntryRegion.registerInterest(".*", InterestResultPolicy.KEYS_VALUES);
    
        CacheTransactionManager cacheTransactionManager = cache.getCacheTransactionManager();
    
        QueryService localQueryService = cache.getLocalQueryService();
        Query query = localQueryService.newQuery("SELECT * from /VALUEENTRY WHERE nullable = $1");
        // No Exception will be thrown if create index for the field (uncomment below);
        // localQueryService.createIndex("IndexName", "nullable", "/VALUEENTRY");
    
        // ... Or run without transaction (comment below tx opening and closing)
        cacheTransactionManager.begin();
        System.out.println("Before Query Executed");
        query.execute(new Object[]{"1"});
        System.out.println("After Query Executed");
        cacheTransactionManager.commit();
    }
    }
    

    域对象:ValueEntry.java

    public class ValueEntry implements DataSerializable {
    private String notNull;
    private String nullable;
    
    public ValueEntry() {
    }
    
    public ValueEntry(String notNull, String nullable) {
        this.notNull = notNull;
        this.nullable = nullable;
    }
    
    public String getNotNull() {
        return notNull;
    }
    
    public String getNullable() {
        return nullable;
    }
    
    @Override
    public void toData(DataOutput dataOutput) throws IOException {
        DataSerializer.writeString(notNull, dataOutput);
        DataSerializer.writeString(nullable, dataOutput);
    }
    
    @Override
    public void fromData(DataInput dataInput) throws IOException, ClassNotFoundException {
        this.notNull = DataSerializer.readString(dataInput);
        this.nullable = DataSerializer.readString(dataInput);
    }
    }
    

    Server Proerties和xml:

    cache-xml-file=query_in_tx\\cache-server.xml
    start-locator=40001
    locators=localhost[40001]
    log-file=logs\\server.log
    log-level=config
    mcast-port=0
    name=server
    
    <cache>
    <serialization-registration>
        <instantiator id="999">
            <class-name>com.testing.gemfire.domain.ValueEntry</class-name>
        </instantiator>
    </serialization-registration>
    </cache>
    

    Client Proerties和xml:

    cache-xml-file=query_in_tx\\cache-query-in-tx.xml
    log-disk-space-limit=100
    log-file-size-limit=20
    log-file=logs\\cache.log
    log-level=config
    mcast-port=0
    name=gemfire-playground
    
    <client-cache>
        <pool name="Zero" subscription-enabled="true" read-timeout="3000"
              retry-attempts="5" socket-buffer-size="65536">
            <locator host="localhost" port="40001" />
        </pool>
    
        <region-attributes id="DEFAULT" refid="CACHING_PROXY" pool-name="Zero"/>
    </client-cache>
    

1 个答案:

答案 0 :(得分:0)

与Pivotal团队沟通后,结果证明这是Gemfire客户端中的一个错误。正如问题描述中所提到的,创建索引将阻止抛出此异常。

如果在将来的版本中修复它,我将再次更新。