Denis Mekhanikov created IGNITE-9196:
----------------------------------------

             Summary: SQL: Memory leak in MapNodeResults
                 Key: IGNITE-9196
                 URL: https://issues.apache.org/jira/browse/IGNITE-9196
             Project: Ignite
          Issue Type: Bug
          Components: sql
    Affects Versions: 2.6
            Reporter: Denis Mekhanikov


When size of a SQL query result set is a multiple of {{Query#pageSize}}, then 
{{MapQueryResult}} is never closed and removed from {{MapNodeResults#res}} 
collection.

The following code leads to OOME when run with 1Gb heap:
{code:java}
public class MemLeakRepro {
    public static void main(String[] args) {
        Ignition.start(getConfiguration("server"));

        try (Ignite client = 
Ignition.start(getConfiguration("client").setClientMode(true))) {
            IgniteCache<Integer, Person> cache = startPeopleCache(client);

            int pages = 10;
            int pageSize = 1024;

            for (int i = 0; i < pages * pageSize; i++) {
                Person p = new Person("Person #" + i, 25);
                cache.put(i, p);
            }

            for (int i = 0; i < 1_000_000; i++) {
                if (i % 1000 == 0)
                    System.out.println("Select iteration #" + i);

                Query<List<?>> qry = new SqlFieldsQuery("select * from people");
                qry.setPageSize(pageSize);
                QueryCursor<List<?>> cursor = cache.query(qry);
                cursor.getAll();
                cursor.close();
            }
        }
    }

    private static IgniteConfiguration getConfiguration(String instanceName) {
        IgniteConfiguration igniteCfg = new IgniteConfiguration();
        igniteCfg.setIgniteInstanceName(instanceName);

        TcpDiscoverySpi discoSpi = new TcpDiscoverySpi();
        discoSpi.setIpFinder(new TcpDiscoveryVmIpFinder(true));

        return igniteCfg;
    }

    private static IgniteCache<Integer, Person> startPeopleCache(Ignite node) {
        CacheConfiguration<Integer, Person> cacheCfg = new 
CacheConfiguration<>("cache");

        QueryEntity qe = new QueryEntity(Integer.class, Person.class);
        qe.setTableName("people");
        cacheCfg.setQueryEntities(Collections.singleton(qe));

        cacheCfg.setSqlSchema("PUBLIC");

        return node.getOrCreateCache(cacheCfg);
    }

    public static class Person {
        @QuerySqlField
        private String name;
        @QuerySqlField
        private int age;

        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
    }
}
{code}
 

At the same time it works perfectly fine, when there are, for example, {{pages 
* (pageSize + 1)}} records in cache instead.

The reason for it is that {{MapQueryResult#fetchNextPage(...)}} method doesn't 
return true, when the result set size is a multiple of the page size.



--
This message was sent by Atlassian JIRA
(v7.6.3#76005)

Reply via email to