From 4e077068bf741707e35ccbf63c3cf1585f1b08ea Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Mon, 10 Nov 2014 18:37:15 +0300 Subject: [PATCH] [log] IDEA-132229 Optimize HashImpl serialization * Read/write bytes, don't convert from/to String. * Introduce VcsLogHashMap versioning, cleanup previous version on start. --- .../intellij/vcs/log/data/VcsLogHashMap.java | 16 +++-- .../com/intellij/vcs/log/impl/HashImpl.java | 17 +++++ .../vcs/log/impl/HashSerializeTest.java | 70 +++++++++++++++++++ 3 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 platform/vcs-log/impl/test/com/intellij/vcs/log/impl/HashSerializeTest.java diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java index a2fe8792c759..6787de3058d9 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/data/VcsLogHashMap.java @@ -54,18 +54,24 @@ public class VcsLogHashMap implements Disposable { private static final File LOG_CACHE_APP_DIR = new File(PathManager.getSystemPath(), "vcs-log"); private static final Logger LOG = Logger.getInstance(VcsLogHashMap.class); + private static final int VERSION = 1; private final PersistentEnumerator myPersistentEnumerator; VcsLogHashMap(@NotNull Project project, @NotNull Map logProviders) throws IOException { - final File myMapFile = new File(LOG_CACHE_APP_DIR, calcLogId(project, logProviders)); + String logId = calcLogId(project, logProviders); + final File mapFile = new File(LOG_CACHE_APP_DIR, logId + "." + VERSION); + if (!mapFile.exists()) { + IOUtil.deleteAllFilesStartingWith(new File(LOG_CACHE_APP_DIR, logId)); + } + Disposer.register(project, this); myPersistentEnumerator = IOUtil.openCleanOrResetBroken(new ThrowableComputable, IOException>() { @Override public PersistentEnumerator compute() throws IOException { - return new PersistentEnumerator(myMapFile, new MyHashKeyDescriptor(), Page.PAGE_SIZE); + return new PersistentEnumerator(mapFile, new MyHashKeyDescriptor(), Page.PAGE_SIZE); } - }, myMapFile); + }, mapFile); } @NotNull @@ -189,12 +195,12 @@ public class VcsLogHashMap implements Disposable { private static class MyHashKeyDescriptor implements KeyDescriptor { @Override public void save(@NotNull DataOutput out, Hash value) throws IOException { - out.writeUTF(value.asString()); + ((HashImpl)value).write(out); } @Override public Hash read(@NotNull DataInput in) throws IOException { - return HashImpl.build(in.readUTF()); + return HashImpl.read(in); } @Override diff --git a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/HashImpl.java b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/HashImpl.java index 82db30cbe613..c4539cfdf4eb 100644 --- a/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/HashImpl.java +++ b/platform/vcs-log/impl/src/com/intellij/vcs/log/impl/HashImpl.java @@ -15,9 +15,13 @@ */ package com.intellij.vcs.log.impl; +import com.intellij.util.io.DataInputOutputUtil; import com.intellij.vcs.log.Hash; import org.jetbrains.annotations.NotNull; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; import java.util.Arrays; /** @@ -37,6 +41,19 @@ public class HashImpl implements Hash { return new HashImpl(data); } + @NotNull + public static Hash read(@NotNull DataInput in) throws IOException { + int length = DataInputOutputUtil.readINT(in); + byte[] buf = new byte[length]; + in.readFully(buf); + return new HashImpl(buf); + } + + public void write(@NotNull DataOutput out) throws IOException { + DataInputOutputUtil.writeINT(out, myData.length); + out.write(myData); + } + @NotNull private static byte[] buildData(@NotNull String inputStr) { // if length == 5, need 3 byte + 1 signal byte diff --git a/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/HashSerializeTest.java b/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/HashSerializeTest.java new file mode 100644 index 000000000000..af8c703e1811 --- /dev/null +++ b/platform/vcs-log/impl/test/com/intellij/vcs/log/impl/HashSerializeTest.java @@ -0,0 +1,70 @@ +/* + * Copyright 2000-2014 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.vcs.log.impl; + +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.util.io.DataOutputStream; +import org.jetbrains.annotations.NotNull; +import org.junit.Test; + +import java.io.*; + +import static org.junit.Assert.assertEquals; + +public class HashSerializeTest { + + @Test + public void full_hash() throws IOException { + HashImpl hash = (HashImpl)HashImpl.build("d35ee91fad4a04bce0ea91a762cc8f3bf3e1929f"); + File file = writeToTempFile(hash); + HashImpl newHash = readFromFile(file); + assertEquals(hash, newHash); + } + + @Test + public void short_hash() throws IOException { + HashImpl hash = (HashImpl)HashImpl.build("d35ee91"); + File file = writeToTempFile(hash); + HashImpl newHash = readFromFile(file); + assertEquals(hash, newHash); + } + + @NotNull + private static File writeToTempFile(@NotNull HashImpl hash) throws IOException { + File file = FileUtil.createTempFile("", ""); + DataOutputStream out = new DataOutputStream(new FileOutputStream(file)); + try { + hash.write(out); + } + finally { + out.close(); + } + return file; + } + + @NotNull + private static HashImpl readFromFile(@NotNull File file) throws IOException { + HashImpl newHash; + DataInputStream in = new DataInputStream(new FileInputStream(file)); + try { + newHash = (HashImpl)HashImpl.read(in); + } + finally { + in.close(); + } + return newHash; + } +}