Skip to content

Commit

Permalink
IGNITE-20943 Fix deserializing cache entries for IndexQuery on server (
Browse files Browse the repository at this point in the history
  • Loading branch information
timoninmaxim committed Jul 25, 2024
1 parent 4c38b2f commit fb80a12
Show file tree
Hide file tree
Showing 3 changed files with 261 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,8 @@ private IndexQueryCriterion readInCriterion(BinaryRawReaderEx reader) {
* {@inheritDoc}
*/
@Override public ClientResponse process(ClientConnectionContext ctx) {
IgniteCache<Object, Object> cache = !isKeepBinary() ? rawCache(ctx) : cache(ctx);
IgniteCache<Object, Object> cache = qry.getFilter() != null && !isKeepBinary() ?
rawCache(ctx) : cache(ctx);

if (qry.getPartition() != null)
updateAffinityMetrics(ctx, qry.getPartition());
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.apache.ignite.internal.ducktest.tests.thin_client_query_test;

import java.util.LinkedHashMap;
import java.util.List;
import javax.cache.Cache;
import com.fasterxml.jackson.databind.JsonNode;
import org.apache.ignite.binary.BinaryObject;
import org.apache.ignite.cache.QueryEntity;
import org.apache.ignite.cache.QueryIndex;
import org.apache.ignite.cache.query.IndexQuery;
import org.apache.ignite.cache.query.ScanQuery;
import org.apache.ignite.client.ClientCache;
import org.apache.ignite.client.ClientCacheConfiguration;
import org.apache.ignite.internal.ducktest.utils.IgniteAwareApplication;
import org.apache.ignite.internal.util.typedef.F;

/** Tests cache queries for thin client. */
public class ThinClientQueryTestApplication extends IgniteAwareApplication {
/** */
private static final int CNT = 100;

/** */
@Override protected void run(JsonNode jsonNode) throws Exception {
markInitialized();

QueryEntity qe = new QueryEntity(Integer.class, EntityValue.class)
.setValueType(EntityValue.class.getName())
.setFields(new LinkedHashMap<>(F.asMap("val", Integer.class.getName())))
.setIndexes(F.asList(new QueryIndex("val", false).setName("VAL_IDX")));

ClientCacheConfiguration clnCacheCfg = new ClientCacheConfiguration()
.setName("testCache")
.setQueryEntities(qe);

ClientCache<Integer, EntityValue> cache = client.createCache(clnCacheCfg);

for (int i = 0; i < CNT; i++)
cache.put(i, new EntityValue(i));

boolean filter = jsonNode.get("filter").asBoolean();

testIndexQuery(cache, filter);
testBinaryIndexQuery(cache, filter);
testScanQuery(cache, filter);
testBinaryScanQuery(cache, filter);

markFinished();
}

/** */
private void testIndexQuery(ClientCache<Integer, EntityValue> cache, boolean filter) {
IndexQuery<Integer, EntityValue> idxQry = new IndexQuery<>(EntityValue.class.getName(), "VAL_IDX");

if (filter)
idxQry.setFilter((k, v) -> v.val < CNT / 2);

List<Cache.Entry<Integer, EntityValue>> result = cache.query(idxQry).getAll();

int cnt = filter ? CNT / 2 : CNT;

assert result.size() == cnt;

for (int i = 0; i < cnt; i++) {
Cache.Entry<Integer, EntityValue> e = result.get(i);

assert e.getKey() == i;
assert e.getValue().val == i;
}
}

/** */
private void testBinaryIndexQuery(ClientCache<Integer, EntityValue> cache, boolean filter) {
IndexQuery<Integer, BinaryObject> idxQry = new IndexQuery<>(EntityValue.class.getName(), "VAL_IDX");

if (filter)
idxQry.setFilter((k, v) -> (int)v.field("val") < CNT / 2);

List<Cache.Entry<Integer, BinaryObject>> result = cache.withKeepBinary().query(idxQry).getAll();

int cnt = filter ? CNT / 2 : CNT;

assert result.size() == cnt;

for (int i = 0; i < cnt; i++) {
Cache.Entry<Integer, BinaryObject> e = result.get(i);

assert e.getKey() == i;
assert (int)e.getValue().field("val") == i;
}
}

/** */
private void testScanQuery(ClientCache<Integer, EntityValue> cache, boolean filter) {
ScanQuery<Integer, EntityValue> scanQry = new ScanQuery<>();

if (filter)
scanQry.setFilter((k, v) -> v.val < CNT / 2);

List<Cache.Entry<Integer, EntityValue>> result = cache.query(scanQry).getAll();

int cnt = filter ? CNT / 2 : CNT;

assert result.size() == cnt;

for (int i = 0; i < cnt; i++) {
Cache.Entry<Integer, EntityValue> e = result.get(i);

assert e.getKey() == e.getValue().val;
}
}

/** */
private void testBinaryScanQuery(ClientCache<Integer, EntityValue> cache, boolean filter) {
ScanQuery<Integer, BinaryObject> scanQry = new ScanQuery<>();

if (filter)
scanQry.setFilter((k, v) -> (int)v.field("val") < CNT / 2);

List<Cache.Entry<Integer, BinaryObject>> result = cache.withKeepBinary().query(scanQry).getAll();

int cnt = filter ? CNT / 2 : CNT;

assert result.size() == cnt;

for (int i = 0; i < cnt; i++) {
Cache.Entry<Integer, BinaryObject> e = result.get(i);

assert e.getKey() == e.getValue().field("val");
}
}

/** */
private static class EntityValue {
/** */
private final int val;

/** */
public EntityValue(int val) {
this.val = val;
}

/** */
public String toString() {
return "EntityValue [val=" + val + "]";
}
}
}
95 changes: 95 additions & 0 deletions modules/ducktests/tests/ignitetest/tests/thin_client_query_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
This module contains client queries tests.
"""
from ducktape.mark import matrix

from ignitetest.services.ignite import IgniteService
from ignitetest.services.ignite_app import IgniteApplicationService
from ignitetest.services.utils.ignite_configuration import IgniteConfiguration, IgniteThinClientConfiguration
from ignitetest.services.utils.ignite_spec import IgniteNodeSpec
from ignitetest.services.utils.ssl.client_connector_configuration import ClientConnectorConfiguration
from ignitetest.utils import cluster, ignite_versions
from ignitetest.utils.ignite_test import IgniteTest
from ignitetest.utils.version import DEV_BRANCH, IgniteVersion


class ThinClientQueryTest(IgniteTest):
"""
cluster - cluster size.
JAVA_CLIENT_CLASS_NAME - running classname.
to use with ssl enabled:
export GLOBALS='{"ssl":{"enabled":true}}' .
"""
@cluster(num_nodes=3)
@ignite_versions(str(DEV_BRANCH), version_prefix="server_version")
@matrix(filter=[False, True])
def test_thin_client_index_query(self, server_version, filter):
"""
Thin client IndexQuery test.
:param server_version Ignite node version.
:param filter Whether to use filter for queries.
"""

server_config = IgniteConfiguration(version=IgniteVersion(server_version),
client_connector_configuration=ClientConnectorConfiguration())

ignite = IgniteService(self.test_context, server_config, 2)

if not filter:
ignite.spec = IgniteNodeSpecExcludeDucktests(service=ignite)

addresses = [ignite.nodes[0].account.hostname + ":" + str(server_config.client_connector_configuration.port)]

cls = "org.apache.ignite.internal.ducktest.tests.thin_client_query_test.ThinClientQueryTestApplication"

thin_clients = IgniteApplicationService(self.test_context,
IgniteThinClientConfiguration(
addresses=addresses,
version=IgniteVersion(str(DEV_BRANCH))),
java_class_name=cls,
num_nodes=1,
params={"filter": filter})

ignite.start()
thin_clients.run()
ignite.stop()


class IgniteNodeSpecExcludeDucktests(IgniteNodeSpec):
"""
Ignite node specification that excludes module 'ducktests' from classpath.
"""
def modules(self):
"""
Exclude module from preparing USER_LIBS environment variable.
"""
modules = super().modules()

modules.remove("ducktests")

return modules

def envs(self):
"""
Skip the module target directory while building classpath.
"""
envs = super().envs()

envs["EXCLUDE_MODULES"] = "ducktests"

return envs

0 comments on commit fb80a12

Please sign in to comment.