001 /*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
019 */
020 package org.sonar.batch.index;
021
022 import com.google.common.base.Preconditions;
023 import com.google.common.collect.Sets;
024 import com.persistit.Exchange;
025 import com.persistit.Persistit;
026 import com.persistit.Value;
027 import com.persistit.Volume;
028 import com.persistit.encoding.CoderManager;
029 import com.persistit.encoding.ValueCoder;
030 import com.persistit.exception.PersistitException;
031 import com.persistit.logging.Slf4jAdapter;
032 import org.apache.commons.io.FileUtils;
033 import org.picocontainer.Startable;
034 import org.slf4j.LoggerFactory;
035 import org.sonar.api.BatchComponent;
036 import org.sonar.api.utils.TempFolder;
037
038 import java.io.File;
039 import java.util.Properties;
040 import java.util.Set;
041
042 /**
043 * Factory of caches
044 *
045 * @since 3.6
046 */
047 public class Caches implements BatchComponent, Startable {
048
049 private final Set<String> cacheNames = Sets.newHashSet();
050 private File tempDir;
051 private Persistit persistit;
052 private Volume volume;
053 private final TempFolder tempFolder;
054
055 public Caches(TempFolder tempFolder) {
056 this.tempFolder = tempFolder;
057 initPersistit();
058 }
059
060 private void initPersistit() {
061 try {
062 tempDir = tempFolder.newDir("caches");
063 persistit = new Persistit();
064 persistit.setPersistitLogger(new Slf4jAdapter(LoggerFactory.getLogger("PERSISTIT")));
065 Properties props = new Properties();
066 props.setProperty("datapath", tempDir.getAbsolutePath());
067 props.setProperty("logpath", "${datapath}/log");
068 props.setProperty("logfile", "${logpath}/persistit_${timestamp}.log");
069 props.setProperty("buffer.count.8192", "10");
070 props.setProperty("journalpath", "${datapath}/journal");
071 props.setProperty("tmpvoldir", "${datapath}");
072 props.setProperty("volume.1", "${datapath}/persistit,create,pageSize:8192,initialPages:10,extensionPages:100,maximumPages:25000");
073 persistit.setProperties(props);
074 persistit.initialize();
075 volume = persistit.createTemporaryVolume();
076
077 } catch (Exception e) {
078 throw new IllegalStateException("Fail to start caches", e);
079 }
080 }
081
082 public void registerValueCoder(Class<?> clazz, ValueCoder coder) {
083 CoderManager cm = persistit.getCoderManager();
084 cm.registerValueCoder(clazz, coder);
085 }
086
087 public <V> Cache<V> createCache(String cacheName) {
088 Preconditions.checkState(volume != null && volume.isOpened(), "Caches are not initialized");
089 Preconditions.checkState(!cacheNames.contains(cacheName), "Cache is already created: " + cacheName);
090 try {
091 Exchange exchange = persistit.getExchange(volume, cacheName, true);
092 exchange.setMaximumValueSize(Value.MAXIMUM_SIZE);
093 Cache<V> cache = new Cache<V>(cacheName, exchange);
094 cacheNames.add(cacheName);
095 return cache;
096 } catch (Exception e) {
097 throw new IllegalStateException("Fail to create cache: " + cacheName, e);
098 }
099 }
100
101 @Override
102 public void start() {
103 // already started in constructor
104 }
105
106 @Override
107 public void stop() {
108 if (persistit != null) {
109 try {
110 persistit.close(false);
111 persistit = null;
112 volume = null;
113 } catch (PersistitException e) {
114 throw new IllegalStateException("Fail to close caches", e);
115 }
116 }
117 FileUtils.deleteQuietly(tempDir);
118 tempDir = null;
119 cacheNames.clear();
120 }
121
122 File tempDir() {
123 return tempDir;
124 }
125
126 Persistit persistit() {
127 return persistit;
128 }
129 }