import org.sonar.core.platform.PluginRepository;
import org.sonar.core.util.DefaultHttpDownloader;
import org.sonar.core.util.UuidFactoryImpl;
-import org.sonar.scanner.index.CachesManager;
import org.sonar.scanner.platform.DefaultServer;
import org.sonar.scanner.repository.DefaultGlobalRepositoriesLoader;
import org.sonar.scanner.repository.GlobalRepositoriesLoader;
import org.sonar.scanner.repository.GlobalRepositoriesProvider;
+import org.sonar.scanner.storage.StoragesManager;
import org.sonar.scanner.task.TaskContainer;
public class GlobalContainer extends ComponentContainer {
new SonarQubeVersion(apiVersion),
SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER),
- CachesManager.class,
+ StoragesManager.class,
GlobalSettings.class,
new BatchWsClientProvider(),
DefaultServer.class,
+++ /dev/null
-/*
- * 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.scanner.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 java.util.Iterator;
-import java.util.NoSuchElementException;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import org.apache.commons.lang.builder.ToStringBuilder;
-
-/**
- * <p>
- * This cache is not thread-safe, due to direct usage of {@link com.persistit.Exchange}
- * </p>
- */
-public class Cache<V> {
-
- private final String name;
- private final Exchange exchange;
-
- Cache(String name, Exchange exchange) {
- this.name = name;
- this.exchange = exchange;
- }
-
- public Cache<V> put(Object key, V value) {
- resetKey(key);
- return doPut(value);
- }
-
- public Cache<V> put(Object firstKey, Object secondKey, V value) {
- resetKey(firstKey, secondKey);
- return doPut(value);
- }
-
- public Cache<V> put(Object firstKey, Object secondKey, Object thirdKey, V value) {
- resetKey(firstKey, secondKey, thirdKey);
- return doPut(value);
- }
-
- public Cache<V> put(Object[] key, V value) {
- resetKey(key);
- return doPut(value);
- }
-
- private Cache<V> doPut(V value) {
- try {
- exchange.getValue().put(value);
- exchange.store();
- return this;
- } catch (Exception e) {
- throw new IllegalStateException("Fail to put element in the storage '" + 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<V> clear(Object key) {
- resetKey(key);
- return doClear();
- }
-
- public Cache<V> clear(Object firstKey, Object secondKey) {
- resetKey(firstKey, secondKey);
- return doClear();
- }
-
- public Cache<V> clear(Object firstKey, Object secondKey, Object thirdKey) {
- resetKey(firstKey, secondKey, thirdKey);
- return doClear();
- }
-
- public Cache<V> clear(Object[] key) {
- resetKey(key);
- return doClear();
- }
-
- private Cache<V> 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<Object> 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<Object> 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<Object> keySet() {
- try {
- Set<Object> 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<V> values(Object firstKey, Object secondKey) {
- return new ValueIterable<>(exchange, firstKey, secondKey);
- }
-
- /**
- * Lazy-loading values for a given key
- */
- public Iterable<V> values(Object firstKey) {
- return new ValueIterable<>(exchange, firstKey);
- }
-
- /**
- * Lazy-loading values
- */
- public Iterable<V> values() {
- return new ValueIterable<>(exchange);
- }
-
- public Iterable<Entry<V>> entries() {
- return new EntryIterable<>(exchange);
- }
-
- public Iterable<Entry<V>> 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<T> implements Iterable<T> {
- private final Exchange originExchange;
- private final Object[] keys;
-
- private ValueIterable(Exchange originExchange, Object... keys) {
- this.originExchange = originExchange;
- this.keys = keys;
- }
-
- @Override
- public Iterator<T> 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<T> implements Iterator<T> {
- 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<T> implements Iterable<Entry<T>> {
- private final Exchange originExchange;
- private final Object[] keys;
-
- private EntryIterable(Exchange originExchange, Object... keys) {
- this.originExchange = originExchange;
- this.keys = keys;
- }
-
- @Override
- public Iterator<Entry<T>> 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<T> implements Iterator<Entry<T>> {
- 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<T> 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<V> {
- 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);
- }
- }
-
-}
+++ /dev/null
-/*
- * 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.scanner.index;
-
-import com.google.common.collect.Maps;
-
-import java.util.Map;
-import java.util.Map.Entry;
-
-import com.google.common.base.Preconditions;
-import com.persistit.Exchange;
-import com.persistit.Value;
-import com.persistit.encoding.CoderManager;
-import com.persistit.Persistit;
-import com.persistit.encoding.ValueCoder;
-import com.persistit.exception.PersistitException;
-import com.persistit.Volume;
-import org.picocontainer.Startable;
-import org.sonar.api.batch.ScannerSide;
-
-@ScannerSide
-public class Caches implements Startable {
- private final Map<String, Exchange> cacheMap = Maps.newHashMap();
- private Persistit persistit;
- private Volume volume;
-
- public Caches(CachesManager caches) {
- persistit = caches.persistit();
- doStart();
- }
-
- @Override
- public void start() {
- // done in constructor
- }
-
- private void doStart() {
- try {
- persistit.flush();
- volume = persistit.createTemporaryVolume();
- } catch (Exception e) {
- throw new IllegalStateException("Fail to create a cache volume", e);
- }
- }
-
- public void registerValueCoder(Class<?> clazz, ValueCoder coder) {
- CoderManager cm = persistit.getCoderManager();
- cm.registerValueCoder(clazz, coder);
- }
-
- public <V> Cache<V> createCache(String cacheName) {
- Preconditions.checkState(volume != null && volume.isOpened(), "Caches are not initialized");
- Preconditions.checkState(!cacheMap.containsKey(cacheName), "Cache is already created: " + cacheName);
- try {
- Exchange exchange = persistit.getExchange(volume, cacheName, true);
- exchange.setMaximumValueSize(Value.MAXIMUM_SIZE);
- Cache<V> cache = new Cache<>(cacheName, exchange);
- cacheMap.put(cacheName, exchange);
- return cache;
- } catch (Exception e) {
- throw new IllegalStateException("Fail to create cache: " + cacheName, e);
- }
- }
-
- @Override
- public void stop() {
- for (Entry<String, Exchange> e : cacheMap.entrySet()) {
- persistit.releaseExchange(e.getValue());
- }
-
- cacheMap.clear();
-
- if (volume != null) {
- try {
- volume.close();
- volume.delete();
- } catch (PersistitException e) {
- throw new IllegalStateException("Fail to close caches", e);
- }
- volume = null;
- }
- }
-}
+++ /dev/null
-/*
- * 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.scanner.index;
-
-import com.persistit.Persistit;
-import com.persistit.exception.PersistitException;
-import com.persistit.logging.Slf4jAdapter;
-import java.io.File;
-import java.util.Properties;
-import org.picocontainer.Startable;
-import org.slf4j.LoggerFactory;
-import org.sonar.api.batch.ScannerSide;
-import org.sonar.api.utils.TempFolder;
-
-import static org.sonar.core.util.FileUtils.deleteQuietly;
-
-/**
- * Factory of caches
- *
- * @since 3.6
- */
-@ScannerSide
-public class CachesManager implements Startable {
- private File tempDir;
- private Persistit persistit;
- private final TempFolder tempFolder;
-
- public CachesManager(TempFolder tempFolder) {
- this.tempFolder = tempFolder;
- initPersistit();
- }
-
- private void initPersistit() {
- try {
- tempDir = tempFolder.newDir("caches");
- persistit = new Persistit();
- persistit.setPersistitLogger(new Slf4jAdapter(LoggerFactory.getLogger("PERSISTIT")));
- Properties props = new Properties();
- props.setProperty("datapath", tempDir.getAbsolutePath());
- props.setProperty("logpath", "${datapath}/log");
- props.setProperty("logfile", "${logpath}/persistit_${timestamp}.log");
- props.setProperty("buffer.count.8192", "10");
- props.setProperty("journalpath", "${datapath}/journal");
- props.setProperty("tmpvoldir", "${datapath}");
- props.setProperty("volume.1", "${datapath}/persistit,create,pageSize:8192,initialPages:10,extensionPages:100,maximumPages:25000");
- props.setProperty("jmx", "false");
- persistit.setProperties(props);
- persistit.initialize();
-
- } catch (Exception e) {
- throw new IllegalStateException("Fail to start caches", e);
- }
- }
-
- @Override
- public void start() {
- // already started in constructor
- }
-
- @Override
- public void stop() {
- if (persistit != null) {
- try {
- persistit.close(false);
- persistit = null;
- } catch (PersistitException e) {
- throw new IllegalStateException("Fail to close caches", e);
- }
- }
- deleteQuietly(tempDir);
- tempDir = null;
- }
-
- File tempDir() {
- return tempDir;
- }
-
- Persistit persistit() {
- return persistit;
- }
-}
package org.sonar.scanner.issue;
import org.sonar.api.batch.ScannerSide;
-import org.sonar.scanner.index.Cache;
-import org.sonar.scanner.index.Caches;
import org.sonar.scanner.issue.tracking.TrackedIssue;
+import org.sonar.scanner.storage.Storage;
+import org.sonar.scanner.storage.Storages;
import java.util.Collection;
/**
public class IssueCache {
// component key -> issue key -> issue
- private final Cache<TrackedIssue> cache;
+ private final Storage<TrackedIssue> cache;
- public IssueCache(Caches caches) {
+ public IssueCache(Storages caches) {
cache = caches.createCache("issues");
}
import org.sonar.core.component.ComponentKeys;
import org.sonar.scanner.index.BatchComponent;
import org.sonar.scanner.index.BatchComponentCache;
-import org.sonar.scanner.index.Cache;
-import org.sonar.scanner.index.Caches;
import org.sonar.scanner.protocol.input.ScannerInput.ServerIssue;
import org.sonar.scanner.repository.ServerIssuesLoader;
import org.sonar.scanner.scan.ImmutableProjectReactor;
+import org.sonar.scanner.storage.Storage;
+import org.sonar.scanner.storage.Storages;
@InstantiationStrategy(InstantiationStrategy.PER_BATCH)
@ScannerSide
private static final Logger LOG = Loggers.get(ServerIssueRepository.class);
private static final String LOG_MSG = "Load server issues";
- private final Caches caches;
- private Cache<ServerIssue> issuesCache;
+ private final Storages caches;
+ private Storage<ServerIssue> issuesCache;
private final ServerIssuesLoader previousIssuesLoader;
private final ImmutableProjectReactor reactor;
private final BatchComponentCache resourceCache;
- public ServerIssueRepository(Caches caches, ServerIssuesLoader previousIssuesLoader, ImmutableProjectReactor reactor, BatchComponentCache resourceCache) {
+ public ServerIssueRepository(Storages caches, ServerIssuesLoader previousIssuesLoader, ImmutableProjectReactor reactor, BatchComponentCache resourceCache) {
this.caches = caches;
this.previousIssuesLoader = previousIssuesLoader;
this.reactor = reactor;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
import org.sonar.scanner.events.EventBus;
import org.sonar.scanner.index.BatchComponentCache;
-import org.sonar.scanner.index.Caches;
import org.sonar.scanner.index.DefaultIndex;
import org.sonar.scanner.issue.DefaultIssueCallback;
import org.sonar.scanner.issue.DefaultProjectIssues;
import org.sonar.scanner.scan.measure.DeprecatedMetricFinder;
import org.sonar.scanner.scan.measure.MeasureCache;
import org.sonar.scanner.source.CodeColorizers;
+import org.sonar.scanner.storage.Storages;
import org.sonar.scanner.test.TestPlanBuilder;
import org.sonar.scanner.test.TestableBuilder;
MetricProvider.class,
ProjectConfigurator.class,
DefaultIndex.class,
- Caches.class,
+ Storages.class,
BatchComponentCache.class,
DefaultIssueCallback.class,
new RulesProvider(),
import org.sonar.api.batch.ScannerSide;
import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
-import org.sonar.scanner.index.Cache;
-import org.sonar.scanner.index.Cache.Entry;
-import org.sonar.scanner.index.Caches;
+import org.sonar.scanner.storage.Storage;
+import org.sonar.scanner.storage.Storages;
+import org.sonar.scanner.storage.Storage.Entry;
/**
* Cache of all measures. This cache is shared amongst all project modules.
@ScannerSide
public class MeasureCache {
- private final Cache<DefaultMeasure<?>> cache;
+ private final Storage<DefaultMeasure<?>> cache;
- public MeasureCache(Caches caches, MetricFinder metricFinder) {
+ public MeasureCache(Storages caches, MetricFinder metricFinder) {
caches.registerValueCoder(DefaultMeasure.class, new MeasureValueCoder(metricFinder));
cache = caches.createCache("measures");
}
--- /dev/null
+/*
+ * 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.scanner.storage;
+
+import com.google.common.collect.Sets;
+import com.persistit.Exchange;
+import com.persistit.Key;
+import com.persistit.KeyFilter;
+import com.persistit.exception.PersistitException;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import org.apache.commons.lang.builder.ToStringBuilder;
+
+/**
+ * <p>
+ * This storage is not thread-safe, due to direct usage of {@link com.persistit.Exchange}
+ * </p>
+ */
+public class Storage<V> {
+
+ private final String name;
+ private final Exchange exchange;
+
+ Storage(String name, Exchange exchange) {
+ this.name = name;
+ this.exchange = exchange;
+ }
+
+ public Storage<V> put(Object key, V value) {
+ resetKey(key);
+ return doPut(value);
+ }
+
+ public Storage<V> put(Object firstKey, Object secondKey, V value) {
+ resetKey(firstKey, secondKey);
+ return doPut(value);
+ }
+
+ public Storage<V> put(Object firstKey, Object secondKey, Object thirdKey, V value) {
+ resetKey(firstKey, secondKey, thirdKey);
+ return doPut(value);
+ }
+
+ public Storage<V> put(Object[] key, V value) {
+ resetKey(key);
+ return doPut(value);
+ }
+
+ private Storage<V> doPut(V value) {
+ try {
+ exchange.getValue().put(value);
+ exchange.store();
+ return this;
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to put element in the storage '" + 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 Storage<V> clear(Object key) {
+ resetKey(key);
+ return doClear();
+ }
+
+ public Storage<V> clear(Object firstKey, Object secondKey) {
+ resetKey(firstKey, secondKey);
+ return doClear();
+ }
+
+ public Storage<V> clear(Object firstKey, Object secondKey, Object thirdKey) {
+ resetKey(firstKey, secondKey, thirdKey);
+ return doClear();
+ }
+
+ public Storage<V> clear(Object[] key) {
+ resetKey(key);
+ return doClear();
+ }
+
+ private Storage<V> 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<Object> 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<Object> 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<Object> keySet() {
+ try {
+ Set<Object> 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<V> values(Object firstKey, Object secondKey) {
+ return new ValueIterable<>(exchange, firstKey, secondKey);
+ }
+
+ /**
+ * Lazy-loading values for a given key
+ */
+ public Iterable<V> values(Object firstKey) {
+ return new ValueIterable<>(exchange, firstKey);
+ }
+
+ /**
+ * Lazy-loading values
+ */
+ public Iterable<V> values() {
+ return new ValueIterable<>(exchange);
+ }
+
+ public Iterable<Entry<V>> entries() {
+ return new EntryIterable<>(exchange);
+ }
+
+ public Iterable<Entry<V>> 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<T> implements Iterable<T> {
+ private final Exchange originExchange;
+ private final Object[] keys;
+
+ private ValueIterable(Exchange originExchange, Object... keys) {
+ this.originExchange = originExchange;
+ this.keys = keys;
+ }
+
+ @Override
+ public Iterator<T> 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<T> implements Iterator<T> {
+ 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<T> implements Iterable<Entry<T>> {
+ private final Exchange originExchange;
+ private final Object[] keys;
+
+ private EntryIterable(Exchange originExchange, Object... keys) {
+ this.originExchange = originExchange;
+ this.keys = keys;
+ }
+
+ @Override
+ public Iterator<Entry<T>> 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<T> implements Iterator<Entry<T>> {
+ 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<T> 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<V> {
+ 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);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * 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.scanner.storage;
+
+import com.google.common.collect.Maps;
+
+import java.util.Map;
+import java.util.Map.Entry;
+
+import com.google.common.base.Preconditions;
+import com.persistit.Exchange;
+import com.persistit.Value;
+import com.persistit.encoding.CoderManager;
+import com.persistit.Persistit;
+import com.persistit.encoding.ValueCoder;
+import com.persistit.exception.PersistitException;
+import com.persistit.Volume;
+import org.picocontainer.Startable;
+import org.sonar.api.batch.ScannerSide;
+
+@ScannerSide
+public class Storages implements Startable {
+ private final Map<String, Exchange> cacheMap = Maps.newHashMap();
+ private Persistit persistit;
+ private Volume volume;
+
+ public Storages(StoragesManager storagesManager) {
+ persistit = storagesManager.persistit();
+ doStart();
+ }
+
+ @Override
+ public void start() {
+ // done in constructor
+ }
+
+ private void doStart() {
+ try {
+ persistit.flush();
+ volume = persistit.createTemporaryVolume();
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to create a cache volume", e);
+ }
+ }
+
+ public void registerValueCoder(Class<?> clazz, ValueCoder coder) {
+ CoderManager cm = persistit.getCoderManager();
+ cm.registerValueCoder(clazz, coder);
+ }
+
+ public <V> Storage<V> createCache(String cacheName) {
+ Preconditions.checkState(volume != null && volume.isOpened(), "Caches are not initialized");
+ Preconditions.checkState(!cacheMap.containsKey(cacheName), "Cache is already created: " + cacheName);
+ try {
+ Exchange exchange = persistit.getExchange(volume, cacheName, true);
+ exchange.setMaximumValueSize(Value.MAXIMUM_SIZE);
+ Storage<V> cache = new Storage<>(cacheName, exchange);
+ cacheMap.put(cacheName, exchange);
+ return cache;
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to create cache: " + cacheName, e);
+ }
+ }
+
+ @Override
+ public void stop() {
+ for (Entry<String, Exchange> e : cacheMap.entrySet()) {
+ persistit.releaseExchange(e.getValue());
+ }
+
+ cacheMap.clear();
+
+ if (volume != null) {
+ try {
+ volume.close();
+ volume.delete();
+ } catch (PersistitException e) {
+ throw new IllegalStateException("Fail to close caches", e);
+ }
+ volume = null;
+ }
+ }
+}
--- /dev/null
+/*
+ * 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.scanner.storage;
+
+import com.persistit.Persistit;
+import com.persistit.exception.PersistitException;
+import com.persistit.logging.Slf4jAdapter;
+import java.io.File;
+import java.util.Properties;
+import org.picocontainer.Startable;
+import org.slf4j.LoggerFactory;
+import org.sonar.api.batch.ScannerSide;
+import org.sonar.api.utils.TempFolder;
+
+import static org.sonar.core.util.FileUtils.deleteQuietly;
+
+/**
+ * Factory of storages
+ *
+ * @since 3.6
+ */
+@ScannerSide
+public class StoragesManager implements Startable {
+ private File tempDir;
+ private Persistit persistit;
+ private final TempFolder tempFolder;
+
+ public StoragesManager(TempFolder tempFolder) {
+ this.tempFolder = tempFolder;
+ initPersistit();
+ }
+
+ private void initPersistit() {
+ try {
+ tempDir = tempFolder.newDir("caches");
+ persistit = new Persistit();
+ persistit.setPersistitLogger(new Slf4jAdapter(LoggerFactory.getLogger("PERSISTIT")));
+ Properties props = new Properties();
+ props.setProperty("datapath", tempDir.getAbsolutePath());
+ props.setProperty("logpath", "${datapath}/log");
+ props.setProperty("logfile", "${logpath}/persistit_${timestamp}.log");
+ props.setProperty("buffer.count.8192", "10");
+ props.setProperty("journalpath", "${datapath}/journal");
+ props.setProperty("tmpvoldir", "${datapath}");
+ props.setProperty("volume.1", "${datapath}/persistit,create,pageSize:8192,initialPages:10,extensionPages:100,maximumPages:25000");
+ props.setProperty("jmx", "false");
+ persistit.setProperties(props);
+ persistit.initialize();
+
+ } catch (Exception e) {
+ throw new IllegalStateException("Fail to start caches", e);
+ }
+ }
+
+ @Override
+ public void start() {
+ // already started in constructor
+ }
+
+ @Override
+ public void stop() {
+ if (persistit != null) {
+ try {
+ persistit.close(false);
+ persistit = null;
+ } catch (PersistitException e) {
+ throw new IllegalStateException("Fail to close caches", e);
+ }
+ }
+ deleteQuietly(tempDir);
+ tempDir = null;
+ }
+
+ File tempDir() {
+ return tempDir;
+ }
+
+ Persistit persistit() {
+ return persistit;
+ }
+}
--- /dev/null
+/*
+ * 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.
+ */
+@ParametersAreNonnullByDefault
+package org.sonar.scanner.storage;
+
+import javax.annotation.ParametersAreNonnullByDefault;
import org.sonar.api.CoreProperties;
import org.sonar.scanner.bootstrap.GlobalProperties;
import org.sonar.scanner.bootstrap.GlobalTempFolderProvider;
-import org.sonar.scanner.index.Caches;
-import org.sonar.scanner.index.CachesManager;
+import org.sonar.scanner.storage.Storages;
+import org.sonar.scanner.storage.StoragesManager;
import java.util.Map;
import org.junit.ClassRule;
@ClassRule
public static TemporaryFolder temp = new TemporaryFolder();
- protected static CachesManager cachesManager;
- protected Caches caches;
+ protected static StoragesManager cachesManager;
+ protected Storages caches;
- private static CachesManager createCacheOnTemp() {
+ private static StoragesManager createCacheOnTemp() {
Map<String, String> props = ImmutableMap.of(CoreProperties.WORKING_DIRECTORY, temp.getRoot().getAbsolutePath(),
CoreProperties.GLOBAL_WORKING_DIRECTORY, temp.getRoot().getAbsolutePath());
- return new CachesManager(new GlobalTempFolderProvider().provide(new GlobalProperties(props)));
+ return new StoragesManager(new GlobalTempFolderProvider().provide(new GlobalProperties(props)));
}
@BeforeClass
@Before
public void start() {
- caches = new Caches(cachesManager);
+ caches = new Storages(cachesManager);
caches.start();
}
+++ /dev/null
-/*
- * 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.scanner.index;
-
-import com.google.common.collect.Iterables;
-import org.junit.Test;
-import org.sonar.scanner.index.Cache;
-import org.sonar.scanner.index.Cache.Entry;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CacheTest extends AbstractCachesTest {
-
- @Test
- public void one_part_key() {
- Cache<String> cache = caches.createCache("capitals");
-
- assertThat(cache.get("france")).isNull();
-
- cache.put("france", "paris");
- cache.put("italy", "rome");
- assertThat(cache.get("france")).isEqualTo("paris");
- assertThat(cache.keySet()).containsOnly("france", "italy");
- assertThat(cache.keySet("france")).isEmpty();
- Iterable<String> values = cache.values();
- assertThat(values).containsOnly("paris", "rome");
- assertThat(values).containsOnly("paris", "rome");
- assertThat(cache.containsKey("france")).isTrue();
-
- Iterable<Entry<String>> iterable = cache.entries();
- Cache.Entry[] entries = Iterables.toArray(iterable, Cache.Entry.class);
- assertThat(entries).hasSize(2);
- assertThat(iterable).hasSize(2);
- assertThat(entries[0].key()[0]).isEqualTo("france");
- assertThat(entries[0].value()).isEqualTo("paris");
- assertThat(entries[1].key()[0]).isEqualTo("italy");
- assertThat(entries[1].value()).isEqualTo("rome");
-
- cache.remove("france");
- assertThat(cache.get("france")).isNull();
- assertThat(cache.get("italy")).isEqualTo("rome");
- assertThat(cache.keySet()).containsOnly("italy");
- assertThat(cache.keySet("france")).isEmpty();
- assertThat(cache.containsKey("france")).isFalse();
- assertThat(cache.containsKey("italy")).isTrue();
- assertThat(values).containsOnly("rome");
-
- cache.clear();
- assertThat(values).isEmpty();
- }
-
- @Test
- public void test_key_being_prefix_of_another_key() throws Exception {
- Cache<String> cache = caches.createCache("components");
-
- cache.put("struts-el:org.apache.strutsel.taglib.html.ELButtonTag", "the Tag");
- cache.put("struts-el:org.apache.strutsel.taglib.html.ELButtonTagBeanInfo", "the BeanInfo");
-
- assertThat(cache.get("struts-el:org.apache.strutsel.taglib.html.ELButtonTag")).isEqualTo("the Tag");
- assertThat(cache.get("struts-el:org.apache.strutsel.taglib.html.ELButtonTagBeanInfo")).isEqualTo("the BeanInfo");
- }
-
- @Test
- public void two_parts_key() {
- Cache<String> cache = caches.createCache("capitals");
-
- assertThat(cache.get("europe", "france")).isNull();
-
- cache.put("europe", "france", "paris");
- cache.put("europe", "italy", "rome");
- cache.put("asia", "china", "pekin");
- assertThat(cache.get("europe")).isNull();
- assertThat(cache.get("europe", "france")).isEqualTo("paris");
- assertThat(cache.get("europe", "italy")).isEqualTo("rome");
- assertThat(cache.get("europe")).isNull();
- assertThat(cache.keySet("europe")).containsOnly("france", "italy");
- assertThat(cache.keySet()).containsOnly("europe", "asia");
- assertThat(cache.containsKey("europe")).isFalse();
- assertThat(cache.containsKey("europe", "france")).isTrue();
- assertThat(cache.containsKey("europe", "spain")).isFalse();
- assertThat(cache.values()).containsOnly("paris", "rome", "pekin");
- assertThat(cache.values("america")).isEmpty();
- assertThat(cache.values("europe")).containsOnly("paris", "rome");
- assertThat(cache.values("oceania")).isEmpty();
-
- Iterable<Entry<String>> iterable = cache.entries();
- Cache.Entry[] allEntries = Iterables.toArray(iterable, Cache.Entry.class);
- assertThat(allEntries).hasSize(3);
- assertThat(iterable).hasSize(3);
- assertThat(allEntries[0].key()).isEqualTo(new String[] {"asia", "china"});
- assertThat(allEntries[0].value()).isEqualTo("pekin");
- assertThat(allEntries[1].key()).isEqualTo(new String[] {"europe", "france"});
- assertThat(allEntries[1].value()).isEqualTo("paris");
- assertThat(allEntries[2].key()).isEqualTo(new String[] {"europe", "italy"});
- assertThat(allEntries[2].value()).isEqualTo("rome");
-
- Iterable<Entry<String>> iterable2 = cache.entries("europe");
- Cache.Entry[] subEntries = Iterables.toArray(iterable2, Cache.Entry.class);
- assertThat(subEntries).hasSize(2);
- assertThat(iterable2).hasSize(2);
- assertThat(subEntries[0].key()).isEqualTo(new String[] {"europe", "france"});
- assertThat(subEntries[0].value()).isEqualTo("paris");
- assertThat(subEntries[1].key()).isEqualTo(new String[] {"europe", "italy"});
- assertThat(subEntries[1].value()).isEqualTo("rome");
-
- cache.remove("europe", "france");
- assertThat(cache.values()).containsOnly("rome", "pekin");
- assertThat(cache.get("europe", "france")).isNull();
- assertThat(cache.get("europe", "italy")).isEqualTo("rome");
- assertThat(cache.containsKey("europe", "france")).isFalse();
- assertThat(cache.keySet("europe")).containsOnly("italy");
-
- cache.clear("america");
- assertThat(cache.keySet()).containsOnly("europe", "asia");
- cache.clear();
- assertThat(cache.keySet()).isEmpty();
- }
-
- @Test
- public void three_parts_key() {
- Cache<String> cache = caches.createCache("places");
- assertThat(cache.get("europe", "france", "paris")).isNull();
-
- cache.put("europe", "france", "paris", "eiffel tower");
- cache.put("europe", "france", "annecy", "lake");
- cache.put("europe", "france", "poitiers", "notre dame");
- cache.put("europe", "italy", "rome", "colosseum");
- cache.put("europe2", "ukrania", "kiev", "dunno");
- cache.put("asia", "china", "pekin", "great wall");
- cache.put("america", "us", "new york", "empire state building");
- assertThat(cache.get("europe")).isNull();
- assertThat(cache.get("europe", "france")).isNull();
- assertThat(cache.get("europe", "france", "paris")).isEqualTo("eiffel tower");
- assertThat(cache.get("europe", "france", "annecy")).isEqualTo("lake");
- assertThat(cache.get("europe", "italy", "rome")).isEqualTo("colosseum");
- assertThat(cache.keySet()).containsOnly("europe", "asia", "america", "europe2");
- assertThat(cache.keySet("europe")).containsOnly("france", "italy");
- assertThat(cache.keySet("europe", "france")).containsOnly("annecy", "paris", "poitiers");
- assertThat(cache.containsKey("europe")).isFalse();
- assertThat(cache.containsKey("europe", "france")).isFalse();
- assertThat(cache.containsKey("europe", "france", "annecy")).isTrue();
- assertThat(cache.containsKey("europe", "france", "biarritz")).isFalse();
- assertThat(cache.values()).containsOnly("eiffel tower", "lake", "colosseum", "notre dame", "great wall", "empire state building", "dunno");
- assertThat(cache.values("europe")).containsOnly("eiffel tower", "lake", "colosseum", "notre dame");
- assertThat(cache.values("europe", "france")).containsOnly("eiffel tower", "lake", "notre dame");
-
- Iterable<Entry<String>> iterable = cache.entries();
- Cache.Entry[] allEntries = Iterables.toArray(iterable, Cache.Entry.class);
- assertThat(allEntries).hasSize(7);
- assertThat(iterable).hasSize(7);
- assertThat(allEntries[0].key()).isEqualTo(new String[] {"america", "us", "new york"});
- assertThat(allEntries[0].value()).isEqualTo("empire state building");
- assertThat(allEntries[1].key()).isEqualTo(new String[] {"asia", "china", "pekin"});
- assertThat(allEntries[1].value()).isEqualTo("great wall");
- assertThat(allEntries[2].key()).isEqualTo(new String[] {"europe", "france", "annecy"});
- assertThat(allEntries[2].value()).isEqualTo("lake");
- assertThat(allEntries[3].key()).isEqualTo(new String[] {"europe", "france", "paris"});
- assertThat(allEntries[3].value()).isEqualTo("eiffel tower");
- assertThat(allEntries[4].key()).isEqualTo(new String[] {"europe", "france", "poitiers"});
- assertThat(allEntries[4].value()).isEqualTo("notre dame");
- assertThat(allEntries[5].key()).isEqualTo(new String[] {"europe", "italy", "rome"});
- assertThat(allEntries[5].value()).isEqualTo("colosseum");
-
- Iterable<Entry<String>> iterable2 = cache.entries("europe");
- Cache.Entry[] subEntries = Iterables.toArray(iterable2, Cache.Entry.class);
- assertThat(subEntries).hasSize(4);
- assertThat(iterable2).hasSize(4);
- assertThat(subEntries[0].key()).isEqualTo(new String[] {"europe", "france", "annecy"});
- assertThat(subEntries[0].value()).isEqualTo("lake");
- assertThat(subEntries[1].key()).isEqualTo(new String[] {"europe", "france", "paris"});
- assertThat(subEntries[1].value()).isEqualTo("eiffel tower");
- assertThat(subEntries[2].key()).isEqualTo(new String[] {"europe", "france", "poitiers"});
- assertThat(subEntries[2].value()).isEqualTo("notre dame");
- assertThat(subEntries[3].key()).isEqualTo(new String[] {"europe", "italy", "rome"});
- assertThat(subEntries[3].value()).isEqualTo("colosseum");
-
- cache.remove("europe", "france", "annecy");
- assertThat(cache.values()).containsOnly("eiffel tower", "colosseum", "notre dame", "great wall", "empire state building", "dunno");
- assertThat(cache.values("europe")).containsOnly("eiffel tower", "colosseum", "notre dame");
- assertThat(cache.values("europe", "france")).containsOnly("eiffel tower", "notre dame");
- assertThat(cache.get("europe", "france", "annecy")).isNull();
- assertThat(cache.get("europe", "italy", "rome")).isEqualTo("colosseum");
- assertThat(cache.containsKey("europe", "france")).isFalse();
-
- cache.clear("europe", "italy");
- assertThat(cache.values()).containsOnly("eiffel tower", "notre dame", "great wall", "empire state building", "dunno");
-
- cache.clear("europe");
- assertThat(cache.values()).containsOnly("great wall", "empire state building", "dunno");
-
- cache.clear();
- assertThat(cache.values()).isEmpty();
- }
-
- @Test
- public void remove_versus_clear() {
- Cache<String> cache = caches.createCache("capitals");
- cache.put("europe", "france", "paris");
- cache.put("europe", "italy", "rome");
-
- // remove("europe") does not remove sub-keys
- cache.remove("europe");
- assertThat(cache.values()).containsOnly("paris", "rome");
-
- // clear("europe") removes sub-keys
- cache.clear("europe");
- assertThat(cache.values()).isEmpty();
- }
-
- @Test
- public void empty_cache() {
- Cache<String> cache = caches.createCache("empty");
-
- assertThat(cache.get("foo")).isNull();
- assertThat(cache.get("foo", "bar")).isNull();
- assertThat(cache.get("foo", "bar", "baz")).isNull();
- assertThat(cache.keySet()).isEmpty();
- assertThat(cache.keySet("foo")).isEmpty();
- assertThat(cache.containsKey("foo")).isFalse();
- assertThat(cache.containsKey("foo", "bar")).isFalse();
- assertThat(cache.containsKey("foo", "bar", "baz")).isFalse();
- assertThat(cache.values()).isEmpty();
- assertThat(cache.values("foo")).isEmpty();
-
- // do not fail
- cache.remove("foo");
- cache.remove("foo", "bar");
- cache.remove("foo", "bar", "baz");
- cache.clear("foo");
- cache.clear("foo", "bar");
- cache.clear("foo", "bar", "baz");
- cache.clear();
- }
-}
+++ /dev/null
-/*
- * 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.scanner.index;
-
-import org.junit.Test;
-
-import java.io.File;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class CachesManagerTest extends AbstractCachesTest {
- @Test
- public void should_stop_and_clean_temp_dir() {
- File tempDir = cachesManager.tempDir();
- assertThat(tempDir).isDirectory().exists();
- assertThat(cachesManager.persistit()).isNotNull();
- assertThat(cachesManager.persistit().isInitialized()).isTrue();
-
- cachesManager.stop();
-
- assertThat(tempDir).doesNotExist();
- assertThat(cachesManager.tempDir()).isNull();
- assertThat(cachesManager.persistit()).isNull();
- }
-}
+++ /dev/null
-/*
- * 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.scanner.index;
-
-import java.io.Serializable;
-
-import com.persistit.exception.PersistitException;
-import org.junit.Test;
-import org.sonar.scanner.index.Cache;
-import org.sonar.scanner.index.Caches;
-
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.junit.Assert.fail;
-
-public class CachesTest extends AbstractCachesTest {
- @Test
- public void should_create_cache() {
- Cache<Element> cache = caches.createCache("foo");
- assertThat(cache).isNotNull();
- }
-
- @Test
- public void should_not_create_cache_twice() {
- caches.<Element>createCache("foo");
- try {
- caches.<Element>createCache("foo");
- fail();
- } catch (IllegalStateException e) {
- // ok
- }
- }
-
- @Test
- public void should_clean_resources() {
- Cache<String> c = caches.<String>createCache("test1");
- for (int i = 0; i < 1_000_000; i++) {
- c.put("a" + i, "a" + i);
- }
-
- caches.stop();
-
- // manager continues up
- assertThat(cachesManager.persistit().isInitialized()).isTrue();
-
- caches = new Caches(cachesManager);
- caches.start();
- caches.createCache("test1");
- }
-
- @Test
- public void leak_test() throws PersistitException {
- caches.stop();
-
- int len = 1 * 1024 * 1024;
- StringBuilder sb = new StringBuilder(len);
- for (int i = 0; i < len; i++) {
- sb.append("a");
- }
-
- for (int i = 0; i < 3; i++) {
- caches = new Caches(cachesManager);
- caches.start();
- Cache<String> c = caches.<String>createCache("test" + i);
- c.put("key" + i, sb.toString());
- cachesManager.persistit().flush();
-
- caches.stop();
- }
- }
-
- private static class Element implements Serializable {
- private static final long serialVersionUID = 1L;
-
- }
-}
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.scanner.index.AbstractCachesTest;
-import org.sonar.scanner.index.Cache.Entry;
+import org.sonar.scanner.storage.Storage.Entry;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
--- /dev/null
+/*
+ * 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.scanner.storage;
+
+import com.google.common.collect.Iterables;
+import org.junit.Test;
+import org.sonar.scanner.index.AbstractCachesTest;
+import org.sonar.scanner.storage.Storage;
+import org.sonar.scanner.storage.Storage.Entry;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class StorageTest extends AbstractCachesTest {
+
+ @Test
+ public void one_part_key() {
+ Storage<String> cache = caches.createCache("capitals");
+
+ assertThat(cache.get("france")).isNull();
+
+ cache.put("france", "paris");
+ cache.put("italy", "rome");
+ assertThat(cache.get("france")).isEqualTo("paris");
+ assertThat(cache.keySet()).containsOnly("france", "italy");
+ assertThat(cache.keySet("france")).isEmpty();
+ Iterable<String> values = cache.values();
+ assertThat(values).containsOnly("paris", "rome");
+ assertThat(values).containsOnly("paris", "rome");
+ assertThat(cache.containsKey("france")).isTrue();
+
+ Iterable<Entry<String>> iterable = cache.entries();
+ Storage.Entry[] entries = Iterables.toArray(iterable, Storage.Entry.class);
+ assertThat(entries).hasSize(2);
+ assertThat(iterable).hasSize(2);
+ assertThat(entries[0].key()[0]).isEqualTo("france");
+ assertThat(entries[0].value()).isEqualTo("paris");
+ assertThat(entries[1].key()[0]).isEqualTo("italy");
+ assertThat(entries[1].value()).isEqualTo("rome");
+
+ cache.remove("france");
+ assertThat(cache.get("france")).isNull();
+ assertThat(cache.get("italy")).isEqualTo("rome");
+ assertThat(cache.keySet()).containsOnly("italy");
+ assertThat(cache.keySet("france")).isEmpty();
+ assertThat(cache.containsKey("france")).isFalse();
+ assertThat(cache.containsKey("italy")).isTrue();
+ assertThat(values).containsOnly("rome");
+
+ cache.clear();
+ assertThat(values).isEmpty();
+ }
+
+ @Test
+ public void test_key_being_prefix_of_another_key() throws Exception {
+ Storage<String> cache = caches.createCache("components");
+
+ cache.put("struts-el:org.apache.strutsel.taglib.html.ELButtonTag", "the Tag");
+ cache.put("struts-el:org.apache.strutsel.taglib.html.ELButtonTagBeanInfo", "the BeanInfo");
+
+ assertThat(cache.get("struts-el:org.apache.strutsel.taglib.html.ELButtonTag")).isEqualTo("the Tag");
+ assertThat(cache.get("struts-el:org.apache.strutsel.taglib.html.ELButtonTagBeanInfo")).isEqualTo("the BeanInfo");
+ }
+
+ @Test
+ public void two_parts_key() {
+ Storage<String> cache = caches.createCache("capitals");
+
+ assertThat(cache.get("europe", "france")).isNull();
+
+ cache.put("europe", "france", "paris");
+ cache.put("europe", "italy", "rome");
+ cache.put("asia", "china", "pekin");
+ assertThat(cache.get("europe")).isNull();
+ assertThat(cache.get("europe", "france")).isEqualTo("paris");
+ assertThat(cache.get("europe", "italy")).isEqualTo("rome");
+ assertThat(cache.get("europe")).isNull();
+ assertThat(cache.keySet("europe")).containsOnly("france", "italy");
+ assertThat(cache.keySet()).containsOnly("europe", "asia");
+ assertThat(cache.containsKey("europe")).isFalse();
+ assertThat(cache.containsKey("europe", "france")).isTrue();
+ assertThat(cache.containsKey("europe", "spain")).isFalse();
+ assertThat(cache.values()).containsOnly("paris", "rome", "pekin");
+ assertThat(cache.values("america")).isEmpty();
+ assertThat(cache.values("europe")).containsOnly("paris", "rome");
+ assertThat(cache.values("oceania")).isEmpty();
+
+ Iterable<Entry<String>> iterable = cache.entries();
+ Storage.Entry[] allEntries = Iterables.toArray(iterable, Storage.Entry.class);
+ assertThat(allEntries).hasSize(3);
+ assertThat(iterable).hasSize(3);
+ assertThat(allEntries[0].key()).isEqualTo(new String[] {"asia", "china"});
+ assertThat(allEntries[0].value()).isEqualTo("pekin");
+ assertThat(allEntries[1].key()).isEqualTo(new String[] {"europe", "france"});
+ assertThat(allEntries[1].value()).isEqualTo("paris");
+ assertThat(allEntries[2].key()).isEqualTo(new String[] {"europe", "italy"});
+ assertThat(allEntries[2].value()).isEqualTo("rome");
+
+ Iterable<Entry<String>> iterable2 = cache.entries("europe");
+ Storage.Entry[] subEntries = Iterables.toArray(iterable2, Storage.Entry.class);
+ assertThat(subEntries).hasSize(2);
+ assertThat(iterable2).hasSize(2);
+ assertThat(subEntries[0].key()).isEqualTo(new String[] {"europe", "france"});
+ assertThat(subEntries[0].value()).isEqualTo("paris");
+ assertThat(subEntries[1].key()).isEqualTo(new String[] {"europe", "italy"});
+ assertThat(subEntries[1].value()).isEqualTo("rome");
+
+ cache.remove("europe", "france");
+ assertThat(cache.values()).containsOnly("rome", "pekin");
+ assertThat(cache.get("europe", "france")).isNull();
+ assertThat(cache.get("europe", "italy")).isEqualTo("rome");
+ assertThat(cache.containsKey("europe", "france")).isFalse();
+ assertThat(cache.keySet("europe")).containsOnly("italy");
+
+ cache.clear("america");
+ assertThat(cache.keySet()).containsOnly("europe", "asia");
+ cache.clear();
+ assertThat(cache.keySet()).isEmpty();
+ }
+
+ @Test
+ public void three_parts_key() {
+ Storage<String> cache = caches.createCache("places");
+ assertThat(cache.get("europe", "france", "paris")).isNull();
+
+ cache.put("europe", "france", "paris", "eiffel tower");
+ cache.put("europe", "france", "annecy", "lake");
+ cache.put("europe", "france", "poitiers", "notre dame");
+ cache.put("europe", "italy", "rome", "colosseum");
+ cache.put("europe2", "ukrania", "kiev", "dunno");
+ cache.put("asia", "china", "pekin", "great wall");
+ cache.put("america", "us", "new york", "empire state building");
+ assertThat(cache.get("europe")).isNull();
+ assertThat(cache.get("europe", "france")).isNull();
+ assertThat(cache.get("europe", "france", "paris")).isEqualTo("eiffel tower");
+ assertThat(cache.get("europe", "france", "annecy")).isEqualTo("lake");
+ assertThat(cache.get("europe", "italy", "rome")).isEqualTo("colosseum");
+ assertThat(cache.keySet()).containsOnly("europe", "asia", "america", "europe2");
+ assertThat(cache.keySet("europe")).containsOnly("france", "italy");
+ assertThat(cache.keySet("europe", "france")).containsOnly("annecy", "paris", "poitiers");
+ assertThat(cache.containsKey("europe")).isFalse();
+ assertThat(cache.containsKey("europe", "france")).isFalse();
+ assertThat(cache.containsKey("europe", "france", "annecy")).isTrue();
+ assertThat(cache.containsKey("europe", "france", "biarritz")).isFalse();
+ assertThat(cache.values()).containsOnly("eiffel tower", "lake", "colosseum", "notre dame", "great wall", "empire state building", "dunno");
+ assertThat(cache.values("europe")).containsOnly("eiffel tower", "lake", "colosseum", "notre dame");
+ assertThat(cache.values("europe", "france")).containsOnly("eiffel tower", "lake", "notre dame");
+
+ Iterable<Entry<String>> iterable = cache.entries();
+ Storage.Entry[] allEntries = Iterables.toArray(iterable, Storage.Entry.class);
+ assertThat(allEntries).hasSize(7);
+ assertThat(iterable).hasSize(7);
+ assertThat(allEntries[0].key()).isEqualTo(new String[] {"america", "us", "new york"});
+ assertThat(allEntries[0].value()).isEqualTo("empire state building");
+ assertThat(allEntries[1].key()).isEqualTo(new String[] {"asia", "china", "pekin"});
+ assertThat(allEntries[1].value()).isEqualTo("great wall");
+ assertThat(allEntries[2].key()).isEqualTo(new String[] {"europe", "france", "annecy"});
+ assertThat(allEntries[2].value()).isEqualTo("lake");
+ assertThat(allEntries[3].key()).isEqualTo(new String[] {"europe", "france", "paris"});
+ assertThat(allEntries[3].value()).isEqualTo("eiffel tower");
+ assertThat(allEntries[4].key()).isEqualTo(new String[] {"europe", "france", "poitiers"});
+ assertThat(allEntries[4].value()).isEqualTo("notre dame");
+ assertThat(allEntries[5].key()).isEqualTo(new String[] {"europe", "italy", "rome"});
+ assertThat(allEntries[5].value()).isEqualTo("colosseum");
+
+ Iterable<Entry<String>> iterable2 = cache.entries("europe");
+ Storage.Entry[] subEntries = Iterables.toArray(iterable2, Storage.Entry.class);
+ assertThat(subEntries).hasSize(4);
+ assertThat(iterable2).hasSize(4);
+ assertThat(subEntries[0].key()).isEqualTo(new String[] {"europe", "france", "annecy"});
+ assertThat(subEntries[0].value()).isEqualTo("lake");
+ assertThat(subEntries[1].key()).isEqualTo(new String[] {"europe", "france", "paris"});
+ assertThat(subEntries[1].value()).isEqualTo("eiffel tower");
+ assertThat(subEntries[2].key()).isEqualTo(new String[] {"europe", "france", "poitiers"});
+ assertThat(subEntries[2].value()).isEqualTo("notre dame");
+ assertThat(subEntries[3].key()).isEqualTo(new String[] {"europe", "italy", "rome"});
+ assertThat(subEntries[3].value()).isEqualTo("colosseum");
+
+ cache.remove("europe", "france", "annecy");
+ assertThat(cache.values()).containsOnly("eiffel tower", "colosseum", "notre dame", "great wall", "empire state building", "dunno");
+ assertThat(cache.values("europe")).containsOnly("eiffel tower", "colosseum", "notre dame");
+ assertThat(cache.values("europe", "france")).containsOnly("eiffel tower", "notre dame");
+ assertThat(cache.get("europe", "france", "annecy")).isNull();
+ assertThat(cache.get("europe", "italy", "rome")).isEqualTo("colosseum");
+ assertThat(cache.containsKey("europe", "france")).isFalse();
+
+ cache.clear("europe", "italy");
+ assertThat(cache.values()).containsOnly("eiffel tower", "notre dame", "great wall", "empire state building", "dunno");
+
+ cache.clear("europe");
+ assertThat(cache.values()).containsOnly("great wall", "empire state building", "dunno");
+
+ cache.clear();
+ assertThat(cache.values()).isEmpty();
+ }
+
+ @Test
+ public void remove_versus_clear() {
+ Storage<String> cache = caches.createCache("capitals");
+ cache.put("europe", "france", "paris");
+ cache.put("europe", "italy", "rome");
+
+ // remove("europe") does not remove sub-keys
+ cache.remove("europe");
+ assertThat(cache.values()).containsOnly("paris", "rome");
+
+ // clear("europe") removes sub-keys
+ cache.clear("europe");
+ assertThat(cache.values()).isEmpty();
+ }
+
+ @Test
+ public void empty_cache() {
+ Storage<String> cache = caches.createCache("empty");
+
+ assertThat(cache.get("foo")).isNull();
+ assertThat(cache.get("foo", "bar")).isNull();
+ assertThat(cache.get("foo", "bar", "baz")).isNull();
+ assertThat(cache.keySet()).isEmpty();
+ assertThat(cache.keySet("foo")).isEmpty();
+ assertThat(cache.containsKey("foo")).isFalse();
+ assertThat(cache.containsKey("foo", "bar")).isFalse();
+ assertThat(cache.containsKey("foo", "bar", "baz")).isFalse();
+ assertThat(cache.values()).isEmpty();
+ assertThat(cache.values("foo")).isEmpty();
+
+ // do not fail
+ cache.remove("foo");
+ cache.remove("foo", "bar");
+ cache.remove("foo", "bar", "baz");
+ cache.clear("foo");
+ cache.clear("foo", "bar");
+ cache.clear("foo", "bar", "baz");
+ cache.clear();
+ }
+}
--- /dev/null
+/*
+ * 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.scanner.storage;
+
+import org.junit.Test;
+import org.sonar.scanner.index.AbstractCachesTest;
+import java.io.File;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class StoragesManagerTest extends AbstractCachesTest {
+ @Test
+ public void should_stop_and_clean_temp_dir() {
+ File tempDir = cachesManager.tempDir();
+ assertThat(tempDir).isDirectory().exists();
+ assertThat(cachesManager.persistit()).isNotNull();
+ assertThat(cachesManager.persistit().isInitialized()).isTrue();
+
+ cachesManager.stop();
+
+ assertThat(tempDir).doesNotExist();
+ assertThat(cachesManager.tempDir()).isNull();
+ assertThat(cachesManager.persistit()).isNull();
+ }
+}
--- /dev/null
+/*
+ * 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.scanner.storage;
+
+import java.io.Serializable;
+
+import com.persistit.exception.PersistitException;
+import org.junit.Test;
+import org.sonar.scanner.index.AbstractCachesTest;
+import org.sonar.scanner.storage.Storage;
+import org.sonar.scanner.storage.Storages;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.Assert.fail;
+
+public class StoragesTest extends AbstractCachesTest {
+ @Test
+ public void should_create_cache() {
+ Storage<Element> cache = caches.createCache("foo");
+ assertThat(cache).isNotNull();
+ }
+
+ @Test
+ public void should_not_create_cache_twice() {
+ caches.<Element>createCache("foo");
+ try {
+ caches.<Element>createCache("foo");
+ fail();
+ } catch (IllegalStateException e) {
+ // ok
+ }
+ }
+
+ @Test
+ public void should_clean_resources() {
+ Storage<String> c = caches.<String>createCache("test1");
+ for (int i = 0; i < 1_000_000; i++) {
+ c.put("a" + i, "a" + i);
+ }
+
+ caches.stop();
+
+ // manager continues up
+ assertThat(cachesManager.persistit().isInitialized()).isTrue();
+
+ caches = new Storages(cachesManager);
+ caches.start();
+ caches.createCache("test1");
+ }
+
+ @Test
+ public void leak_test() throws PersistitException {
+ caches.stop();
+
+ int len = 1 * 1024 * 1024;
+ StringBuilder sb = new StringBuilder(len);
+ for (int i = 0; i < len; i++) {
+ sb.append("a");
+ }
+
+ for (int i = 0; i < 3; i++) {
+ caches = new Storages(cachesManager);
+ caches.start();
+ Storage<String> c = caches.<String>createCache("test" + i);
+ c.put("key" + i, sb.toString());
+ cachesManager.persistit().flush();
+
+ caches.stop();
+ }
+ }
+
+ private static class Element implements Serializable {
+ private static final long serialVersionUID = 1L;
+
+ }
+}