All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.sonar.batch.index.Cache Maven / Gradle / Ivy

There is a newer version: 25.1.0.102122
Show newest version
/*
 * SonarQube
 * Copyright (C) 2009-2016 SonarSource SA
 * mailto:contact AT sonarsource DOT com
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.sonar.batch.index;

import com.google.common.collect.Sets;
import com.persistit.Exchange;
import com.persistit.Key;
import com.persistit.KeyFilter;
import com.persistit.exception.PersistitException;
import org.apache.commons.lang.builder.ToStringBuilder;

import javax.annotation.CheckForNull;

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;

/**
 * 

* This cache is not thread-safe, due to direct usage of {@link com.persistit.Exchange} *

*/ public class Cache { private final String name; private final Exchange exchange; Cache(String name, Exchange exchange) { this.name = name; this.exchange = exchange; } public Cache put(Object key, V value) { resetKey(key); return doPut(value); } public Cache put(Object firstKey, Object secondKey, V value) { resetKey(firstKey, secondKey); return doPut(value); } public Cache put(Object firstKey, Object secondKey, Object thirdKey, V value) { resetKey(firstKey, secondKey, thirdKey); return doPut(value); } public Cache put(Object[] key, V value) { resetKey(key); return doPut(value); } private Cache doPut(V value) { try { exchange.getValue().put(value); exchange.store(); return this; } catch (Exception e) { throw new IllegalStateException("Fail to put element in the cache " + name, e); } } /** * Returns the value object associated with keys, or null if not found. */ public V get(Object key) { resetKey(key); return doGet(); } /** * Returns the value object associated with keys, or null if not found. */ @CheckForNull public V get(Object firstKey, Object secondKey) { resetKey(firstKey, secondKey); return doGet(); } /** * Returns the value object associated with keys, or null if not found. */ @CheckForNull public V get(Object firstKey, Object secondKey, Object thirdKey) { resetKey(firstKey, secondKey, thirdKey); return doGet(); } /** * Returns the value object associated with keys, or null if not found. */ @CheckForNull public V get(Object[] key) { resetKey(key); return doGet(); } @SuppressWarnings("unchecked") @CheckForNull private V doGet() { try { exchange.fetch(); if (!exchange.getValue().isDefined()) { return null; } return (V) exchange.getValue().get(); } catch (Exception e) { // TODO add parameters to message throw new IllegalStateException("Fail to get element from cache " + name, e); } } public boolean containsKey(Object key) { resetKey(key); return doContainsKey(); } public boolean containsKey(Object firstKey, Object secondKey) { resetKey(firstKey, secondKey); return doContainsKey(); } public boolean containsKey(Object firstKey, Object secondKey, Object thirdKey) { resetKey(firstKey, secondKey, thirdKey); return doContainsKey(); } public boolean containsKey(Object[] key) { resetKey(key); return doContainsKey(); } private boolean doContainsKey() { try { exchange.fetch(); return exchange.isValueDefined(); } catch (Exception e) { // TODO add parameters to message throw new IllegalStateException("Fail to check if element is in cache " + name, e); } } public boolean remove(Object key) { resetKey(key); return doRemove(); } public boolean remove(Object firstKey, Object secondKey) { resetKey(firstKey, secondKey); return doRemove(); } public boolean remove(Object firstKey, Object secondKey, Object thirdKey) { resetKey(firstKey, secondKey, thirdKey); return doRemove(); } public boolean remove(Object[] key) { resetKey(key); return doRemove(); } private boolean doRemove() { try { return exchange.remove(); } catch (Exception e) { // TODO add parameters to message throw new IllegalStateException("Fail to get element from cache " + name, e); } } /** * Removes everything in the specified group. * * @param group The group name. */ public Cache clear(Object key) { resetKey(key); return doClear(); } public Cache clear(Object firstKey, Object secondKey) { resetKey(firstKey, secondKey); return doClear(); } public Cache clear(Object firstKey, Object secondKey, Object thirdKey) { resetKey(firstKey, secondKey, thirdKey); return doClear(); } public Cache clear(Object[] key) { resetKey(key); return doClear(); } private Cache doClear() { try { Key to = new Key(exchange.getKey()); to.append(Key.AFTER); exchange.removeKeyRange(exchange.getKey(), to); return this; } catch (Exception e) { throw new IllegalStateException("Fail to clear values from cache " + name, e); } } /** * Clears the default as well as all group caches. */ public void clear() { try { exchange.clear(); exchange.removeAll(); } catch (Exception e) { throw new IllegalStateException("Fail to clear cache", e); } } /** * Returns the set of cache keys associated with this group. * TODO implement a lazy-loading equivalent with Iterator/Iterable * * @param group The group. * @return The set of cache keys for this group. */ @SuppressWarnings("rawtypes") public Set keySet(Object key) { try { Set keys = Sets.newLinkedHashSet(); exchange.clear(); Exchange iteratorExchange = new Exchange(exchange); iteratorExchange.append(key); iteratorExchange.append(Key.BEFORE); while (iteratorExchange.next(false)) { keys.add(iteratorExchange.getKey().indexTo(-1).decode()); } return keys; } catch (Exception e) { throw new IllegalStateException("Fail to get keys from cache " + name, e); } } @SuppressWarnings("rawtypes") public Set keySet(Object firstKey, Object secondKey) { try { Set keys = Sets.newLinkedHashSet(); exchange.clear(); Exchange iteratorExchange = new Exchange(exchange); iteratorExchange.append(firstKey); iteratorExchange.append(secondKey); iteratorExchange.append(Key.BEFORE); while (iteratorExchange.next(false)) { keys.add(iteratorExchange.getKey().indexTo(-1).decode()); } return keys; } catch (Exception e) { throw new IllegalStateException("Fail to get keys from cache " + name, e); } } /** * Returns the set of keys associated with this cache. * * @return The set containing the keys for this cache. */ public Set keySet() { try { Set keys = Sets.newLinkedHashSet(); exchange.clear(); Exchange iteratorExchange = new Exchange(exchange); iteratorExchange.append(Key.BEFORE); while (iteratorExchange.next(false)) { keys.add(iteratorExchange.getKey().indexTo(-1).decode()); } return keys; } catch (Exception e) { throw new IllegalStateException("Fail to get keys from cache " + name, e); } } /** * Lazy-loading values for given keys */ public Iterable values(Object firstKey, Object secondKey) { return new ValueIterable<>(exchange, firstKey, secondKey); } /** * Lazy-loading values for a given key */ public Iterable values(Object firstKey) { return new ValueIterable<>(exchange, firstKey); } /** * Lazy-loading values */ public Iterable values() { return new ValueIterable<>(exchange); } public Iterable> entries() { return new EntryIterable<>(exchange); } public Iterable> entries(Object firstKey) { return new EntryIterable<>(exchange, firstKey); } private void resetKey(Object key) { exchange.clear(); exchange.append(key); } private void resetKey(Object first, Object second) { exchange.clear(); exchange.append(first).append(second); } private void resetKey(Object first, Object second, Object third) { exchange.clear(); exchange.append(first).append(second).append(third); } private void resetKey(Object[] keys) { exchange.clear(); for (Object o : keys) { exchange.append(o); } } // // LAZY ITERATORS AND ITERABLES // private static class ValueIterable implements Iterable { private final Exchange originExchange; private final Object[] keys; private ValueIterable(Exchange originExchange, Object... keys) { this.originExchange = originExchange; this.keys = keys; } @Override public Iterator iterator() { originExchange.clear(); KeyFilter filter = new KeyFilter(); for (Object key : keys) { originExchange.append(key); filter = filter.append(KeyFilter.simpleTerm(key)); } originExchange.append(Key.BEFORE); Exchange iteratorExchange = new Exchange(originExchange); return new ValueIterator<>(iteratorExchange, filter); } } private static class ValueIterator implements Iterator { private final Exchange exchange; private final KeyFilter keyFilter; private ValueIterator(Exchange exchange, KeyFilter keyFilter) { this.exchange = exchange; this.keyFilter = keyFilter; } @Override public boolean hasNext() { try { return exchange.hasNext(keyFilter); } catch (PersistitException e) { throw new IllegalStateException(e); } } @SuppressWarnings("unchecked") @Override public T next() { try { exchange.next(keyFilter); } catch (PersistitException e) { throw new IllegalStateException(e); } if (exchange.getValue().isDefined()) { return (T) exchange.getValue().get(); } throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException("Removing an item is not supported"); } } private static class EntryIterable implements Iterable> { private final Exchange originExchange; private final Object[] keys; private EntryIterable(Exchange originExchange, Object... keys) { this.originExchange = originExchange; this.keys = keys; } @Override public Iterator> iterator() { originExchange.clear(); KeyFilter filter = new KeyFilter(); for (Object key : keys) { originExchange.append(key); filter = filter.append(KeyFilter.simpleTerm(key)); } originExchange.append(Key.BEFORE); Exchange iteratorExchange = new Exchange(originExchange); return new EntryIterator<>(iteratorExchange, filter); } } private static class EntryIterator implements Iterator> { private final Exchange exchange; private final KeyFilter keyFilter; private EntryIterator(Exchange exchange, KeyFilter keyFilter) { this.exchange = exchange; this.keyFilter = keyFilter; } @Override public boolean hasNext() { try { return exchange.hasNext(keyFilter); } catch (PersistitException e) { throw new IllegalStateException(e); } } @SuppressWarnings("unchecked") @Override public Entry next() { try { exchange.next(keyFilter); } catch (PersistitException e) { throw new IllegalStateException(e); } if (exchange.getValue().isDefined()) { T value = (T) exchange.getValue().get(); Key key = exchange.getKey(); Object[] array = new Object[key.getDepth()]; for (int i = 0; i < key.getDepth(); i++) { array[i] = key.indexTo(i - key.getDepth()).decode(); } return new Entry<>(array, value); } throw new NoSuchElementException(); } @Override public void remove() { throw new UnsupportedOperationException("Removing an item is not supported"); } } public static class Entry { private final Object[] key; private final V value; Entry(Object[] key, V value) { this.key = key; this.value = value; } public Object[] key() { return key; } public V value() { return value; } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } } }