]> source.dussan.org Git - sonarqube.git/commitdiff
Rename persistit classes Cache* -> Storage*
authorJulien HENRY <julien.henry@sonarsource.com>
Wed, 19 Oct 2016 08:29:39 +0000 (10:29 +0200)
committerJulien HENRY <henryju@yahoo.fr>
Fri, 21 Oct 2016 11:17:30 +0000 (13:17 +0200)
20 files changed:
sonar-scanner-engine/src/main/java/org/sonar/scanner/bootstrap/GlobalContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/index/Cache.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/index/Caches.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/index/CachesManager.java [deleted file]
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/IssueCache.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/issue/tracking/ServerIssueRepository.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/ProjectScanContainer.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/scan/measure/MeasureCache.java
sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storages.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/StoragesManager.java [new file with mode: 0644]
sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/package-info.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/index/AbstractCachesTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/index/CacheTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/index/CachesManagerTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/index/CachesTest.java [deleted file]
sonar-scanner-engine/src/test/java/org/sonar/scanner/scan/measure/MeasureCacheTest.java
sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StorageTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesManagerTest.java [new file with mode: 0644]
sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesTest.java [new file with mode: 0644]

index cb98c42d0472ad874aa6d439a5afd69f2590d840..c4532d72ea9c845205091eed2338665aa2a93e97 100644 (file)
@@ -38,11 +38,11 @@ import org.sonar.core.platform.PluginLoader;
 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 {
@@ -82,7 +82,7 @@ public class GlobalContainer extends ComponentContainer {
 
       new SonarQubeVersion(apiVersion),
       SonarRuntimeImpl.forSonarQube(apiVersion, SonarQubeSide.SCANNER),
-      CachesManager.class,
+      StoragesManager.class,
       GlobalSettings.class,
       new BatchWsClientProvider(),
       DefaultServer.class,
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/Cache.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/Cache.java
deleted file mode 100644 (file)
index 40ae68c..0000000
+++ /dev/null
@@ -1,503 +0,0 @@
-/*
- * 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);
-    }
-  }
-
-}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/Caches.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/Caches.java
deleted file mode 100644 (file)
index d74acd5..0000000
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * 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;
-    }
-  }
-}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/CachesManager.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/index/CachesManager.java
deleted file mode 100644 (file)
index 95d3aaf..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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;
-  }
-}
index 9fb784d1563427b551bf847aa81814d5be83dc7f..4d18806a10fd4c009b7f4124ea753b00716a6932 100644 (file)
@@ -20,9 +20,9 @@
 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;
 
 /**
@@ -32,9 +32,9 @@ 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");
   }
 
index 9c3fefbd5ac50650f3492289d157e176dfcef0a1..116955cc6ead1ec85922525bb4e54c2900e718cb 100644 (file)
@@ -29,11 +29,11 @@ import org.sonar.api.utils.log.Profiler;
 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
@@ -42,13 +42,13 @@ public class ServerIssueRepository {
   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;
index 649e994cb05521730933645d95ace4bbfbb3f0ed..310acabe7413e4ecc4fdb0a24bd6f042677073db 100644 (file)
@@ -44,7 +44,6 @@ import org.sonar.scanner.cpd.CpdExecutor;
 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;
@@ -90,6 +89,7 @@ import org.sonar.scanner.scan.measure.DefaultMetricFinder;
 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;
 
@@ -139,7 +139,7 @@ public class ProjectScanContainer extends ComponentContainer {
       MetricProvider.class,
       ProjectConfigurator.class,
       DefaultIndex.class,
-      Caches.class,
+      Storages.class,
       BatchComponentCache.class,
       DefaultIssueCallback.class,
       new RulesProvider(),
index b0e9b87ceeb9426bd2f76bdcb55929425fdbb910..36695769b927327e0da9633c349da7de06d81f31 100644 (file)
@@ -24,9 +24,9 @@ import javax.annotation.CheckForNull;
 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.
@@ -34,9 +34,9 @@ import org.sonar.scanner.index.Caches;
 @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");
   }
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storage.java
new file mode 100644 (file)
index 0000000..2fe7fe2
--- /dev/null
@@ -0,0 +1,503 @@
+/*
+ * 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);
+    }
+  }
+
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storages.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/Storages.java
new file mode 100644 (file)
index 0000000..c7ecb2e
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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;
+    }
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/StoragesManager.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/StoragesManager.java
new file mode 100644 (file)
index 0000000..2678c13
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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;
+  }
+}
diff --git a/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/package-info.java b/sonar-scanner-engine/src/main/java/org/sonar/scanner/storage/package-info.java
new file mode 100644 (file)
index 0000000..bae79eb
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * 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;
index d15905dbb820780c1e7bc1013841f3010f46773d..e2c5760cfd4651eec59a137f0d4d927896b57df9 100644 (file)
@@ -28,8 +28,8 @@ import com.google.common.collect.ImmutableMap;
 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;
@@ -39,14 +39,14 @@ public abstract class AbstractCachesTest {
   @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
@@ -57,7 +57,7 @@ public abstract class AbstractCachesTest {
 
   @Before
   public void start() {
-    caches = new Caches(cachesManager);
+    caches = new Storages(cachesManager);
     caches.start();
   }
 
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/CacheTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/CacheTest.java
deleted file mode 100644 (file)
index 3c2765a..0000000
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * 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();
-  }
-}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/CachesManagerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/CachesManagerTest.java
deleted file mode 100644 (file)
index 48dc339..0000000
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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();
-  }
-}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/CachesTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/index/CachesTest.java
deleted file mode 100644 (file)
index 1a001c5..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * 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;
-
-  }
-}
index 702fd8a31d5f32bef59fa9c292b37d5754dcfa45..e667ed629de9147e177d96e92e2b3ba6f7f24cc5 100644 (file)
@@ -28,7 +28,7 @@ import org.sonar.api.batch.measure.MetricFinder;
 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;
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StorageTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StorageTest.java
new file mode 100644 (file)
index 0000000..b936aae
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * 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();
+  }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesManagerTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesManagerTest.java
new file mode 100644 (file)
index 0000000..d395786
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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();
+  }
+}
diff --git a/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesTest.java b/sonar-scanner-engine/src/test/java/org/sonar/scanner/storage/StoragesTest.java
new file mode 100644 (file)
index 0000000..6f90a10
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+  }
+}