Uploaded image for project: 'Infinispan'
  1. Infinispan
  2. ISPN-1800

indexes are added instead of updated after cache restart

    XMLWordPrintable

Details

    • Hide

      Scenario: put data (K1/V1) into the cache with persistence and indexing enabled - after cache restart put the same data under same key (K1,V1) to the cache - new (same) indexes are added instead of update therefore if data are queried after cache restart for K1 the query contains 2 results instead of one. There is different behaviour of the bug in 5.0.1 and 5.1.0:

      • in 5.0.1 the bug is present always regardless whether the put is done in or outside transaction
      • in 5.1.0 only in case there is transaction manager defined or batching enabled

      UT:

      package org.y4n.jlibs.jboss.ifspn5.bugs;

      import org.apache.commons.logging.Log;
      import org.apache.commons.logging.LogFactory;
      import org.apache.lucene.index.Term;
      import org.apache.lucene.search.BooleanClause;
      import org.apache.lucene.search.BooleanQuery;
      import org.apache.lucene.search.Query;
      import org.apache.lucene.search.TermQuery;
      import org.hibernate.search.annotations.Field;
      import org.hibernate.search.annotations.Indexed;
      import org.hibernate.search.annotations.ProvidedId;
      import org.hibernate.search.annotations.Store;
      import org.infinispan.Cache;
      import org.infinispan.manager.DefaultCacheManager;
      import org.infinispan.manager.EmbeddedCacheManager;
      import org.infinispan.query.CacheQuery;
      import org.infinispan.query.Search;
      import org.infinispan.query.SearchManager;
      import org.testng.annotations.BeforeMethod;
      import org.testng.annotations.Test;
      import java.io.File;
      import java.io.IOException;
      import java.io.Serializable;
      import java.util.List;
      import static org.testng.Assert.assertEquals;

      public class InconsistentIndexesAfterRestart {

      private static Log log = LogFactory.getLog(InconsistentIndexesAfterRestart.class);

      @Test
      public void testPutSearchablePersistent() throws Exception

      { Cache c = getSearchablePersistentCache(); // c.getAdvancedCache().getTransactionManager().begin(); c.put("key1", new SEntity(1, "name1", "surname1")); // c.getAdvancedCache().getTransactionManager().commit(); assertEquals(searchByName("name1", c).size(), 1, "should be 1"); c.getCacheManager().stop(); c.stop(); Thread.sleep(5000); c = getSearchablePersistentCache(); // c.getAdvancedCache().getTransactionManager().begin(); // if in sequence get, put (non tx) - there is no idx problem // c.get("key1"); c.put("key1", new SEntity(1, "name1", "surname1")); // c.getAdvancedCache().getTransactionManager().commit(); assertEquals(searchByName("name1", c).size(), 1, "should be again 1"); c.getCacheManager().stop(); c.stop(); }

      @BeforeMethod
      public void init()

      { deleteDir(new File("/tmp/ifspn5tests/")); }

      private Cache getSearchablePersistentCache() throws Exception

      { EmbeddedCacheManager manager = new DefaultCacheManager("searchable_caches.xml"); manager.start(); Cache c = manager.getCache("searchable-persistent"); c.start(); return c; }

      private List searchByName(String name, Cache c)

      { SearchManager sm = Search.getSearchManager(c); CacheQuery q = sm.getQuery(SEntity.searchByName(name), SEntity.class); List l = q.list(); return q.list(); }

      private static boolean deleteDir(File dir)

      { log.info("Deleting dir recursively: " + dir); return deleteDirRecursively(dir); }

      private static boolean deleteDirRecursively(File dir) {
      boolean success = true;
      if (dir.exists()) {
      if (dir.isDirectory()) {
      String[] children = dir.list();
      for (String aChildren : children)

      { success = deleteDirRecursively(new File(dir, aChildren)); }

      } else {
      success = dir.delete();
      if (!success)

      { log.error("Can't delete file: " + dir.getAbsolutePath()); }

      }
      } else

      { log.debug("Directory doesn't exist: " + dir.getName()); }

      return success;
      }

      @ProvidedId
      @Indexed
      public static class SEntity implements Serializable {

      public static final String IDX_NAME = "name";

      public static final String IDX_SURNAME = "surname";

      private final long id;

      @Field(store = Store.YES)
      private final String name;

      @Field (store = Store.YES)
      private final String surname;

      public SEntity(long id, String name, String surname)

      { this.id = id; this.name = name; this.surname = surname; }

      public long getId()

      { return id; }

      public String getName()

      { return name; }

      public String getSurname()

      { return surname; }

      @Override
      public String toString() {
      return "SEntity

      {" + "id=" + id + ", name='" + name + '\'' + ", surname='" + surname + '\'' + '}

      ';
      }

      public static Query searchByName(String name)

      { BooleanQuery query = new BooleanQuery(); query.add(new TermQuery( new Term(SEntity.IDX_NAME, name.toLowerCase())), BooleanClause.Occur.MUST); return query; }

      }

      }

      XML config:

      <?xml version="1.0" encoding="UTF-8"?>

      <infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="urn:infinispan:config:5.1 http://www.infinispan.org/schemas/infinispan-config-5.1.xsd"
      xmlns="urn:infinispan:config:5.1">

      <default>
      <indexing enabled="true" indexLocalOnly="true">
      <properties>
      <property name="hibernate.search.default.directory_provider" value="filesystem" />
      <property name="hibernate.search.default.indexBase" value="/tmp/ifspn5tests/idx" />
      </properties>
      </indexing>
      <!-- idx problem if enabled in 5.1.x (not in 5.0.1) without transactions -->
      <invocationBatching enabled="true"/>
      </default>

      <namedCache name="searchable-persistent">
      <loaders passivation="false">
      <loader class="org.infinispan.loaders.jdbm.JdbmCacheStore"
      fetchPersistentState="true"
      ignoreModifications="false"
      purgeOnStartup="false">
      <properties>
      <property name="location" value="/tmp/ifspn5tests/"/>
      </properties>
      <async enabled="false"/>
      </loader>
      </loaders>
      </namedCache>

      </infinispan>

      Show
      Scenario: put data (K1/V1) into the cache with persistence and indexing enabled - after cache restart put the same data under same key (K1,V1) to the cache - new (same) indexes are added instead of update therefore if data are queried after cache restart for K1 the query contains 2 results instead of one. There is different behaviour of the bug in 5.0.1 and 5.1.0: in 5.0.1 the bug is present always regardless whether the put is done in or outside transaction in 5.1.0 only in case there is transaction manager defined or batching enabled UT: package org.y4n.jlibs.jboss.ifspn5.bugs; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.TermQuery; import org.hibernate.search.annotations.Field; import org.hibernate.search.annotations.Indexed; import org.hibernate.search.annotations.ProvidedId; import org.hibernate.search.annotations.Store; import org.infinispan.Cache; import org.infinispan.manager.DefaultCacheManager; import org.infinispan.manager.EmbeddedCacheManager; import org.infinispan.query.CacheQuery; import org.infinispan.query.Search; import org.infinispan.query.SearchManager; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.util.List; import static org.testng.Assert.assertEquals; public class InconsistentIndexesAfterRestart { private static Log log = LogFactory.getLog(InconsistentIndexesAfterRestart.class); @Test public void testPutSearchablePersistent() throws Exception { Cache c = getSearchablePersistentCache(); // c.getAdvancedCache().getTransactionManager().begin(); c.put("key1", new SEntity(1, "name1", "surname1")); // c.getAdvancedCache().getTransactionManager().commit(); assertEquals(searchByName("name1", c).size(), 1, "should be 1"); c.getCacheManager().stop(); c.stop(); Thread.sleep(5000); c = getSearchablePersistentCache(); // c.getAdvancedCache().getTransactionManager().begin(); // if in sequence get, put (non tx) - there is no idx problem // c.get("key1"); c.put("key1", new SEntity(1, "name1", "surname1")); // c.getAdvancedCache().getTransactionManager().commit(); assertEquals(searchByName("name1", c).size(), 1, "should be again 1"); c.getCacheManager().stop(); c.stop(); } @BeforeMethod public void init() { deleteDir(new File("/tmp/ifspn5tests/")); } private Cache getSearchablePersistentCache() throws Exception { EmbeddedCacheManager manager = new DefaultCacheManager("searchable_caches.xml"); manager.start(); Cache c = manager.getCache("searchable-persistent"); c.start(); return c; } private List searchByName(String name, Cache c) { SearchManager sm = Search.getSearchManager(c); CacheQuery q = sm.getQuery(SEntity.searchByName(name), SEntity.class); List l = q.list(); return q.list(); } private static boolean deleteDir(File dir) { log.info("Deleting dir recursively: " + dir); return deleteDirRecursively(dir); } private static boolean deleteDirRecursively(File dir) { boolean success = true; if (dir.exists()) { if (dir.isDirectory()) { String[] children = dir.list(); for (String aChildren : children) { success = deleteDirRecursively(new File(dir, aChildren)); } } else { success = dir.delete(); if (!success) { log.error("Can't delete file: " + dir.getAbsolutePath()); } } } else { log.debug("Directory doesn't exist: " + dir.getName()); } return success; } @ProvidedId @Indexed public static class SEntity implements Serializable { public static final String IDX_NAME = "name"; public static final String IDX_SURNAME = "surname"; private final long id; @Field(store = Store.YES) private final String name; @Field (store = Store.YES) private final String surname; public SEntity(long id, String name, String surname) { this.id = id; this.name = name; this.surname = surname; } public long getId() { return id; } public String getName() { return name; } public String getSurname() { return surname; } @Override public String toString() { return "SEntity {" + "id=" + id + ", name='" + name + '\'' + ", surname='" + surname + '\'' + '} '; } public static Query searchByName(String name) { BooleanQuery query = new BooleanQuery(); query.add(new TermQuery( new Term(SEntity.IDX_NAME, name.toLowerCase())), BooleanClause.Occur.MUST); return query; } } } XML config: <?xml version="1.0" encoding="UTF-8"?> <infinispan xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:infinispan:config:5.1 http://www.infinispan.org/schemas/infinispan-config-5.1.xsd " xmlns="urn:infinispan:config:5.1"> <default> <indexing enabled="true" indexLocalOnly="true"> <properties> <property name="hibernate.search.default.directory_provider" value="filesystem" /> <property name="hibernate.search.default.indexBase" value="/tmp/ifspn5tests/idx" /> </properties> </indexing> <!-- idx problem if enabled in 5.1.x (not in 5.0.1) without transactions --> <invocationBatching enabled="true"/> </default> <namedCache name="searchable-persistent"> <loaders passivation="false"> <loader class="org.infinispan.loaders.jdbm.JdbmCacheStore" fetchPersistentState="true" ignoreModifications="false" purgeOnStartup="false"> <properties> <property name="location" value="/tmp/ifspn5tests/"/> </properties> <async enabled="false"/> </loader> </loaders> </namedCache> </infinispan>
    • Workaround Exists
    • Hide

      Turn on cache warm-up using preload option: <loaders passivation="false" preload="true">

      Show
      Turn on cache warm-up using preload option: <loaders passivation="false" preload="true">
    • Medium

    Description

      Problem with index addition instead of update after cache restart therefore there may arise inconsistencies data vs. indexes

      Attachments

        Activity

          People

            sgrinove Sanne Grinovero
            jsl_jira Jan Slezak (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

              Created:
              Updated:
              Resolved: