blob: 50170b24ce8a4241390256c3dba828a113381b73 [file] [log] [blame]
/*
* Copyright (c) 2011, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.indexer.storage.inmemory;
import com.google.dart.indexer.IndexerPlugin;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.BitSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
public final class StorageManager {
private static final long MAGIC = 0xCAFEBABEL;
protected static final long FLUSH_TIMEOUT = 180000;
private static Thread storagePersistenceManager = new Thread("Indexer State Saver") {
@Override
public void run() {
while (true) {
try {
Thread.sleep(FLUSH_TIMEOUT);
} catch (InterruptedException e) {
IndexerPlugin.getLogger().logError(e);
}
saveIfNeeded();
}
}
};
static HashSet<OptimizedIndexStorage> changed = new HashSet<OptimizedIndexStorage>();
private static File wholeIndexFileStorage;
private static File tmpFile;
static {
storagePersistenceManager.setDaemon(true);
storagePersistenceManager.start();
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
saveIfNeeded();
}
});
}
public static OptimizedIndexStorage loadFromCache() throws FileNotFoundException, IOException {
DataInputStream in = new DataInputStream(new BufferedInputStream(new FileInputStream(
wholeIndexFileStorage)));
try {
OptimizedIndexStorage storage = loadOptimizedIndexStorage(in);
// registerStorage(storage);
return storage;
} finally {
in.close();
}
}
public static void setTargetFile(File file) {
wholeIndexFileStorage = file;
}
static void registerStorage(OptimizedIndexStorage storage) {
storage.addStorageChangeListener(new IStorageChangeListener() {
@Override
public void storageChanged(OptimizedIndexStorage storage) {
synchronized (changed) {
changed.add(storage);
}
// saveIfNeeded();
}
});
}
private static void checkMagic(DataInputStream in) throws IOException {
if (MAGIC != in.readLong()) {
throw new RuntimeException("invalid magic!");
}
}
private static File getTargetIndexFile() {
if (wholeIndexFileStorage == null) {
wholeIndexFileStorage = new File("c:\\test.indx");
}
wholeIndexFileStorage.delete();
return wholeIndexFileStorage;
}
private static File getTemporaryFile(OptimizedIndexStorage ip) throws IOException {
if (tmpFile == null) {
tmpFile = File.createTempFile("indexer", null);
tmpFile.deleteOnExit();
}
return tmpFile;
}
private static BitSet loadBitSet(DataInputStream in) throws IOException {
int cardinality = in.readInt();
BitSet result = new BitSet();
while (cardinality-- != 0) {
result.set(in.readInt());
}
return result;
}
private static ByteArray loadByteArray(DataInputStream in) throws IOException {
int size = in.readInt();
byte[] data = new byte[size];
in.readFully(data);
AbstractStringEncoder e = null;
int x = in.read();
if (x == 1) {
e = new PlainStringEncoder();
} else if (x == 2) {
e = new OptimizedStringEncoder2(loadSimpleStringPool(in));
} else {
throw new IllegalStateException();
}
return new ByteArray(size, data, e);
}
private static FileInfoManager loadFileInfoManager(DataInputStream in) throws IOException {
int size = in.readInt();
int[] ids = readInts(in);
IntArray locInfos = loadIntArray(in);
IntArray poss = loadIntArray(in);
ByteArray array = loadByteArray(in);
checkMagic(in);
return new FileInfoManager(size, ids, locInfos, poss, array, new PlainStringEncoder());
}
private static IntArray loadIntArray(DataInputStream in) throws IOException {
return new IntArray(readInts(in));
}
private static HashMap<String, ByteByteArray> loadLayersMap(DataInputStream in)
throws IOException {
int size = in.readInt();
HashMap<String, ByteByteArray> result = new HashMap<String, ByteByteArray>();
for (int i = 0; i < size; i++) {
String key = in.readUTF();
ByteByteArray value = new ByteByteArray(in);
result.put(key, value);
}
checkMagic(in);
return result;
}
private static LocationInfoManager loadLocationInfoManager(DataInputStream in) throws IOException {
int size = in.readInt();
int[] ids = readInts(in);
IntArray locInfos = loadIntArray(in);
IntArray poss = loadIntArray(in);
ByteArray array = loadByteArray(in);
checkMagic(in);
return new LocationInfoManager(size, ids, locInfos, poss, array, new OptimizedStringEncoder2());
}
private static int loadMaxLocationsSize(DataInputStream in) throws IOException {
return in.readInt();
}
private static OptimizedIndexStorage loadOptimizedIndexStorage(DataInputStream in)
throws IOException {
/* int maxLoc = */loadMaxLocationsSize(in);
/* SimpleStringPool layerIds = */loadSimpleStringPool(in);
/* LocationInfoManager locInfoMananger = */loadLocationInfoManager(in);
/* FileInfoManager fileInfoManager = */loadFileInfoManager(in);
/* ByteByteArray fileInfos = */new ByteByteArray(in);
/* HashMap<String, ByteByteArray> layers = */loadLayersMap(in);
/* BitSet deletedFiles = */loadBitSet(in);
/* BitSet deletedLocations = */loadBitSet(in);
checkMagic(in);
throw new AssertionError("unused method, disabled");
// return new OptimizedIndexStorage(locInfoMananger, fileInfoManager,
// layerIds, layers, maxLoc, fileInfos, deletedFiles,
// deletedLocations);
}
private static SimpleStringPool loadSimpleStringPool(DataInputStream in) throws IOException {
int size = in.readInt();
int[] ids = readInts(in);
IntArray intArray = loadIntArray(in);
ByteArray byteArray = loadByteArray(in);
checkMagic(in);
return new SimpleStringPool(size, ids, intArray, byteArray);
}
private static int[] readInts(DataInputStream in) throws IOException {
int[] result = new int[in.readInt()];
for (int i = 0; i < result.length; i++) {
result[i] = in.readInt();
}
checkMagic(in);
return result;
}
private static boolean saveAllDeletionMarks(BitSet deletedFileIds, BitSet deletedElementIds,
DataOutputStream out) {
try {
saveBitSet(deletedFileIds, out);
saveBitSet(deletedElementIds, out);
writeMagic(out);
return true;
} catch (Exception e) {
return false;
}
}
private static boolean saveBitSet(BitSet bs, DataOutputStream out) {
try {
int elements = bs.cardinality();
out.writeInt(elements);
for (int i = bs.nextSetBit(0); i >= 0; i = bs.nextSetBit(i + 1)) {
out.writeInt(i);
}
return true;
} catch (Exception e) {
return false;
}
}
private static void saveByteArray(ByteArray array, DataOutputStream out) throws IOException {
out.writeInt(array.elementsCount);
out.write(array.data, 0, array.elementsCount);
if (array.encoder instanceof PlainStringEncoder) {
out.write(1);
} else if (array.encoder instanceof OptimizedStringEncoder2) {
out.write(2);
OptimizedStringEncoder2 e = (OptimizedStringEncoder2) array.encoder;
saveSimpleStringPool(e.packagePool, out);
} else {
throw new RuntimeException();
}
}
private static boolean saveFileInfoManager(FileInfoManager fileInfoPool, DataOutputStream out) {
try {
out.writeInt(fileInfoPool.size);
writeInts(fileInfoPool.ids, out);
saveIntArray(fileInfoPool.locationInfos, out);
saveIntArray(fileInfoPool.positions, out);
saveByteArray(fileInfoPool.array, out);
writeMagic(out);
return true;
} catch (Exception e) {
return false;
}
}
private static boolean saveFileInfos(ByteByteArray bbarray, DataOutputStream out) {
try {
bbarray.store(out);
return true;
} catch (Exception e) {
return false;
}
}
private static void saveIfNeeded() {
HashSet<OptimizedIndexStorage> toSave = new HashSet<OptimizedIndexStorage>();
synchronized (changed) {
toSave.addAll(changed);
changed.clear();
}
Iterator<OptimizedIndexStorage> i = toSave.iterator();
while (i.hasNext()) {
OptimizedIndexStorage ip = i.next();
synchronized (ip) {
try {
File fls = getTemporaryFile(ip);
DataOutputStream out = null;
try {
out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(fls)));
if (saveOptimizedStorage(ip, out)) {
out.close();
File targetFile = getTargetIndexFile();
if (!fls.renameTo(targetFile)) {
targetFile.delete();
fls.renameTo(targetFile);
} else {
}
}
} finally {
if (null != out) {
out.close();
}
}
} catch (IOException exception) {
IndexerPlugin.getLogger().logError(exception);
}
}
}
}
private static void saveIntArray(IntArray array, DataOutputStream out) throws IOException {
writeInts(array.toArray(), out);
}
private static boolean saveLayersMap(HashMap<String, ByteByteArray> map, DataOutputStream out) {
try {
int elements = map.size();
out.writeInt(elements);
for (Iterator<Map.Entry<String, ByteByteArray>> i = map.entrySet().iterator(); i.hasNext();) {
Entry<String, ByteByteArray> entry = i.next();
out.writeUTF(entry.getKey());
entry.getValue().store(out);
}
writeMagic(out);
return true;
} catch (Exception e) {
return false;
}
}
private static boolean saveLocationInfoManager(LocationInfoManager manager, DataOutputStream out) {
try {
out.writeInt(manager.size);
writeInts(manager.ids, out);
saveIntArray(manager.locationInfos, out);
saveIntArray(manager.positions, out);
saveByteArray(manager.array, out);
writeMagic(out);
return true;
} catch (Exception e) {
return false;
}
}
private static boolean saveMaxLocationsSize(int maxLocationSize, DataOutputStream out) {
try {
out.writeInt(maxLocationSize);
return true;
} catch (Exception e) {
return false;
}
}
private static boolean saveOptimizedStorage(OptimizedIndexStorage ip, DataOutputStream out) {
return saveMaxLocationsSize(ip.getMaxLocationSize(), out)
&& saveSimpleStringPool(ip.getLayerIds(), out)
&& saveLocationInfoManager(ip.getLocationInfoPool(), out)
&& saveFileInfoManager(ip.getFileInfoPool(), out) && saveFileInfos(ip.getFileInfos(), out)
&& saveLayersMap(ip.getLayersMap(), out)
&& saveAllDeletionMarks(ip.getDeletedFileIds(), ip.getDeletedElementIds(), out);
}
private static boolean saveSimpleStringPool(SimpleStringPool stringsPool, DataOutputStream out) {
try {
out.writeInt(stringsPool.size);
writeInts(stringsPool.ids, out);
saveIntArray(stringsPool.positions, out);
saveByteArray(stringsPool.array, out);
writeMagic(out);
return true;
} catch (Exception e) {
return false;
}
}
private static void writeInts(int[] ints, DataOutputStream out) throws IOException {
out.writeInt(ints.length);
for (int i = 0; i < ints.length; i++) {
out.writeInt(ints[i]);
}
writeMagic(out);
}
private static void writeMagic(DataOutputStream out) throws IOException {
out.writeLong(MAGIC);
}
private StorageManager() {
}
}