public synchronized void setRollingEnabled(boolean rollingEnabled) {
    if (this.rollingEnabled != rollingEnabled) {
      if (rollingEnabled) {
        rollingTypeahead.open();
        logger.info("rolling enabled");
      } else {
        rollingTypeahead.close();
        logger.info("rolling disabled");
      }
      this.rollingEnabled = rollingEnabled;

      try {
        flush();
      } catch (IOException e) {
        logger.error("failed to flush indexes", e);
      }
    }
  }
  /**
   * Update the underlying connectiosStore.
   *
   * @param oldElement - old element
   * @param newElement - new element
   * @throws Exception
   */
  protected void updateConnectionStore(E oldElement, E newElement) throws Exception {
    if (rollingEnabled && oldElement == null) {
      rollingTypeahead.offer(newElement);
    } else {
      long scn = newElement.getTimestamp();
      int elemId = newElement.getElementId();

      if (oldElement == null) {
        // Insert operation
        for (String term : newElement.getTerms()) {
          int len = Math.min(term.length(), maxKeyLength);
          for (int i = 1; i <= len; i++) {
            String source = term.substring(0, i);
            connectionsStore.addConnection(source, elemId, scn);
          }
        }
      } else if (newElement.getTimestamp() >= getHWMark()) {
        // Update operation
        Set<String> oldPrefixes = new HashSet<String>();
        Set<String> newPrefixes = new HashSet<String>();

        for (String term : oldElement.getTerms()) {
          int len = Math.min(term.length(), maxKeyLength);
          for (int i = 1; i <= len; i++) {
            String source = term.substring(0, i);
            oldPrefixes.add(source);
          }
        }

        for (String term : newElement.getTerms()) {
          int len = Math.min(term.length(), maxKeyLength);
          for (int i = 1; i <= len; i++) {
            String source = term.substring(0, i);
            newPrefixes.add(source);
          }
        }

        // Calculate intersection
        Set<String> commonPrefixes = new HashSet<String>();
        commonPrefixes.addAll(oldPrefixes);
        commonPrefixes.retainAll(newPrefixes);

        newPrefixes.removeAll(commonPrefixes);
        for (String source : newPrefixes) {
          connectionsStore.addConnection(source, elemId, scn);
        }

        oldPrefixes.removeAll(commonPrefixes);
        for (String source : oldPrefixes) {
          connectionsStore.removeConnection(source, elemId, scn);
        }
      } else {
        logger.info("ignored element: " + newElement);
      }
    }
  }
  @Override
  public synchronized void persist() throws IOException {
    // Calls are ordered
    if (rollingEnabled) {
      rollingTypeahead.drain();
    }

    elementStore.persist();
    connectionsStore.persist();
  }
  @Override
  public Collector<E> search(int uid, String[] terms, Collector<E> collector, long timeoutMillis) {
    if (terms == null || terms.length == 0) return collector;

    HitStats hitStats = new HitStats();
    hitStats.start();

    Selector<E> selector = getSelectorFactory().createSelector(terms);
    searchInternal(uid, terms, collector, selector, hitStats, timeoutMillis);

    if (rollingEnabled) {
      long timeout = Math.max(1, timeoutMillis - hitStats.tick());
      rollingTypeahead.search(uid, terms, collector, timeout, hitStats);
    }

    hitStats.stop();
    log(logger, uid, terms, hitStats);
    return collector;
  }