Skip to content

Instantly share code, notes, and snippets.

@klauswuestefeld
Created July 25, 2011 04:55
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save klauswuestefeld/1103582 to your computer and use it in GitHub Desktop.
Save klauswuestefeld/1103582 to your computer and use it in GitHub Desktop.
PrevaylerJr - "To serve the persistence needs of 99% of information systems in the world using 23 semicolons."
import java.io.*;
public class PrevaylerJr {
public static interface Command extends Serializable {
Object executeOn(Object system);
}
private final Object _system;
private final ObjectOutputStream _journal;
public PrevaylerJr(Serializable initialState, File storageFile) throws Exception {
File tempFile = new File(storageFile.getAbsolutePath() + ".tmp");
_system = restoreState(initialState, storageFile, tempFile);
_journal = new ObjectOutputStream(new FileOutputStream(tempFile));
writeToJournal(_system);
if (storageFile.delete() && tempFile.renameTo(storageFile))
return;
throw new IOException("Unable to rename " + tempFile + " to " + storageFile);
}
synchronized
public Object executeTransaction(Command transaction) throws Exception {
writeToJournal(transaction);
return transaction.executeOn(_system);
}
synchronized
public Object executeQuery(Command query) {
return query.executeOn(_system);
}
private Object restoreState(Object initialState, File storageFile, File tempFile) {
Object state = initialState;
try {
File fileToRead = storageFile.exists() ? storageFile : tempFile;
ObjectInputStream input = new ObjectInputStream(new FileInputStream(fileToRead));
state = restoreImage(input);
restoreCommands(state, input);
} catch (Exception endOfStreamReached) {}
return state;
}
private Serializable restoreImage(ObjectInputStream input) throws IOException, ClassNotFoundException {
return (Serializable) input.readObject();
}
private void restoreCommands(Object state, ObjectInputStream input) throws IOException, ClassNotFoundException {
while (true)
((Command) input.readObject()).executeOn(state);
}
private void writeToJournal(Object object) throws IOException {
_journal.writeObject(object);
_journal.flush();
}
}
@rofr
Copy link

rofr commented Aug 14, 2011

You mean 99% of the systems written in java :)
For .NET check out http://livedb.devrex.se and http://livedomain.codeplex.com

@rofr
Copy link

rofr commented Aug 14, 2011

In executeTransaction() I would write to the journal after executing the command.Why would we want a failed command in the journal? It will just fail again when the system is restored, possibly leaving the system in an inconsistent state. In #livedb, if a command throws an unexpected exception, the system either shuts down or rolls back to the state prior to the failing command.

@klauswuestefeld
Copy link
Author

You mean 99% of the systems written in java :)

Nice one. :) I'm almost sure you are capable of writing a port of PrevaylerJr to your favorite language using only 23 statements. Oops , you already did: http://livedb.devrex.se

In #livedb, if a command throws an unexpected exception, the system either
shuts down or rolls back to the state prior to the failing command.

You will revise that as the project matures.

@rofr
Copy link

rofr commented Aug 22, 2011

I still can't figure out why writing to the journal before executing the transaction is a good idea unless of course all commands are well written and never fail unexpectedly. From my point of view the engine is part of a framework while commands are written by users and should not be trusted. I'm of course very curious about what experience leads you to the opposite conclusion. Any hints or pointers are welcome.

@klauswuestefeld
Copy link
Author

Applying transactions to the system before they are written will cause queries to see unwritten changes. So, unless you sequence all queries with disk writes, you lose the D in ACID.
Recovering the system after a transaction exception, even if done with the RoyalFoodTaster pattern, is a huge hiccup in the system. If there is a silly transaction throwing a frequent but unimportant exception, sysadmins will hate you for this feature.
Throwing an exception is just one particular kind of bug a transaction can cause. All other bugs will not be caught, just as they won't be caught in any DBMS.

@beothorn
Copy link

Is there a reason to use Object instead of Serializable on lines 67,41 and 11?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment