Skip to content
This repository was archived by the owner on Sep 27, 2022. It is now read-only.
Open
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
@@ -0,0 +1,17 @@
package ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.db;

import ru.fizteh.fivt.storage.structured.TableProvider;

import java.io.IOException;
import java.util.List;

public interface AutoCloseableProvider extends TableProvider, AutoCloseable {
@Override
void close();

@Override
AutoCloseableTable getTable(String name);

@Override
AutoCloseableTable createTable(String name, List<Class<?>> columnTypes) throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.db;

import ru.fizteh.fivt.storage.structured.Table;

public interface AutoCloseableTable extends Table, AutoCloseable {
@Override
void close();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.db;

import ru.fizteh.fivt.storage.structured.TableProviderFactory;

import java.io.Closeable;
import java.io.IOException;

public interface AutoCloseableTableProviderFactory extends TableProviderFactory, Closeable {
@Override
AutoCloseableProvider create(String path) throws IOException;
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,16 +1,78 @@
package ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.db;

import ru.fizteh.fivt.storage.structured.TableProviderFactory;
import ru.fizteh.fivt.proxy.LoggingProxyFactory;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.exception.DatabaseIOException;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.Log;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.LoggingProxyFactoryXML;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.Utility;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.ValidityController;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.ValidityController.KillLock;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.support.ValidityController.UseLock;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.IdentityHashMap;

public class DBTableProviderFactory implements TableProviderFactory {
public final class DBTableProviderFactory implements AutoCloseableTableProviderFactory {
private static final LoggingProxyFactory LOGGING_PROXY_FACTORY = new LoggingProxyFactoryXML();
private static final Writer LOG_WRITER;

static {
Writer tempWriter;

try {
tempWriter = new OutputStreamWriter(new FileOutputStream("Proxy.log"));
} catch (IOException exc) {
Log.log(DBTableProviderFactory.class, exc, "Failed to create log");
tempWriter = null;
}

LOG_WRITER = tempWriter;
}

private final ValidityController validityController = new ValidityController();
private final IdentityHashMap<AutoCloseableProvider, Boolean> generatedProviders =
new IdentityHashMap<>();

private boolean providerClosedByMe = false;

static <T> T wrapImplementation(T implementation, Class<T> interfaceClass) {
if (LOG_WRITER != null) {
return (T) LOGGING_PROXY_FACTORY.wrap(LOG_WRITER, implementation, interfaceClass);
} else {
return implementation;
}
}

@Override
public synchronized void close() {
try (KillLock lock = validityController.useAndKill()) {
providerClosedByMe = true;
generatedProviders.keySet().forEach(AutoCloseableProvider::close);
generatedProviders.clear();
} finally {
providerClosedByMe = false;
}
}

/**
* Unregisters the given provider.
* @param provider
* Pure (not proxied) link to the closed provider.
*/
synchronized void onProviderClosed(AutoCloseableProvider provider) {
try (UseLock useLock = validityController.use()) {
if (!providerClosedByMe) {
generatedProviders.remove(provider);
}
}
}

private void checkDatabaseDirectory(final Path databaseRoot) throws DatabaseIOException {
if (!Files.isDirectory(databaseRoot)) {
Expand All @@ -31,25 +93,37 @@ private void checkDatabaseDirectory(final Path databaseRoot) throws DatabaseIOEx
}

@Override
public DBTableProvider create(String dir) throws IllegalArgumentException, DatabaseIOException {
Utility.checkNotNull(dir, "Directory");

Path databaseRoot = Paths.get(dir).normalize();
if (!Files.exists(databaseRoot)) {
if (databaseRoot.getParent() == null || !Files.isDirectory(databaseRoot.getParent())) {
throw new DatabaseIOException(
"Database directory parent path does not exist or is not a directory");
}
protected void finalize() throws Throwable {
super.finalize();
close();
}

@Override
public synchronized AutoCloseableProvider create(String dir)
throws IllegalArgumentException, DatabaseIOException {
try (UseLock useLock = validityController.use()) {
Utility.checkNotNull(dir, "Directory");

try {
Files.createDirectory(databaseRoot);
} catch (IOException exc) {
throw new DatabaseIOException("Failed to establish database on path " + dir, exc);
Path databaseRoot = Paths.get(dir).normalize();
if (!Files.exists(databaseRoot)) {
if (databaseRoot.getParent() == null || !Files.isDirectory(databaseRoot.getParent())) {
throw new DatabaseIOException(
"Database directory parent path does not exist or is not a directory");
}

try {
Files.createDirectory(databaseRoot);
} catch (IOException exc) {
throw new DatabaseIOException("Failed to establish database on path " + dir, exc);
}
} else {
checkDatabaseDirectory(databaseRoot);
}
} else {
checkDatabaseDirectory(databaseRoot);
}

return new DBTableProvider(databaseRoot);
AutoCloseableProvider provider = new DBTableProvider(databaseRoot, this);
AutoCloseableProvider wrappedProvider = wrapImplementation(provider, AutoCloseableProvider.class);
generatedProviders.put(provider, Boolean.TRUE);
return wrappedProvider;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,24 @@
import ru.fizteh.fivt.storage.structured.Table;
import ru.fizteh.fivt.storage.structured.TableProvider;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.exception.DatabaseIOException;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.exception.InvalidatedObjectException;
import ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.exception.NoActiveTableException;

import java.io.IOException;
import java.nio.file.Path;
import java.io.PrintStream;
import java.util.List;

/**
* Database class responsible for a set of tables assigned to it.
* @author phoenix
*/
public class Database {
protected final TableProvider provider;
private final TableProvider provider;
/**
* Root directory of all database files
*/
private final Path dbDirectory;
private final String dbDirectory;
private final PrintStream outputStream;
/**
* Table in use.<br/> All operations (like {@code put}, {@code get}, etc.) are performed with
* this table.
Expand All @@ -28,12 +30,11 @@ public class Database {
/**
* Establishes a database instance on given folder.<br/> If the folder exists, the old database
* is used.<br/> If the folder does not exist, a new database is created within the folder.
* @throws ru.fizteh.fivt.students.fedorov_andrew.databaselibrary.exception.DatabaseIOException
*/
public Database(Path dbDirectory) throws DatabaseIOException {
public Database(TableProvider provider, String dbDirectory, PrintStream outputStream) {
this.outputStream = outputStream;
this.dbDirectory = dbDirectory;
DBTableProviderFactory factory = new DBTableProviderFactory();
this.provider = factory.create(dbDirectory.toString());
this.provider = provider;
}

public TableProvider getProvider() {
Expand All @@ -60,7 +61,14 @@ public boolean createTable(String tableName, List<Class<?>> columnTypes)
* Name of table to drop.
*/
public void dropTable(String tableName) throws IllegalArgumentException, IOException {
String activeTableName = activeTable == null ? null : activeTable.getName();
String activeTableName = null;
if (activeTable != null) {
try {
activeTableName = activeTable.getName();
} catch (InvalidatedObjectException exc) {
// Ignore it.
}
}

provider.removeTable(tableName);

Expand All @@ -74,7 +82,7 @@ public Table getActiveTable() throws NoActiveTableException {
return activeTable;
}

public Path getDbDirectory() {
public String getDbDirectory() {
return dbDirectory;
}

Expand All @@ -99,9 +107,10 @@ public int rollback() {
}

public void showTables() {
System.out.println("table_name row_count");
outputStream.println("table_name row_count");
List<String> tableNames = provider.getTableNames();

StringBuilder sb = new StringBuilder();
for (String tableName : tableNames) {
boolean valid;
int changesCount = 0;
Expand All @@ -114,8 +123,10 @@ public void showTables() {
valid = false;
}

System.out.println(String.format("%s %s", tableName, valid ? changesCount : "corrupt"));
sb.append(String.format("%s %s", tableName, valid ? changesCount : "corrupt"));
sb.append(System.lineSeparator());
}
outputStream.print(sb.toString());
}

/**
Expand All @@ -124,27 +135,32 @@ public void showTables() {
* Name of table to use.
*/
public void useTable(String tableName) throws IOException, IllegalArgumentException {
if (activeTable != null) {
if (tableName.equals(activeTable.getName())) {
return;
}

int uncommitted = activeTable.getNumberOfUncommittedChanges();
if (uncommitted != 0) {
throw new DatabaseIOException(String.format("%d unsaved changes", uncommitted));
try {
if (activeTable != null) {
if (tableName.equals(activeTable.getName())) {
return;
}

int uncommitted = activeTable.getNumberOfUncommittedChanges();
if (uncommitted != 0) {
throw new DatabaseIOException(String.format("%d unsaved changes", uncommitted));
}
}
}

Table oldActiveTable = activeTable;
Table oldActiveTable = activeTable;

try {
activeTable = provider.getTable(tableName);
if (activeTable == null) {
throw new IllegalArgumentException(tableName + " not exists");
try {
activeTable = provider.getTable(tableName);
if (activeTable == null) {
throw new IllegalArgumentException(tableName + " not exists");
}
} catch (Exception exc) {
activeTable = oldActiveTable;
throw exc;
}
} catch (Exception exc) {
activeTable = oldActiveTable;
throw exc;
} catch (InvalidatedObjectException exc) {
activeTable = null;
useTable(tableName);
}
}
}
Loading