DOM stubs: stub serialization decoupled from PSI

This commit is contained in:
Dmitry Avdeev
2012-08-06 13:58:26 +04:00
parent 0bf3c2fab0
commit 12f5fa9fff
14 changed files with 121 additions and 33 deletions
@@ -0,0 +1,35 @@
/*
* Copyright 2000-2012 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.psi.stubs;
import org.jetbrains.annotations.NonNls;
import java.io.IOException;
/**
* @author Dmitry Avdeev
* Date: 8/2/12
*/
public interface ObjectStubSerializer<T extends Stub, P extends Stub> {
@NonNls
String getExternalId();
void serialize(T stub, StubOutputStream dataStream) throws IOException;
T deserialize(StubInputStream dataStream, final P parentStub) throws IOException;
void indexStub(T stub, IndexSink sink);
}
@@ -0,0 +1,30 @@
/*
* Copyright 2000-2012 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.psi.stubs;
import java.util.List;
/**
* @author Dmitry Avdeev
* Date: 8/2/12
*/
public interface Stub {
Stub getParentStub();
List<? extends Stub> getChildrenStubs();
ObjectStubSerializer getStubType();
}
@@ -27,7 +27,7 @@ import org.jetbrains.annotations.Nullable;
import java.util.List;
public interface StubElement<T extends PsiElement> {
public interface StubElement<T extends PsiElement> extends Stub {
IStubElementType getStubType();
StubElement getParentStub();
List<StubElement> getChildrenStubs();
@@ -42,36 +42,36 @@ import java.util.concurrent.locks.Lock;
public class StubSerializationHelper {
private AbstractStringEnumerator myNameStorage;
protected final TIntObjectHashMap<StubSerializer<? extends StubElement>> myIdToSerializer = new TIntObjectHashMap<StubSerializer<? extends StubElement>>();
protected final TObjectIntHashMap<StubSerializer<? extends StubElement>> mySerializerToId = new TObjectIntHashMap<StubSerializer<? extends StubElement>>();
protected final TIntObjectHashMap<ObjectStubSerializer> myIdToSerializer = new TIntObjectHashMap<ObjectStubSerializer>();
protected final TObjectIntHashMap<ObjectStubSerializer> mySerializerToId = new TObjectIntHashMap<ObjectStubSerializer>();
public StubSerializationHelper(AbstractStringEnumerator nameStorage) {
myNameStorage = nameStorage;
}
public void assignId(@NotNull final StubSerializer<? extends StubElement> serializer) throws IOException {
public void assignId(@NotNull final ObjectStubSerializer serializer) throws IOException {
final int id = persistentId(serializer);
final StubSerializer old = myIdToSerializer.put(id, serializer);
final ObjectStubSerializer old = myIdToSerializer.put(id, serializer);
assert old == null : "ID: " + serializer.getExternalId() + " is not unique; Already registered serializer with this ID: " + old.getClass().getName();
final int oldId = mySerializerToId.put(serializer, id);
assert oldId == 0 : "Serializer " + serializer + " is already registered; Old ID:" + oldId;
}
private int persistentId(@NotNull final StubSerializer<? extends StubElement> serializer) throws IOException {
private int persistentId(@NotNull final ObjectStubSerializer serializer) throws IOException {
if (myNameStorage == null) {
throw new IOException("SerializationManager's name storage failed to initialize");
}
return myNameStorage.enumerate(serializer.getExternalId());
}
private void doSerialize(final StubElement rootStub, final StubOutputStream stream) throws IOException {
final StubSerializer serializer = StubSerializationUtil.getSerializer(rootStub);
private void doSerialize(final Stub rootStub, final StubOutputStream stream) throws IOException {
final ObjectStubSerializer serializer = StubSerializationUtil.getSerializer(rootStub);
DataInputOutputUtil.writeINT(stream, getClassId(serializer));
serializer.serialize(rootStub, stream);
final List<StubElement> children = rootStub.getChildrenStubs();
final List<? extends Stub> children = rootStub.getChildrenStubs();
final int childrenSize = children.size();
DataInputOutputUtil.writeINT(stream, childrenSize);
for (int i = 0; i < childrenSize; ++i) {
@@ -79,7 +79,7 @@ public class StubSerializationHelper {
}
}
public void serialize(StubElement rootStub, OutputStream stream) throws IOException {
public void serialize(Stub rootStub, OutputStream stream) throws IOException {
BufferExposingByteArrayOutputStream out = new BufferExposingByteArrayOutputStream();
FileLocalStringEnumerator storage = new FileLocalStringEnumerator();
StubOutputStream stubOutputStream = new StubOutputStream(out, storage);
@@ -94,7 +94,7 @@ public class StubSerializationHelper {
resultStream.write(out.getInternalBuffer(), 0, out.size());
}
private int getClassId(final StubSerializer serializer) {
private int getClassId(final ObjectStubSerializer serializer) {
final int idValue = mySerializerToId.get(serializer);
assert idValue != 0: "No ID found for serializer " + LogUtil.objectAndClass(serializer);
return idValue;
@@ -152,7 +152,7 @@ public class StubSerializationHelper {
private final RecentStringInterner myStringInterner = new RecentStringInterner(8192);
public StubElement deserialize(InputStream stream) throws IOException {
public Stub deserialize(InputStream stream) throws IOException {
FileLocalStringEnumerator storage = new FileLocalStringEnumerator();
StubInputStream inputStream = new StubInputStream(stream, storage);
final int size = DataInputOutputUtil.readINT(inputStream);
@@ -168,13 +168,13 @@ public class StubSerializationHelper {
return deserialize(inputStream, null);
}
private StubElement deserialize(StubInputStream stream, StubElement parentStub) throws IOException {
private Stub deserialize(StubInputStream stream, Stub parentStub) throws IOException {
final int id = DataInputOutputUtil.readINT(stream);
final StubSerializer serializer = getClassById(id);
final ObjectStubSerializer serializer = getClassById(id);
assert serializer != null : "No serializer registered for stub: ID=" + id + "; parent stub class=" + (parentStub != null? parentStub.getClass().getName() : "null");
StubElement stub = serializer.deserialize(stream, parentStub);
Stub stub = serializer.deserialize(stream, parentStub);
int childCount = DataInputOutputUtil.readINT(stream);
for (int i = 0; i < childCount; i++) {
deserialize(stream, stub);
@@ -183,7 +183,7 @@ public class StubSerializationHelper {
}
private StubSerializer getClassById(int id) {
private ObjectStubSerializer getClassById(int id) {
return myIdToSerializer.get(id);
}
@@ -21,7 +21,7 @@ package com.intellij.psi.stubs;
public abstract class StubSerializationUtil {
private StubSerializationUtil() {}
public static StubSerializer getSerializer(StubElement rootStub) {
public static ObjectStubSerializer getSerializer(Stub rootStub) {
if (rootStub instanceof PsiFileStub) {
final PsiFileStub fileStub = (PsiFileStub)rootStub;
return fileStub.getType();
@@ -22,7 +22,7 @@ import java.io.IOException;
/*
* @author max
*/
public interface StubSerializer<T extends StubElement> {
public interface StubSerializer<T extends StubElement> extends ObjectStubSerializer<T, StubElement> {
@NonNls
String getExternalId();
@@ -45,7 +45,7 @@ public class CoreStubTreeLoader extends StubTreeLoader {
try {
final FileContent fc = new FileContentImpl(vFile, vFile.contentsToByteArray());
fc.putUserData(IndexingDataKeys.PROJECT, project);
final StubElement element = StubTreeBuilder.buildStubTree(fc);
final Stub element = StubTreeBuilder.buildStubTree(fc);
if (element instanceof PsiFileStub) {
return new StubTree((PsiFileStub)element);
}
@@ -29,14 +29,14 @@ import com.intellij.util.indexing.SubstitutedFileType;
import org.jetbrains.annotations.Nullable;
public class StubTreeBuilder {
private static final Key<StubElement> stubElementKey = Key.create("stub.tree.for.file.content");
private static final Key<Stub> stubElementKey = Key.create("stub.tree.for.file.content");
private StubTreeBuilder() {
}
@Nullable
public static StubElement buildStubTree(final FileContent inputData) {
StubElement data = inputData.getUserData(stubElementKey);
public static Stub buildStubTree(final FileContent inputData) {
Stub data = inputData.getUserData(stubElementKey);
if (data != null) return data;
//noinspection SynchronizationOnLocalVariableOrMethodParameter
@@ -27,9 +27,9 @@ public abstract class SerializationManagerEx extends SerializationManager {
return (SerializationManagerEx) SerializationManager.getInstance();
}
public abstract void serialize(StubElement rootStub, OutputStream stream);
public abstract void serialize(Stub rootStub, OutputStream stream);
public abstract StubElement deserialize(InputStream stream);
public abstract Stub deserialize(InputStream stream);
public abstract boolean isNameStorageCorrupted();
@@ -146,7 +146,7 @@ public class SerializationManagerImpl extends SerializationManagerEx implements
public void serialize(StubElement rootStub, OutputStream stream) {
public void serialize(Stub rootStub, OutputStream stream) {
initSerializers();
try {
myStubSerializationHelper.serialize(rootStub, stream);
@@ -158,7 +158,7 @@ public class SerializationManagerImpl extends SerializationManagerEx implements
}
public StubElement deserialize(InputStream stream) {
public Stub deserialize(InputStream stream) {
initSerializers();
try {
@@ -30,9 +30,9 @@ import java.io.IOException;
public class SerializedStubTree {
private final byte[] myBytes;
private final int myLength;
private StubElement myStubElement;
private Stub myStubElement;
public SerializedStubTree(final byte[] bytes, int length, @Nullable StubElement stubElement) {
public SerializedStubTree(final byte[] bytes, int length, @Nullable Stub stubElement) {
myBytes = bytes;
myLength = length;
myStubElement = stubElement;
@@ -48,8 +48,8 @@ public class SerializedStubTree {
}
// willIndexStub is one time optimization hint, once can safely pass false
public StubElement getStub(boolean willIndexStub) {
StubElement stubElement = myStubElement;
public Stub getStub(boolean willIndexStub) {
Stub stubElement = myStubElement;
if (stubElement != null) {
// not null myStubElement means we just built SerializedStubTree for indexing,
// if we request stub for indexing we can safely use it
@@ -60,7 +60,7 @@ public class StubTreeLoaderImpl extends StubTreeLoader {
}
psiFile.putUserData(PsiFileImpl.BUILDING_STUB, true);
}
StubElement element;
Stub element;
try {
element = StubTreeBuilder.buildStubTree(fc);
}
@@ -94,7 +94,7 @@ public class StubTreeLoaderImpl extends StubTreeLoader {
final int size = datas.size();
if (size == 1) {
StubElement stub = datas.get(0).getStub(false);
Stub stub = datas.get(0).getStub(false);
return new StubTree((PsiFileStub)stub);
}
else if (size != 0) {
@@ -118,7 +118,7 @@ public class StubUpdatingIndex extends CustomImplementationFileBasedIndexExtensi
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
final StubElement rootStub = StubTreeBuilder.buildStubTree(inputData);
final Stub rootStub = StubTreeBuilder.buildStubTree(inputData);
if (rootStub == null) return;
final BufferExposingByteArrayOutputStream bytes = new BufferExposingByteArrayOutputStream();
@@ -0,0 +1,23 @@
/*
* Copyright 2000-2012 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.xml.stubs;
/**
* @author Dmitry Avdeev
* Date: 8/2/12
*/
public class DomStubElement {
}