Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • caosdb/src/caosdb-server
1 result
Show changes
Commits on Source (2)
......@@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Fixed
* #122 - Dead-lock due to error in the DatabaseAccessManager.
* #120 - Editing entities that were created with a no longer existing user
leads to a server error.
* #31 - Queries with keywords in the path (e.g. `... STORED AT 0in.txt`)
......
......@@ -26,6 +26,7 @@
package org.caosdb.server.database;
import java.util.concurrent.Semaphore;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;
import org.caosdb.server.database.access.Access;
import org.caosdb.server.database.access.AccessControlAccess;
......@@ -56,7 +57,7 @@ import org.caosdb.server.utils.Releasable;
class ReadAccessSemaphore extends Semaphore implements Releasable {
private static final long serialVersionUID = 4384921156838881337L;
private int acquired = 0; // how many threads have read access
private AtomicInteger acquired = new AtomicInteger(0); // how many threads have read access
Semaphore writersBlock =
new Semaphore(1, true); // This semaphore is blocked as long as there are any
// unreleased read permits.
......@@ -73,10 +74,9 @@ class ReadAccessSemaphore extends Semaphore implements Releasable {
@Override
public void acquire() throws InterruptedException {
super.acquire(); // Protect the next few lines
if (this.acquired == 0) {
if (this.acquired.getAndIncrement() == 0) {
this.writersBlock.acquire();
}
this.acquired++;
super.release();
}
......@@ -87,9 +87,7 @@ class ReadAccessSemaphore extends Semaphore implements Releasable {
*/
@Override
public void release() {
this.acquired--;
if (this.acquired <= 0) { // Last permit: release
this.acquired = 0;
if (this.acquired.decrementAndGet() == 0) { // Last permit: release
if (this.writersBlock.availablePermits() <= 0) {
this.writersBlock.release();
}
......
......@@ -22,10 +22,91 @@
*/
package org.caosdb.server.database;
import static org.junit.Assert.assertFalse;
import java.util.LinkedList;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
public class DatabaseAccessManagerTest {
Thread createReadThread(long wait, String name, ReadAccessSemaphore readAccess) {
return new Thread(
new Runnable() {
@Override
public void run() {
try {
readAccess.acquire();
Thread.sleep(wait);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
readAccess.release();
}
}
},
name);
}
Thread createWriteThread(long wait, String name, WriteAccessLock writeAccess) {
return new Thread(
new Runnable() {
@Override
public void run() {
try {
writeAccess.reserve();
Thread.sleep(wait);
writeAccess.lockInterruptibly();
Thread.sleep(wait);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
writeAccess.release();
}
}
},
name);
}
@Test
public void testDeadLock() throws InterruptedException {
final ReadAccessSemaphore readAccess = new ReadAccessSemaphore();
final WriteAccessLock writeAccess = new WriteAccessLock(readAccess);
List<Thread> ts = new LinkedList<>();
for (int i = 0; i < 1000; i++) {
Thread t1 = createReadThread(1, "Ra" + i, readAccess);
Thread t2 = createReadThread(2, "Rb" + i, readAccess);
Thread t3 = createReadThread(3, "Rc" + i, readAccess);
Thread t5 = createReadThread(5, "Rd" + i, readAccess);
Thread t7 = createReadThread(7, "Re" + i, readAccess);
Thread t11 = createReadThread(11, "Rf" + i, readAccess);
Thread w5 = createWriteThread(2, "W" + i, writeAccess);
t1.start();
t2.start();
w5.start();
t3.start();
t5.start();
t7.start();
t11.start();
ts.add(t1);
ts.add(t2);
ts.add(t3);
ts.add(t5);
ts.add(t7);
ts.add(t11);
ts.add(w5);
}
for (Thread t : ts) {
t.join(10000);
assertFalse(t.isAlive());
}
}
public static final ReadAccessSemaphore readAccess = new ReadAccessSemaphore();
public static final WriteAccessLock writeAccess = new WriteAccessLock(readAccess);
......
......@@ -70,8 +70,8 @@ public class QueryTest {
/**
* Assure that {@link WriteTransaction#commit()} calls {@link Query#clearCache()}.
*
* Since currently the cache shall be cleared whenever there is a commit.
* */
* <p>Since currently the cache shall be cleared whenever there is a commit.
*/
@Test
public void testEtagChangesAfterWrite() {
String old = Query.getETag();
......