blob: 29e87422bb53298032f259380044e3793904a3c9 [file] [log] [blame]
/*
* 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 org.jetbrains.idea.svn;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.vcs.changes.FilePathsHelper;
import org.jetbrains.annotations.Nullable;
import org.tmatesoft.sqljet.core.SqlJetException;
import org.tmatesoft.sqljet.core.table.ISqlJetBusyHandler;
import org.tmatesoft.sqljet.core.table.ISqlJetTransaction;
import org.tmatesoft.sqljet.core.table.SqlJetDb;
import org.tmatesoft.svn.core.SVNException;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Created with IntelliJ IDEA.
* User: Irina.Chernushina
* Date: 10/19/12
* Time: 12:09 PM
*/
// TODO: Such locking functionality is not required anymore. Likely to be removed (together with SvnProxies).
public abstract class SvnAbstractWriteOperationLocks {
private final long myTimeout;
private final static Map<String, Lock> myLockMap = new HashMap<String, Lock>();
private final static Object myLock = new Object();
private static final Logger LOG = Logger.getInstance("#org.jetbrains.idea.svn.SvnAbstractWriteOperationLocks");
private ISqlJetBusyHandler ourBusyHandler;
private volatile boolean myDisposed;
protected SvnAbstractWriteOperationLocks(long timeout) {
myTimeout = timeout;
ourBusyHandler = new ISqlJetBusyHandler() {
@Override
public boolean call(int i) {
if (myDisposed) return false;
try {
Thread.sleep(myTimeout);
}
catch (InterruptedException e) {
//
}
return true;
}
};
}
public void dispose() {
myDisposed = true;
}
// null if not 1.7+ copy
@Nullable
private Lock getLockObject(File file) throws SVNException {
final boolean directory = file.isDirectory();
final WorkingCopy wcRoot = getCopy(file, directory);
if (! wcRoot.is17Copy()) return null;
Lock lock;
final String path = FilePathsHelper.convertPath(wcRoot.getFile().getPath());
synchronized (myLock) {
lock = myLockMap.get(path);
if (lock == null) {
lock = new ReentrantLock();
myLockMap.put(path, lock);
}
}
return lock;
}
protected abstract WorkingCopy getCopy(File file, boolean directory) throws SVNException;
public void lockWrite(final File file) throws SVNException {
final Lock lock = getLockObject(file);
if (lock != null) {
lock.lock();
}
}
public void unlockWrite(final File file) throws SVNException {
final Lock lock = getLockObject(file);
if (lock != null) {
lock.unlock();
}
}
// would wait until read is available
public void wrapRead(final File file, final Runnable runnable) throws SVNException {
final WorkingCopy copy = getCopy(file, file.isDirectory());
if (! copy.is17Copy()) {
runnable.run();
return;
}
final File root = copy.getFile();
SqlJetDb open = null;
final boolean run[] = new boolean[1];
run[0] = false;
try {
open = SqlJetDb.open(SvnUtil.getWcDb(root), false);
open.setBusyHandler(ourBusyHandler);
try {
final SqlJetDb finalOpen = open;
open.runReadTransaction(new ISqlJetTransaction() {
@Override
public Object run(SqlJetDb db) throws SqlJetException {
run[0] = true;
runnable.run();
return null;
}
});
} finally {
open.rollback();
}
}
catch (SqlJetException e) {
LOG.info(e);
if (! run[0]) {
runnable.run();
}
}
finally {
if (open != null) {
try {
open.close();
}
catch (SqlJetException e) {
LOG.info(e);
}
}
}
}
}