local history: storage bug fixed (hopefully) + some logging and storage checking in internal mode

IO: storage classes cleanup
This commit is contained in:
Anton Makeev
2010-09-24 16:39:24 +04:00
parent 06924e448d
commit cfd2044924
44 changed files with 146 additions and 165 deletions
@@ -21,9 +21,7 @@ import com.intellij.history.core.changes.Change;
import com.intellij.history.core.changes.ChangeSet;
import com.intellij.history.core.changes.ChangeVisitor;
import com.intellij.history.core.changes.ContentChange;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.RootEntry;
import com.intellij.history.integration.IdeaGateway;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
@@ -20,7 +20,6 @@ import com.intellij.history.Clock;
import com.intellij.history.core.changes.Change;
import com.intellij.history.core.changes.ChangeSet;
import com.intellij.history.core.changes.ChangeVisitor;
import com.intellij.history.core.storage.Content;
import com.intellij.history.utils.LocalHistoryLog;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.util.Consumer;
@@ -36,13 +35,13 @@ public class ChangeList {
private int myChangeSetDepth;
private ChangeSet myCurrentChangeSet;
private int myIntervalBetweenActivities = 12 * 60 * 60 * 1000; // one day
private int myIntervalBetweenActivities = 12 * 60 * 60 * 1000; // 12 hours
public ChangeList(ChangeListStorage storage) {
myStorage = storage;
}
public synchronized void save() {
public synchronized void flush() {
myStorage.flush();
}
@@ -27,12 +27,13 @@ import com.intellij.util.io.storage.AbstractStorage;
import java.io.DataInputStream;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
public class ChangeListStorageImpl implements ChangeListStorage {
private static final int VERSION = 4;
private static final int VERSION = 5;
private static final String STORAGE_FILE = "changes";
private final LinkedStorage myStorage;
private final LocalHistoryStorage myStorage;
public ChangeListStorageImpl(File storageDir) {
try {
@@ -43,22 +44,26 @@ public class ChangeListStorageImpl implements ChangeListStorage {
}
}
private static LinkedStorage createStorage(File storageDir) throws IOException {
private static LocalHistoryStorage createStorage(File storageDir) throws IOException {
String path = storageDir.getPath() + "/" + STORAGE_FILE;
LinkedStorage result = new LinkedStorage(path);
LocalHistoryStorage result = new LocalHistoryStorage(path);
long fsTimestamp = ((PersistentFS)ManagingFS.getInstance()).getCreationTimestamp();
boolean versionMismatch = result.getVersion() != VERSION;
int storedVersion = result.getVersion();
boolean versionMismatch = storedVersion != VERSION;
boolean timestampMismatch = result.getFSTimestamp() != fsTimestamp;
if (versionMismatch || timestampMismatch) {
if (versionMismatch) LocalHistoryLog.LOG.info("local history version mismatch, rebuilding...");
if (timestampMismatch) LocalHistoryLog.LOG.info("FS has been rebuild, rebuilding clearing local history...");
if (versionMismatch) {
LocalHistoryLog.LOG.info(MessageFormat.format(
"local history version mismatch (was: {0}, expected: {1}), rebuilding...", storedVersion, VERSION));
}
if (timestampMismatch) LocalHistoryLog.LOG.info("FS has been rebuild, rebuilding local history...");
result.dispose();
if (!FileUtil.delete(storageDir)) {
throw new IOException("cannot clear storage dir: " + storageDir);
}
result = new LinkedStorage(path);
result = new LocalHistoryStorage(path);
result.setVersion(VERSION);
result.setFSTimestamp(fsTimestamp);
}
@@ -74,7 +79,7 @@ public class ChangeListStorageImpl implements ChangeListStorage {
catch (Throwable ex) {
LocalHistoryLog.LOG.error("cannot mark storage as broken", ex);
}
throw new RuntimeException(e);
throw new RuntimeException("Local history is broken and will be rebuilt after restart (storage version: " + VERSION + ")", e);
}
public synchronized void close() {
@@ -128,8 +133,9 @@ public class ChangeListStorageImpl implements ChangeListStorage {
try {
while (eachBlockId != 0) {
processor.consume(doReadBlock(eachBlockId).changeSet);
myStorage.deleteRecord(eachBlockId);
int toDelete = eachBlockId;
eachBlockId = myStorage.getPrevRecord(eachBlockId);
myStorage.deleteRecord(toDelete);
}
}
catch (IOException e) {
@@ -149,6 +155,7 @@ public class ChangeListStorageImpl implements ChangeListStorage {
long delta = prevTimestamp - t;
prevTimestamp = t;
// we sum only intervals between changes during one 'day' (intervalBetweenActivities) and add '1' between two 'days'
length += delta < intervalBetweenActivities ? delta : 1;
if (length >= period) return last;
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.intellij.history.core.storage;
package com.intellij.history.core;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.integration.IdeaGateway;
@@ -18,10 +18,9 @@ package com.intellij.history.core;
import com.intellij.history.ByteContent;
import com.intellij.history.core.changes.*;
import com.intellij.history.core.revisions.ChangeRevision;
import com.intellij.history.core.revisions.RecentChange;
import com.intellij.history.core.revisions.Revision;
import com.intellij.history.core.revisions.ChangeRevision;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.RootEntry;
import com.intellij.openapi.Disposable;
@@ -15,14 +15,13 @@
*/
package com.intellij.history.core;
import com.intellij.openapi.components.impl.stores.StorageUtil;
import com.intellij.util.io.PagePool;
import com.intellij.util.io.storage.AbstractRecordsTable;
import java.io.File;
import java.io.IOException;
public class LinkedRecordsTable extends AbstractRecordsTable {
public class LocalHistoryRecordsTable extends AbstractRecordsTable {
private static final int VERSION = 4;
private static final int ID_COUNTER_OFFSET = DEFAULT_HEADER_SIZE;
@@ -38,7 +37,7 @@ public class LinkedRecordsTable extends AbstractRecordsTable {
private static final int RECORD_SIZE = TIMESTAMP_OFFSET + 8;
private static final byte[] ZEROS = new byte[RECORD_SIZE];
public LinkedRecordsTable(final File storageFilePath, final PagePool pool) throws IOException {
public LocalHistoryRecordsTable(final File storageFilePath, final PagePool pool) throws IOException {
super(storageFilePath, pool);
}
@@ -62,11 +61,11 @@ public class LinkedRecordsTable extends AbstractRecordsTable {
return ZEROS;
}
@Override
protected void clearDeletedRecord(int record) {
setTimestamp(record, 0);
setNextRecord(record, 0);
setPrevRecord(record, 0);
public long nextId() {
markDirty();
long result = myStorage.getLong(ID_COUNTER_OFFSET);
myStorage.putLong(ID_COUNTER_OFFSET, result + 1);
return result;
}
public void setFSTimestamp(long timestamp) {
@@ -122,12 +121,5 @@ public class LinkedRecordsTable extends AbstractRecordsTable {
public long getTimestamp(int record) {
return myStorage.getLong(getOffset(record, TIMESTAMP_OFFSET));
}
public long nextId() {
markDirty();
long result = myStorage.getLong(ID_COUNTER_OFFSET);
myStorage.putLong(ID_COUNTER_OFFSET, result + 1);
return result;
}
}
@@ -23,71 +23,71 @@ import com.intellij.util.io.storage.AbstractStorage;
import java.io.File;
import java.io.IOException;
public class LinkedStorage extends AbstractStorage {
public LinkedStorage(String storageFilePath) throws IOException {
public class LocalHistoryStorage extends AbstractStorage {
public LocalHistoryStorage(String storageFilePath) throws IOException {
super(storageFilePath);
}
public LinkedStorage(String storageFilePath, PagePool pool) throws IOException {
public LocalHistoryStorage(String storageFilePath, PagePool pool) throws IOException {
super(storageFilePath, pool);
}
@Override
protected AbstractRecordsTable createRecordsTable(PagePool pool, File recordsFile) throws IOException {
return new LinkedRecordsTable(recordsFile, pool);
return new LocalHistoryRecordsTable(recordsFile, pool);
}
public long getFSTimestamp() {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getFSTimestamp();
return ((LocalHistoryRecordsTable)myRecordsTable).getFSTimestamp();
}
}
public void setFSTimestamp(long timestamp) {
synchronized (myLock) {
((LinkedRecordsTable)myRecordsTable).setFSTimestamp(timestamp);
((LocalHistoryRecordsTable)myRecordsTable).setFSTimestamp(timestamp);
}
}
public long nextId() {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).nextId();
return ((LocalHistoryRecordsTable)myRecordsTable).nextId();
}
}
public int getFirstRecord() {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getFirstRecord();
return ((LocalHistoryRecordsTable)myRecordsTable).getFirstRecord();
}
}
public int getLastRecord() {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getLastRecord();
return ((LocalHistoryRecordsTable)myRecordsTable).getLastRecord();
}
}
public int getPrevRecord(int record) {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getPrevRecord(record);
return ((LocalHistoryRecordsTable)myRecordsTable).getPrevRecord(record);
}
}
public int getNextRecord(int record) {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getNextRecord(record);
return ((LocalHistoryRecordsTable)myRecordsTable).getNextRecord(record);
}
}
public long getTimestamp(int record) {
synchronized (myLock) {
return ((LinkedRecordsTable)myRecordsTable).getTimestamp(record);
return ((LocalHistoryRecordsTable)myRecordsTable).getTimestamp(record);
}
}
public int createNextRecord() throws IOException {
synchronized (myLock) {
LinkedRecordsTable table = (LinkedRecordsTable)myRecordsTable;
LocalHistoryRecordsTable table = (LocalHistoryRecordsTable)myRecordsTable;
int id = table.createNewRecord();
int prev = table.getLastRecord();
@@ -108,7 +108,7 @@ public class LinkedStorage extends AbstractStorage {
public void deleteRecord(int id) throws IOException {
synchronized (myLock) {
LinkedRecordsTable table = (LinkedRecordsTable)myRecordsTable;
LocalHistoryRecordsTable table = (LocalHistoryRecordsTable)myRecordsTable;
int prev = table.getPrevRecord(id);
int next = table.getNextRecord(id);
@@ -14,7 +14,7 @@
* limitations under the License.
*/
package com.intellij.history.core.storage;
package com.intellij.history.core;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
@@ -14,12 +14,14 @@
* limitations under the License.
*/
package com.intellij.history.core.storage;
package com.intellij.history.core;
import com.intellij.history.core.changes.*;
import com.intellij.history.core.tree.DirectoryEntry;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.FileEntry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.DataInput;
import java.io.DataOutput;
@@ -95,20 +97,22 @@ public class StreamUtil {
change.write(out);
}
@NotNull
public static String readString(DataInput in) throws IOException {
return in.readUTF();
}
public static void writeString(DataOutput out, String s) throws IOException {
public static void writeString(DataOutput out, @NotNull String s) throws IOException {
out.writeUTF(s);
}
@Nullable
public static String readStringOrNull(DataInput in) throws IOException {
if (!in.readBoolean()) return null;
return readString(in);
}
public static void writeStringOrNull(DataOutput out, String s) throws IOException {
public static void writeStringOrNull(DataOutput out, @Nullable String s) throws IOException {
out.writeBoolean(s != null);
if (s != null) writeString(out, s);
}
@@ -16,7 +16,7 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.Content;
import java.io.DataInput;
import java.io.DataOutput;
@@ -16,8 +16,8 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.storage.StreamUtil;
import com.intellij.history.core.Content;
import com.intellij.history.core.StreamUtil;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.Nullable;
@@ -30,7 +30,7 @@ import java.util.List;
public class ChangeSet {
private final long myId;
private String myName;
@Nullable private String myName;
private final long myTimestamp;
private final List<Change> myChanges;
@@ -63,10 +63,11 @@ public class ChangeSet {
}
}
public void setName(String name) {
public void setName(@Nullable String name) {
myName = name;
}
@Nullable
public String getName() {
return myName;
}
@@ -16,8 +16,8 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.storage.StoredContent;
import com.intellij.history.core.Content;
import com.intellij.history.core.StoredContent;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.RootEntry;
@@ -39,7 +39,7 @@ public class ContentChange extends StructuralChange {
public ContentChange(DataInput in) throws IOException {
super(in);
myOldContent = new StoredContent(in.readInt());
myOldContent = new StoredContent(in);
myOldTimestamp = in.readLong();
}
@@ -16,8 +16,6 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.storage.StreamUtil;
import java.io.DataInput;
import java.io.IOException;
@@ -16,8 +16,6 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.storage.StreamUtil;
import java.io.DataInput;
import java.io.IOException;
@@ -16,9 +16,9 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.Content;
import com.intellij.history.core.Paths;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.storage.StreamUtil;
import com.intellij.history.core.StreamUtil;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.RootEntry;
@@ -17,7 +17,7 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.Paths;
import com.intellij.history.core.storage.StreamUtil;
import com.intellij.history.core.StreamUtil;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.RootEntry;
@@ -16,8 +16,8 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.storage.StreamUtil;
import com.intellij.history.core.Content;
import com.intellij.history.core.StreamUtil;
import org.jetbrains.annotations.NotNull;
import java.io.DataInput;
@@ -28,8 +28,8 @@ import java.util.List;
import java.util.regex.Pattern;
public class PutLabelChange extends Change {
private final String myName;
private final String myProjectId;
@NotNull private final String myName;
@NotNull private final String myProjectId;
public PutLabelChange(long id, @NotNull String name, @NotNull String projectId) {
super(id);
@@ -50,10 +50,12 @@ public class PutLabelChange extends Change {
StreamUtil.writeString(out, myProjectId);
}
@NotNull
public String getName() {
return myName;
}
@NotNull
public String getProjectId() {
return myProjectId;
}
@@ -17,7 +17,7 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.Paths;
import com.intellij.history.core.storage.StreamUtil;
import com.intellij.history.core.StreamUtil;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.RootEntry;
@@ -16,9 +16,9 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.Content;
import com.intellij.history.core.Paths;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.storage.StreamUtil;
import com.intellij.history.core.StreamUtil;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.RootEntry;
import com.intellij.history.utils.LocalHistoryLog;
@@ -1,27 +0,0 @@
/*
* 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.history.core.storage;
// todo this class is needed only becase we cannot create IOException with cause - it will be possible in java 1.6
public class BrokenStorageException extends Exception {
public BrokenStorageException() {
}
public BrokenStorageException(Throwable e) {
super(e);
}
}
@@ -16,8 +16,8 @@
package com.intellij.history.core.tree;
import com.intellij.history.core.StreamUtil;
import com.intellij.history.core.revisions.Difference;
import com.intellij.history.core.storage.StreamUtil;
import com.intellij.history.utils.LocalHistoryLog;
import java.io.DataInput;
@@ -26,8 +26,6 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import static java.lang.String.format;
public class DirectoryEntry extends Entry {
private final ArrayList<Entry> myChildren;
@@ -36,7 +34,7 @@ public class DirectoryEntry extends Entry {
myChildren = new ArrayList<Entry>(3);
}
public DirectoryEntry(DataInput in, boolean dummy /* to distinguish from general contructor*/) throws IOException {
public DirectoryEntry(DataInput in, boolean dummy /* to distinguish from general constructor*/) throws IOException {
super(in);
int count = in.readInt();
myChildren = new ArrayList<Entry>(count);
@@ -16,10 +16,10 @@
package com.intellij.history.core.tree;
import com.intellij.history.core.Content;
import com.intellij.history.core.Paths;
import com.intellij.history.core.StreamUtil;
import com.intellij.history.core.revisions.Difference;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.storage.StreamUtil;
import com.intellij.util.SmartList;
import java.io.DataInput;
@@ -37,7 +37,6 @@ public abstract class Entry {
public Entry(String name) {
myName = name;
//assert name == null || !name.contains("/");
}
public Entry(DataInput in) throws IOException {
@@ -16,9 +16,9 @@
package com.intellij.history.core.tree;
import com.intellij.history.core.Content;
import com.intellij.history.core.StoredContent;
import com.intellij.history.core.revisions.Difference;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.storage.StoredContent;
import java.io.DataInput;
import java.io.DataOutput;
@@ -37,7 +37,7 @@ public class FileEntry extends Entry {
myContent = content;
}
public FileEntry(DataInput in, boolean dummy /* to distinguish from general contructor*/) throws IOException {
public FileEntry(DataInput in, boolean dummy /* to distinguish from general constructor*/) throws IOException {
super(in);
myTimestamp = in.readLong();
isReadOnly = in.readBoolean();
@@ -17,13 +17,10 @@
package com.intellij.history.core.tree;
import com.intellij.history.core.Paths;
import com.intellij.history.core.storage.StreamUtil;
import java.io.DataOutput;
import java.io.IOException;
import static java.lang.String.format;
public class RootEntry extends DirectoryEntry {
public RootEntry() {
super("");
@@ -17,10 +17,10 @@
package com.intellij.history.integration;
import com.intellij.history.Clock;
import com.intellij.history.core.Content;
import com.intellij.history.core.LocalHistoryFacade;
import com.intellij.history.core.Paths;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.storage.StoredContent;
import com.intellij.history.core.StoredContent;
import com.intellij.history.core.tree.DirectoryEntry;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.FileEntry;
@@ -16,8 +16,8 @@
package com.intellij.history.integration;
import com.intellij.history.core.Content;
import com.intellij.history.core.LocalHistoryFacade;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.tree.Entry;
import com.intellij.openapi.command.CommandEvent;
import com.intellij.openapi.command.CommandListener;
@@ -19,6 +19,7 @@ package com.intellij.history.integration;
import com.intellij.concurrency.JobScheduler;
import com.intellij.history.*;
import com.intellij.history.core.*;
import com.intellij.history.utils.LocalHistoryLog;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.PathManager;
import com.intellij.openapi.application.ex.ApplicationManagerEx;
@@ -60,7 +61,7 @@ public class LocalHistoryImpl extends LocalHistory implements ApplicationCompone
public void initComponent() {
if (!ApplicationManager.getApplication().isUnitTestMode() && ApplicationManager.getApplication().isHeadlessEnvironment()) return;
myShutdownTask = new Runnable() {
public void run() {
disposeComponent();
@@ -86,6 +87,21 @@ public class LocalHistoryImpl extends LocalHistory implements ApplicationCompone
VirtualFileManager fm = VirtualFileManagerEx.getInstance();
fm.addVirtualFileListener(myEventDispatcher);
fm.addVirtualFileManagerListener(myEventDispatcher);
ApplicationManager.getApplication().executeOnPooledThread(new Runnable() {
@Override
public void run() {
validateStorage();
}
});
}
private void validateStorage() {
if (ApplicationManagerEx.getApplicationEx().isInternal() && !ApplicationManager.getApplication().isUnitTestMode()) {
LocalHistoryLog.LOG.info("Checking local history storage...");
myVcs.getChangeListInTests().getChangesInTests();
LocalHistoryLog.LOG.info("Local history storage seems to be ok");
}
}
public File getStorageDir() {
@@ -100,7 +116,7 @@ public class LocalHistoryImpl extends LocalHistory implements ApplicationCompone
if (ApplicationManagerEx.getApplication().isHeadlessEnvironment()) return;
myAutoSaveFuture = JobScheduler.getScheduler().scheduleAtFixedRate(new Runnable() {
public void run() {
if (!HeavyProcessLatch.INSTANCE.isRunning()) myChangeList.save();
if (!HeavyProcessLatch.INSTANCE.isRunning()) myChangeList.flush();
}
}, 15000, 15000, TimeUnit.MILLISECONDS);
}
@@ -118,7 +134,9 @@ public class LocalHistoryImpl extends LocalHistory implements ApplicationCompone
CommandProcessor.getInstance().removeCommandListener(myEventDispatcher);
myChangeList.purgeObsolete(period);
validateStorage();
myChangeList.close();
LocalHistoryLog.LOG.info("Local history storage successfully closed.");
ShutDownTracker.getInstance().unregisterShutdownTask(myShutdownTask);
}
@@ -17,9 +17,9 @@
package com.intellij.history.integration.revertion;
import com.intellij.history.LocalHistory;
import com.intellij.history.core.Content;
import com.intellij.history.core.Paths;
import com.intellij.history.core.changes.*;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.integration.IdeaGateway;
import com.intellij.openapi.vfs.VfsUtil;
@@ -16,11 +16,11 @@
package com.intellij.history.integration.revertion;
import com.intellij.history.core.Content;
import com.intellij.history.core.LocalHistoryFacade;
import com.intellij.history.core.Paths;
import com.intellij.history.core.revisions.Difference;
import com.intellij.history.core.revisions.Revision;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.integration.FormatUtil;
import com.intellij.history.integration.IdeaGateway;
@@ -18,8 +18,8 @@ package com.intellij.history.integration.ui.models;
import com.intellij.diff.Block;
import com.intellij.diff.FindBlock;
import com.intellij.history.core.Content;
import com.intellij.history.core.revisions.Revision;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.integration.IdeaGateway;
import org.jetbrains.annotations.Nullable;
@@ -19,7 +19,6 @@ package com.intellij.history.core;
import com.intellij.history.Clock;
import com.intellij.history.core.changes.*;
import com.intellij.history.core.revisions.Revision;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.storage.TestContent;
import com.intellij.history.core.tree.Entry;
import com.intellij.history.core.tree.FileEntry;
@@ -175,7 +175,7 @@ public class ChangeListTest extends ChangeListTestCase {
@Test
public void testSavingDuringChangeSet() throws Exception {
facade.beginChangeSet();
facade.getChangeListInTests().save();
facade.getChangeListInTests().flush();
facade.endChangeSet(null); // should not throw exception.
}
}
@@ -16,8 +16,8 @@
package com.intellij.history.core.changes;
import com.intellij.history.core.Content;
import com.intellij.history.core.LocalHistoryTestCase;
import com.intellij.history.core.storage.Content;
import com.intellij.history.core.tree.RootEntry;
import org.junit.Test;
@@ -17,6 +17,8 @@
package com.intellij.history.core.storage;
import com.intellij.history.core.LocalHistoryTestCase;
import com.intellij.history.core.StoredContent;
import com.intellij.history.core.StreamUtil;
import com.intellij.history.core.changes.*;
import com.intellij.history.core.tree.DirectoryEntry;
import com.intellij.history.core.tree.Entry;
@@ -16,6 +16,8 @@
package com.intellij.history.core.storage;
import com.intellij.history.core.Content;
import java.util.Arrays;
public class TestContent extends Content {
@@ -18,13 +18,13 @@ package com.intellij.history.core.tree;
import com.intellij.history.core.LocalHistoryTestCase;
import com.intellij.history.core.Paths;
import com.intellij.history.core.StoredContent;
import com.intellij.history.core.revisions.Difference;
import com.intellij.history.core.storage.StoredContent;
import org.junit.Ignore;
import org.junit.Test;
import java.util.List;
import java.util.ArrayList;
import java.util.List;
public class DirectoryEntryTest extends LocalHistoryTestCase {
@Test
@@ -18,13 +18,12 @@ package com.intellij.history.core.tree;
import com.intellij.history.core.LocalHistoryTestCase;
import com.intellij.history.core.Paths;
import com.intellij.history.core.StoredContent;
import com.intellij.history.core.revisions.Difference;
import com.intellij.history.core.storage.StoredContent;
import org.junit.Ignore;
import org.junit.Test;
import java.util.List;
import java.util.ArrayList;
public class FileEntryTest extends LocalHistoryTestCase {
@Test
@@ -49,14 +49,14 @@ public class GettingContentAtDateTest extends IntegrationTestCase {
}
public void testGettingFirstAvailableContentAfterPurge() throws Exception {
Clock.setCurrentTimestamp(10);
Clock.setCurrentTimestamp(1);
setContent(f, "1", TIMESTAMP_INCREMENT);
Clock.setCurrentTimestamp(20);
Clock.setCurrentTimestamp(2);
setContent(f, "2", TIMESTAMP_INCREMENT * 2);
Clock.setCurrentTimestamp(30);
Clock.setCurrentTimestamp(3);
setContent(f, "3", TIMESTAMP_INCREMENT * 3);
getVcs().getChangeListInTests().purgeObsolete(5);
getVcs().getChangeListInTests().purgeObsolete(2);
assertContentAt(TIMESTAMP_INCREMENT, null);
assertContentAt(TIMESTAMP_INCREMENT * 2, "2");
@@ -15,19 +15,19 @@
*/
package com.intellij.historyIntegrTests;
import com.intellij.history.core.LinkedStorage;
import com.intellij.history.core.LocalHistoryStorage;
import com.intellij.util.io.storage.AbstractStorage;
import java.io.DataInputStream;
import java.io.IOException;
public class LinkedStorageTest extends IntegrationTestCase {
private LinkedStorage myStorage;
public class LocalHistoryStorageTest extends IntegrationTestCase {
private LocalHistoryStorage myStorage;
@Override
public void setUp() throws Exception {
super.setUp();
myStorage = new LinkedStorage(myRoot.getPath() + "/storage");
myStorage = new LocalHistoryStorage(myRoot.getPath() + "/storage");
}
@Override
@@ -105,7 +105,7 @@ public class LinkedStorageTest extends IntegrationTestCase {
myStorage.deleteRecord(r2);
myStorage.dispose();
myStorage = new LinkedStorage(myRoot.getPath() + "/storage");
myStorage = new LocalHistoryStorage(myRoot.getPath() + "/storage");
assertFirstAndLast(r1, r3);
assertRecord(r3, r1, 0);
@@ -114,7 +114,7 @@ public class LinkedStorageTest extends IntegrationTestCase {
myStorage.deleteRecord(r1);
myStorage.dispose();
myStorage = new LinkedStorage(myRoot.getPath() + "/storage");
myStorage = new LocalHistoryStorage(myRoot.getPath() + "/storage");
assertFirstAndLast(r3, r3);
assertRecord(r3, 0, 0);
@@ -122,7 +122,7 @@ public class LinkedStorageTest extends IntegrationTestCase {
int r4 = createRecord();
myStorage.dispose();
myStorage = new LinkedStorage(myRoot.getPath() + "/storage");
myStorage = new LocalHistoryStorage(myRoot.getPath() + "/storage");
assertFirstAndLast(r3, r4);
assertRecord(r4, r3, 0);
@@ -40,6 +40,13 @@ public class PurgingTest extends IntegrationTestCase {
assertRemainedChangesTimestamps(3, 2);
}
@Test
public void testPurgeSeveral() {
createChangesWithTimestamps(1, 2, 3);
getVcs().getChangeListInTests().purgeObsolete(1);
assertRemainedChangesTimestamps(3);
}
@Test
public void testPurgeNothing() {
createChangesWithTimestamps(1, 2, 3);
@@ -35,7 +35,7 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
protected static final int DEFAULT_HEADER_SIZE = 8;
private static final int VERSION = 5;
private static final int CONNECTED_MAGIC = 0x12ad34e4;
private static final int DIRTY_MAGIC = 0x12ad34e4;
private static final int SAFELY_CLOSED_MAGIC = 0x1f2f3f4f + VERSION;
private static final int ADDRESS_OFFSET = 0;
@@ -53,7 +53,7 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
myStorage = new RandomAccessDataFile(storageFilePath, pool);
if (myStorage.length() == 0) {
myStorage.put(0, new byte[getHeaderSize()], 0, getHeaderSize());
myIsDirty = true;
markDirty();
}
else {
if (myStorage.getInt(HEADER_MAGIC_OFFSET) != getSafelyClosedMagic()) {
@@ -77,13 +77,6 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
protected abstract byte[] getZeros();
public void markDirty() {
if (!myIsDirty) {
myIsDirty = true;
myStorage.putInt(HEADER_MAGIC_OFFSET, CONNECTED_MAGIC);
}
}
public int createNewRecord() throws IOException {
markDirty();
ensureFreeRecordsScanned();
@@ -164,13 +157,11 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
public void deleteRecord(final int record) throws IOException {
ensureFreeRecordsScanned();
cleanRecord(record);
setSize(record, -1);
clearDeletedRecord(record);
myFreeRecordsList.add(record);
}
protected abstract void clearDeletedRecord(int record);
public int getVersion() {
return myStorage.getInt(HEADER_VERSION_OFFSET);
}
@@ -202,7 +193,14 @@ public abstract class AbstractRecordsTable implements Disposable, Forceable {
}
public boolean isDirty() {
return myIsDirty;
return myIsDirty || myStorage.isDirty();
}
public void markDirty() {
if (!myIsDirty) {
myIsDirty = true;
myStorage.putInt(HEADER_MAGIC_OFFSET, DIRTY_MAGIC);
}
}
private void markClean() {
@@ -30,7 +30,7 @@ import java.io.IOException;
class DataTable implements Disposable, Forceable {
private static final int HEADER_SIZE = 32;
private static final int CONNECTED_MAGIC = 0x12ad34e4;
private static final int DIRTY_MAGIC = 0x12ad34e4;
private static final int SAFELY_CLOSED_MAGIC = 0x1f2f3f4f;
private final RandomAccessDataFile myFile;
@@ -43,8 +43,7 @@ class DataTable implements Disposable, Forceable {
public DataTable(final File filePath, final PagePool pool) throws IOException {
myFile = new RandomAccessDataFile(filePath, pool);
if (myFile.length() == 0) {
fillInHeader(CONNECTED_MAGIC, 0);
myIsDirty = true;
markDirty();
}
else {
readInHeader(filePath);
@@ -125,7 +124,7 @@ class DataTable implements Disposable, Forceable {
private void markDirty() {
if (!myIsDirty) {
myIsDirty = true;
fillInHeader(CONNECTED_MAGIC, 0);
fillInHeader(DIRTY_MAGIC, 0);
}
}
@@ -48,7 +48,4 @@ class RecordsTable extends AbstractRecordsTable {
return ZEROES;
}
@Override
protected void clearDeletedRecord(int record) {
}
}
@@ -47,11 +47,6 @@ class RefCountingRecordsTable extends AbstractRecordsTable {
return ZEROES;
}
@Override
protected void clearDeletedRecord(int record) {
myStorage.putInt(getOffset(record, REF_COUNT_OFFSET), 0);
}
public void incRefCount(int record) {
markDirty();