Skip to content
This repository was archived by the owner on Sep 27, 2022. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.function.Function;

public class DBTableProvider implements TableProvider {
Expand Down Expand Up @@ -65,10 +67,14 @@ public class DBTableProvider implements TableProvider {
*/
private final Map<String, TableCorruptIOException> corruptTables;

/**
* Lock for getting/creating/removing tables access management.
*/
private final ReadWriteLock persistenceLock = new ReentrantReadWriteLock(true);

/**
* Constructs a database table provider.
* @throws ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.exception
* .DatabaseIOException
* @throws ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.exception.DatabaseIOException
* If failed to scan database directory.
*/
DBTableProvider(Path databaseRoot) throws DatabaseIOException {
Expand All @@ -81,16 +87,22 @@ public class DBTableProvider implements TableProvider {
@Override
public StoreableTableImpl getTable(String name) throws IllegalArgumentException {
Utility.checkTableNameIsCorrect(name);
if (tables.containsKey(name)) {
StoreableTableImpl table = tables.get(name);
if (table == null) {
DatabaseIOException corruptionReason = corruptTables.get(name);
throw new IllegalArgumentException(
corruptionReason.getMessage(), corruptionReason);

persistenceLock.readLock().lock();
try {
if (tables.containsKey(name)) {
StoreableTableImpl table = tables.get(name);
if (table == null) {
DatabaseIOException corruptionReason = corruptTables.get(name);
throw new IllegalArgumentException(
corruptionReason.getMessage(), corruptionReason);
}
return table;
} else {
return null;
}
return table;
} else {
return null;
} finally {
persistenceLock.readLock().unlock();
}
}

Expand All @@ -109,13 +121,18 @@ public StoreableTableImpl createTable(String name, List<Class<?>> columnTypes)

Path tablePath = databaseRoot.resolve(name);

if (tables.containsKey(name) && tables.get(name) != null) {
return null;
}
persistenceLock.writeLock().lock();
try {
if (tables.containsKey(name) && tables.get(name) != null) {
return null;
}

StoreableTableImpl newTable = StoreableTableImpl.createTable(this, tablePath, columnTypes);
tables.put(name, newTable);
return newTable;
StoreableTableImpl newTable = StoreableTableImpl.createTable(this, tablePath, columnTypes);
tables.put(name, newTable);
return newTable;
} finally {
persistenceLock.writeLock().unlock();
}
}

@Override
Expand All @@ -124,31 +141,39 @@ public void removeTable(String name)
Utility.checkTableNameIsCorrect(name);
Path tablePath = databaseRoot.resolve(name);

if (!tables.containsKey(name)) {
throw new IllegalStateException(name + " not exists");
}
persistenceLock.writeLock().lock();
try {
if (!tables.containsKey(name)) {
throw new IllegalStateException(name + " not exists");
}

StoreableTableImpl removed = tables.remove(name);
if (removed != null) {
removed.invalidate();
}
StoreableTableImpl removed = tables.remove(name);
if (removed != null) {
// After invalidation all attempts to commit from other threads fail with
// IllegalStateException. Now we can delete the table without fear that it will be written
// to the file system again.
removed.invalidate();
}

corruptTables.remove(name);
corruptTables.remove(name);

if (!Files.exists(tablePath)) {
return;
}
if (!Files.exists(tablePath)) {
return;
}

try {
Utility.rm(tablePath);
} catch (IOException exc) {
// Mark as corrupt.
tables.put(name, null);
try {
Utility.rm(tablePath);
} catch (IOException exc) {
// Mark as corrupt.
tables.put(name, null);

TableCorruptIOException corruptionReason = new TableCorruptIOException(
name, "Failed to drop table: " + exc.toString(), exc);
corruptTables.put(name, corruptionReason);
throw corruptionReason;
TableCorruptIOException corruptionReason = new TableCorruptIOException(
name, "Failed to drop table: " + exc.toString(), exc);
corruptTables.put(name, corruptionReason);
throw corruptionReason;
}
} finally {
persistenceLock.writeLock().unlock();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@

import java.util.Objects;

/**
* Implementation of Storeable that can be put to the table it is assigned to as a value.<br/>
* Not thread-safe.
*/
public class StoreableImpl implements Storeable {
private final Object[] values;

Expand Down Expand Up @@ -120,16 +124,6 @@ public boolean equals(Object obj) {
return false;
}

if (host.getColumnsCount() != storeable.host.getColumnsCount()) {
return false;
}

for (int col = 0; col < host.getColumnsCount(); col++) {
if (!host.getColumnType(col).equals(storeable.host.getColumnType(col))) {
return false;
}
}

for (int col = 0; col < host.getColumnsCount(); col++) {
if (!Objects.equals(values[col], storeable.values[col])) {
return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.concurrent.atomic.AtomicBoolean;

public class StoreableTableImpl implements Table {
private static final Map<Class<?>, String> CLASSES_TO_NAMES_MAP =
Expand All @@ -47,11 +48,11 @@ public class StoreableTableImpl implements Table {

private final List<Class<?>> columnTypes;

private boolean invalidated;
private AtomicBoolean invalidated;

private StoreableTableImpl(TableProvider provider, StringTableImpl store, List<Class<?>> columnTypes) {
this.provider = provider;
this.invalidated = false;
this.invalidated = new AtomicBoolean(false);
this.store = store;
this.columnTypes = Collections.unmodifiableList(new ArrayList<Class<?>>(columnTypes));
}
Expand Down Expand Up @@ -155,12 +156,13 @@ static StoreableTableImpl getTable(TableProvider provider, Path tablePath) throw

/**
* Checks whether the given storeable can be stored in the given table as a value.
* @throws ColumnFormatException
* @throws ru.fizteh.fivt.storage.structured.ColumnFormatException
* If columns count differs or some column has wrong type. Note that if some column has null
* value, its type cannot be determined.
* @throws java.lang.IllegalStateException
* @throws IllegalStateException
* If the given storeable is already assigned to another table. This check can be performed only
* for instances of {@link StoreableTableImpl}.
* for instances of {@link ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.db
* .StoreableTableImpl}.
*/
public static void checkStoreableAppropriate(Table table, Storeable storeable)
throws ColumnFormatException, IllegalStateException {
Expand Down Expand Up @@ -215,14 +217,21 @@ TableProvider getProvider() {
}

/**
* Mark this table as invalidated (all further operations throw {@link java.lang.IllegalStateException}).
* Mark this table as invalidated (all further operations throw {@link IllegalStateException}).
*/
void invalidate() {
invalidated = true;
// We need table's write lock here to sync with file system.
// Remember the table becomes invalidated before being deleted.
store.getPersistenceLock().writeLock().lock();
try {
invalidated.set(true);
} finally {
store.getPersistenceLock().writeLock().unlock();
}
}

private void checkValidity() throws IllegalStateException {
if (invalidated) {
if (invalidated.get()) {
throw new IllegalStateException(store.getName() + " is invalidated");
}
}
Expand Down
Loading