mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
EOFException in IndexingStamp.createOrGetTimeStamp
This commit is contained in:
@@ -1,218 +1,219 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.intellij.util.indexing;
|
||||
|
||||
import com.intellij.openapi.vfs.InvalidVirtualFileAccessException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.FileAttribute;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
|
||||
import com.intellij.util.containers.ConcurrentHashMap;
|
||||
import com.intellij.util.io.DataInputOutputUtil;
|
||||
import gnu.trove.TObjectLongHashMap;
|
||||
import gnu.trove.TObjectLongProcedure;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: Dec 25, 2007
|
||||
*/
|
||||
public class IndexingStamp {
|
||||
private IndexingStamp() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The class is meant to be accessed from synchronized block only
|
||||
*/
|
||||
private static class Timestamps {
|
||||
private static final FileAttribute PERSISTENCE = new FileAttribute("__index_stamps__", 1, false);
|
||||
private TObjectLongHashMap<ID<?, ?>> myIndexStamps;
|
||||
private boolean myIsDirty = false;
|
||||
|
||||
private Timestamps(@Nullable DataInputStream stream) throws IOException {
|
||||
if (stream != null) {
|
||||
try {
|
||||
if (stream.available() > 0) {
|
||||
long dominatingIndexStamp = DataInputOutputUtil.readTIME(stream);
|
||||
while(stream.available() > 0) {
|
||||
ID<?, ?> id = ID.findById(DataInputOutputUtil.readINT(stream));
|
||||
if (id != null) {
|
||||
long stamp = IndexInfrastructure.getIndexCreationStamp(id);
|
||||
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<ID<?, ?>>(5, 0.98f);
|
||||
if (stamp <= dominatingIndexStamp) myIndexStamps.put(id, stamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeToStream(final DataOutputStream stream) throws IOException {
|
||||
if (myIndexStamps != null) {
|
||||
final long[] dominatingIndexStamp = new long[1];
|
||||
myIndexStamps.forEachEntry(
|
||||
new TObjectLongProcedure<ID<?, ?>>() {
|
||||
@Override
|
||||
public boolean execute(ID<?, ?> a, long b) {
|
||||
dominatingIndexStamp[0] = Math.max(dominatingIndexStamp[0], b);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
DataInputOutputUtil.writeTIME(stream, dominatingIndexStamp[0]);
|
||||
myIndexStamps.forEachEntry(new TObjectLongProcedure<ID<?, ?>>() {
|
||||
@Override
|
||||
public boolean execute(final ID<?, ?> id, final long timestamp) {
|
||||
try {
|
||||
DataInputOutputUtil.writeINT(stream, id.getUniqueId());
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public long get(ID<?, ?> id) {
|
||||
return myIndexStamps != null? myIndexStamps.get(id) : 0L;
|
||||
}
|
||||
|
||||
public void set(ID<?, ?> id, long tmst) {
|
||||
try {
|
||||
if (tmst < 0) {
|
||||
if (myIndexStamps == null) return;
|
||||
myIndexStamps.remove(id);
|
||||
return;
|
||||
}
|
||||
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<ID<?, ?>>(5, 0.98f);
|
||||
|
||||
myIndexStamps.put(id, tmst);
|
||||
}
|
||||
finally {
|
||||
myIsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return myIsDirty;
|
||||
}
|
||||
}
|
||||
|
||||
private static final ConcurrentHashMap<VirtualFile, Timestamps> myTimestampsCache = new ConcurrentHashMap<VirtualFile, Timestamps>();
|
||||
private static final int CAPACITY = 100;
|
||||
private static final ArrayBlockingQueue<VirtualFile> myFinishedFiles = new ArrayBlockingQueue<VirtualFile>(CAPACITY);
|
||||
|
||||
public static boolean isFileIndexed(VirtualFile file, ID<?, ?> indexName, final long indexCreationStamp) {
|
||||
try {
|
||||
return getIndexStamp(file, indexName) == indexCreationStamp;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
final Throwable cause = e.getCause();
|
||||
if (!(cause instanceof IOException)) {
|
||||
throw e; // in case of IO exceptions consider file unindexed
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static long getIndexStamp(VirtualFile file, ID<?, ?> indexName) {
|
||||
synchronized (file) {
|
||||
Timestamps stamp = createOrGetTimeStamp(file);
|
||||
if (stamp != null) return stamp.get(indexName);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static Timestamps createOrGetTimeStamp(VirtualFile file) {
|
||||
if (file instanceof NewVirtualFile && file.isValid()) {
|
||||
Timestamps timestamps = myTimestampsCache.get(file);
|
||||
if (timestamps == null) {
|
||||
synchronized (myTimestampsCache) { // avoid synchroneous reads TODO:
|
||||
timestamps = myTimestampsCache.get(file);
|
||||
if (timestamps == null) {
|
||||
final DataInputStream stream = Timestamps.PERSISTENCE.readAttribute(file);
|
||||
try {
|
||||
timestamps = new Timestamps(stream);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
myTimestampsCache.put(file, timestamps);
|
||||
}
|
||||
}
|
||||
}
|
||||
return timestamps;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void update(final VirtualFile file, final ID<?, ?> indexName, final long indexCreationStamp) {
|
||||
synchronized (file) {
|
||||
try {
|
||||
Timestamps stamp = createOrGetTimeStamp(file);
|
||||
if (stamp != null) stamp.set(indexName, indexCreationStamp);
|
||||
}
|
||||
catch (InvalidVirtualFileAccessException ignored /*ok to ignore it here*/) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void flushCache(@Nullable VirtualFile finishedFile) {
|
||||
if (finishedFile == null || !myFinishedFiles.offer(finishedFile)) {
|
||||
VirtualFile[] files = null;
|
||||
synchronized (myFinishedFiles) {
|
||||
int size = myFinishedFiles.size();
|
||||
if ((finishedFile == null && size > 0) || size == CAPACITY) {
|
||||
files = myFinishedFiles.toArray(new VirtualFile[size]);
|
||||
myFinishedFiles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (files != null) {
|
||||
for(VirtualFile file:files) {
|
||||
synchronized (file) {
|
||||
Timestamps timestamp = myTimestampsCache.remove(file);
|
||||
if (timestamp == null) continue;
|
||||
synchronized (myTimestampsCache) {
|
||||
try {
|
||||
if (timestamp.isDirty() && file.isValid()) {
|
||||
final DataOutputStream sink = Timestamps.PERSISTENCE.writeAttribute(file);
|
||||
timestamp.writeToStream(sink);
|
||||
sink.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (finishedFile != null) myFinishedFiles.offer(finishedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* 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.intellij.util.indexing;
|
||||
|
||||
import com.intellij.openapi.vfs.InvalidVirtualFileAccessException;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.FileAttribute;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
|
||||
import com.intellij.util.containers.ConcurrentHashMap;
|
||||
import com.intellij.util.io.DataInputOutputUtil;
|
||||
import gnu.trove.TObjectLongHashMap;
|
||||
import gnu.trove.TObjectLongProcedure;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
* Date: Dec 25, 2007
|
||||
*/
|
||||
public class IndexingStamp {
|
||||
private IndexingStamp() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The class is meant to be accessed from synchronized block only
|
||||
*/
|
||||
private static class Timestamps {
|
||||
private static final FileAttribute PERSISTENCE = new FileAttribute("__index_stamps__", 1, false);
|
||||
private TObjectLongHashMap<ID<?, ?>> myIndexStamps;
|
||||
private boolean myIsDirty = false;
|
||||
|
||||
private Timestamps(@Nullable DataInputStream stream) throws IOException {
|
||||
if (stream != null) {
|
||||
try {
|
||||
|
||||
long dominatingIndexStamp = DataInputOutputUtil.readTIME(stream);
|
||||
while(stream.available() > 0) {
|
||||
ID<?, ?> id = ID.findById(DataInputOutputUtil.readINT(stream));
|
||||
if (id != null) {
|
||||
long stamp = IndexInfrastructure.getIndexCreationStamp(id);
|
||||
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<ID<?, ?>>(5, 0.98f);
|
||||
if (stamp <= dominatingIndexStamp) myIndexStamps.put(id, stamp);
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeToStream(final DataOutputStream stream) throws IOException {
|
||||
if (myIndexStamps != null && !myIndexStamps.isEmpty()) {
|
||||
final long[] dominatingIndexStamp = new long[1];
|
||||
myIndexStamps.forEachEntry(
|
||||
new TObjectLongProcedure<ID<?, ?>>() {
|
||||
@Override
|
||||
public boolean execute(ID<?, ?> a, long b) {
|
||||
dominatingIndexStamp[0] = Math.max(dominatingIndexStamp[0], b);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
);
|
||||
DataInputOutputUtil.writeTIME(stream, dominatingIndexStamp[0]);
|
||||
myIndexStamps.forEachEntry(new TObjectLongProcedure<ID<?, ?>>() {
|
||||
@Override
|
||||
public boolean execute(final ID<?, ?> id, final long timestamp) {
|
||||
try {
|
||||
DataInputOutputUtil.writeINT(stream, id.getUniqueId());
|
||||
return true;
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
DataInputOutputUtil.writeTIME(stream, DataInputOutputUtil.timeBase);
|
||||
}
|
||||
}
|
||||
|
||||
public long get(ID<?, ?> id) {
|
||||
return myIndexStamps != null? myIndexStamps.get(id) : 0L;
|
||||
}
|
||||
|
||||
public void set(ID<?, ?> id, long tmst) {
|
||||
try {
|
||||
if (tmst < 0) {
|
||||
if (myIndexStamps == null) return;
|
||||
myIndexStamps.remove(id);
|
||||
return;
|
||||
}
|
||||
if (myIndexStamps == null) myIndexStamps = new TObjectLongHashMap<ID<?, ?>>(5, 0.98f);
|
||||
|
||||
myIndexStamps.put(id, tmst);
|
||||
}
|
||||
finally {
|
||||
myIsDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isDirty() {
|
||||
return myIsDirty;
|
||||
}
|
||||
}
|
||||
|
||||
private static final ConcurrentHashMap<VirtualFile, Timestamps> myTimestampsCache = new ConcurrentHashMap<VirtualFile, Timestamps>();
|
||||
private static final int CAPACITY = 100;
|
||||
private static final ArrayBlockingQueue<VirtualFile> myFinishedFiles = new ArrayBlockingQueue<VirtualFile>(CAPACITY);
|
||||
|
||||
public static boolean isFileIndexed(VirtualFile file, ID<?, ?> indexName, final long indexCreationStamp) {
|
||||
try {
|
||||
return getIndexStamp(file, indexName) == indexCreationStamp;
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
final Throwable cause = e.getCause();
|
||||
if (!(cause instanceof IOException)) {
|
||||
throw e; // in case of IO exceptions consider file unindexed
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static long getIndexStamp(VirtualFile file, ID<?, ?> indexName) {
|
||||
synchronized (file) {
|
||||
Timestamps stamp = createOrGetTimeStamp(file);
|
||||
if (stamp != null) return stamp.get(indexName);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static Timestamps createOrGetTimeStamp(VirtualFile file) {
|
||||
if (file instanceof NewVirtualFile && file.isValid()) {
|
||||
Timestamps timestamps = myTimestampsCache.get(file);
|
||||
if (timestamps == null) {
|
||||
synchronized (myTimestampsCache) { // avoid synchroneous reads TODO:
|
||||
timestamps = myTimestampsCache.get(file);
|
||||
if (timestamps == null) {
|
||||
final DataInputStream stream = Timestamps.PERSISTENCE.readAttribute(file);
|
||||
try {
|
||||
timestamps = new Timestamps(stream);
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
myTimestampsCache.put(file, timestamps);
|
||||
}
|
||||
}
|
||||
}
|
||||
return timestamps;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void update(final VirtualFile file, final ID<?, ?> indexName, final long indexCreationStamp) {
|
||||
synchronized (file) {
|
||||
try {
|
||||
Timestamps stamp = createOrGetTimeStamp(file);
|
||||
if (stamp != null) stamp.set(indexName, indexCreationStamp);
|
||||
}
|
||||
catch (InvalidVirtualFileAccessException ignored /*ok to ignore it here*/) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void flushCache(@Nullable VirtualFile finishedFile) {
|
||||
if (finishedFile == null || !myFinishedFiles.offer(finishedFile)) {
|
||||
VirtualFile[] files = null;
|
||||
synchronized (myFinishedFiles) {
|
||||
int size = myFinishedFiles.size();
|
||||
if ((finishedFile == null && size > 0) || size == CAPACITY) {
|
||||
files = myFinishedFiles.toArray(new VirtualFile[size]);
|
||||
myFinishedFiles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (files != null) {
|
||||
for(VirtualFile file:files) {
|
||||
synchronized (file) {
|
||||
Timestamps timestamp = myTimestampsCache.remove(file);
|
||||
if (timestamp == null) continue;
|
||||
synchronized (myTimestampsCache) {
|
||||
try {
|
||||
if (timestamp.isDirty() && file.isValid()) {
|
||||
final DataOutputStream sink = Timestamps.PERSISTENCE.writeAttribute(file);
|
||||
timestamp.writeToStream(sink);
|
||||
sink.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (finishedFile != null) myFinishedFiles.offer(finishedFile);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user