prevayler-coders Mailing List for Prevayler (Page 2)
Brought to you by:
jsampson,
klauswuestefeld
You can subscribe to this list here.
2004 |
Jan
|
Feb
|
Mar
|
Apr
(13) |
May
(83) |
Jun
(8) |
Jul
(18) |
Aug
(33) |
Sep
(132) |
Oct
(16) |
Nov
(32) |
Dec
(32) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2005 |
Jan
(35) |
Feb
(21) |
Mar
(7) |
Apr
(11) |
May
(18) |
Jun
|
Jul
(21) |
Aug
(14) |
Sep
(7) |
Oct
|
Nov
(16) |
Dec
|
2006 |
Jan
(15) |
Feb
|
Mar
|
Apr
|
May
|
Jun
(57) |
Jul
|
Aug
(15) |
Sep
(3) |
Oct
(1) |
Nov
|
Dec
|
2007 |
Jan
|
Feb
(1) |
Mar
|
Apr
|
May
|
Jun
(9) |
Jul
(7) |
Aug
|
Sep
(2) |
Oct
(1) |
Nov
|
Dec
(1) |
2008 |
Jan
|
Feb
(4) |
Mar
(10) |
Apr
(20) |
May
|
Jun
(5) |
Jul
(34) |
Aug
(2) |
Sep
|
Oct
(2) |
Nov
(2) |
Dec
|
2009 |
Jan
|
Feb
|
Mar
(5) |
Apr
|
May
|
Jun
|
Jul
|
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: Bill B. <bi...@mo...> - 2008-07-02 17:06:43
|
I don't think it is possible for a crash to corrupt a part of the file which you are not changing, at least not with a journaling file system that preserves file metadata (size, etc). I'm using XFS and from what I hear, NTFS is pretty good -- I think NTFS only journals metadata. I'm not an expert in file systems, so I'm not sure what all of the guarantees are. My guess is that strict appending (like what prevayler does) probably gives you the best guarantees. Given that a file system that journals metadata and only strict appending, do power failures only truncate data and not introduce garbage? If so, I think this would provide all of the guarantees I need, because I could just write a length before each batch and verify with the remaining file size, which would remove the need for end markers and the extra sync. Bill Klaus Wuestefeld wrote: > Prevayler also syncs batches of transactions. They are only executed > after the sync for their batch completes. > > Prevayler detects corrupt batches and ignores the last one if it is > corrupt, as if it never had been written, which is ok, since its > transactions never got executed on the system in the first place. > > Why is it you cant simply ignore the last corrupt batch? > > A related issue: > Is it possible for a crash during an append to a file to corrupt the > last cluster, corrupting what had previously been completely syncd? > > See you, Klaus. > > > On Tue, Jul 1, 2008 at 8:36 PM, Bill Burdick <bi...@mo...> wrote: > >> Sync isn't atomic for system failures. A power failure can happen before a >> sync completes (and did many times with our system, because users were >> allowing unattended laptops to run out of charge during heavy updating). >> Because of this, if you take out the first sync and only use the last sync, >> and there IS a failure during the sync, there could be a "noop" followed by >> an incomplete journal record. The presence of a "noop" instead of an "end" >> indicates that the next record is known not to be corrupted (in our system, >> there is actually a batch of records after the "noop", not just a single >> record, so you don't have to sync for every record), so we only write it >> after the first sync completes. >> >> Bill >> >> >> Klaus Wuestefeld wrote: >> >>>> The reason for the two syncs is that you can't guarantee the >>>> order that dirty pages will be written to disk >>>> >>>> >>> Doesn't sync guarantee that all its dirty pages have been written? >>> >>> ------------------------------------------------------------------------- >>> Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW! >>> Studies have shown that voting for your favorite open source project, >>> along with a healthy diet, reduces your potential for chronic lameness >>> and boredom. Vote Now at http://www.sourceforge.net/community/cca08 >>> _______________________________________________ >>> Prevayler-coders mailing list >>> Pre...@li... >>> https://lists.sourceforge.net/lists/listinfo/prevayler-coders >>> >>> >>> >> ------------------------------------------------------------------------- >> Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW! >> Studies have shown that voting for your favorite open source project, >> along with a healthy diet, reduces your potential for chronic lameness >> and boredom. Vote Now at http://www.sourceforge.net/community/cca08 >> _______________________________________________ >> Prevayler-coders mailing list >> Pre...@li... >> https://lists.sourceforge.net/lists/listinfo/prevayler-coders >> >> >> > > ------------------------------------------------------------------------- > Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW! > Studies have shown that voting for your favorite open source project, > along with a healthy diet, reduces your potential for chronic lameness > and boredom. Vote Now at http://www.sourceforge.net/community/cca08 > _______________________________________________ > Prevayler-coders mailing list > Pre...@li... > https://lists.sourceforge.net/lists/listinfo/prevayler-coders > > |
From: Justin T. S. <ju...@kr...> - 2008-07-02 01:48:56
|
On Tue, Jul 1, 2008 at 12:27 PM, Klaus Wuestefeld <kla...@gm...> wrote: > I have also treated OutOfMemoryError. Should we catch all Errors? I think so -- any Error is likely to have left the prevalent system in a corrupted state. StackOverflowError is another common one. This can just be part of the Prevayler(Jr) contract... Like those signs in restaurants saying "if you are seen smoking, you will be assumed to be on fire and appropriate action will be taken"... You'd be sayinig "if you throw an Error, you will be assumed to be corrupted and appropriate action will be taken"... :) There's a remaining bug -- while transactions will now be prevented from executing since the journal has been closed, queries are still allowed to execute against the corrupted prevalent system. Cheers, Justin |
From: Klaus W. <kla...@gm...> - 2008-07-02 00:33:19
|
Prevayler also syncs batches of transactions. They are only executed after the sync for their batch completes. Prevayler detects corrupt batches and ignores the last one if it is corrupt, as if it never had been written, which is ok, since its transactions never got executed on the system in the first place. Why is it you cant simply ignore the last corrupt batch? A related issue: Is it possible for a crash during an append to a file to corrupt the last cluster, corrupting what had previously been completely syncd? See you, Klaus. On Tue, Jul 1, 2008 at 8:36 PM, Bill Burdick <bi...@mo...> wrote: > Sync isn't atomic for system failures. A power failure can happen before a > sync completes (and did many times with our system, because users were > allowing unattended laptops to run out of charge during heavy updating). > Because of this, if you take out the first sync and only use the last sync, > and there IS a failure during the sync, there could be a "noop" followed by > an incomplete journal record. The presence of a "noop" instead of an "end" > indicates that the next record is known not to be corrupted (in our system, > there is actually a batch of records after the "noop", not just a single > record, so you don't have to sync for every record), so we only write it > after the first sync completes. > > Bill > > > Klaus Wuestefeld wrote: >>> >>> The reason for the two syncs is that you can't guarantee the >>> order that dirty pages will be written to disk >>> >> >> Doesn't sync guarantee that all its dirty pages have been written? >> >> ------------------------------------------------------------------------- >> Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW! >> Studies have shown that voting for your favorite open source project, >> along with a healthy diet, reduces your potential for chronic lameness >> and boredom. Vote Now at http://www.sourceforge.net/community/cca08 >> _______________________________________________ >> Prevayler-coders mailing list >> Pre...@li... >> https://lists.sourceforge.net/lists/listinfo/prevayler-coders >> >> > > > ------------------------------------------------------------------------- > Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW! > Studies have shown that voting for your favorite open source project, > along with a healthy diet, reduces your potential for chronic lameness > and boredom. Vote Now at http://www.sourceforge.net/community/cca08 > _______________________________________________ > Prevayler-coders mailing list > Pre...@li... > https://lists.sourceforge.net/lists/listinfo/prevayler-coders > > |
From: Bill B. <bi...@mo...> - 2008-07-01 23:33:57
|
Sync isn't atomic for system failures. A power failure can happen before a sync completes (and did many times with our system, because users were allowing unattended laptops to run out of charge during heavy updating). Because of this, if you take out the first sync and only use the last sync, and there IS a failure during the sync, there could be a "noop" followed by an incomplete journal record. The presence of a "noop" instead of an "end" indicates that the next record is known not to be corrupted (in our system, there is actually a batch of records after the "noop", not just a single record, so you don't have to sync for every record), so we only write it after the first sync completes. Bill Klaus Wuestefeld wrote: >> The reason for the two syncs is that you can't guarantee the >> order that dirty pages will be written to disk >> > > Doesn't sync guarantee that all its dirty pages have been written? > > ------------------------------------------------------------------------- > Sponsored by: SourceForge.net Community Choice Awards: VOTE NOW! > Studies have shown that voting for your favorite open source project, > along with a healthy diet, reduces your potential for chronic lameness > and boredom. Vote Now at http://www.sourceforge.net/community/cca08 > _______________________________________________ > Prevayler-coders mailing list > Pre...@li... > https://lists.sourceforge.net/lists/listinfo/prevayler-coders > > |
From: Klaus W. <kla...@gm...> - 2008-07-01 19:29:35
|
oops... the code... ----------------------------------------- import java.io.EOFException; import java.io.IOException; public class PrevaylerJr { private final Object _system; private final AcidOutputStream _journal; public PrevaylerJr(Object initialState, String storageFile) throws Exception { AcidInputStream input = new AcidInputStream(storageFile); try { initialState = input.readObject(); while (true) ((Command)input.readObject()).executeOn(initialState); } catch (EOFException expected) {} _system = initialState; _journal = new AcidOutputStream(storageFile, _system); } synchronized public Object executeTransaction(Command transaction) throws Exception { _journal.append(transaction); return tryToExecute(transaction); } synchronized public Object executeQuery(Command query) { return tryToExecute(query); } private Object tryToExecute(Command command) { try { return command.executeOn(_system); } catch (OutOfMemoryError oome) { _journal.close(); throw oome; } } public static interface Command { Object executeOn(Object system); } } ------------ class AcidInputStream { public AcidInputStream(String fileName) throws IOException {} public Object readObject() throws IOException {return null;} } class AcidOutputStream { /** Atomically and durably replaces the previous journal file with the new entry using file rename manoeuvres.*/ public AcidOutputStream(String fileName, Object firstEntry) throws IOException {} public void append(Object entry) throws IOException {} public void close() {} } |
From: Klaus W. <kla...@gm...> - 2008-07-01 19:28:13
|
> The reason for the two syncs is that you can't guarantee the > order that dirty pages will be written to disk Doesn't sync guarantee that all its dirty pages have been written? |
From: Klaus W. <kla...@gm...> - 2008-07-01 19:26:56
|
16 semicolons... ...but I have extracted AcidInputStream and AcidOutputStream as Bill suggested. Their skeletons are there. Anyone take a shot at them? They could be folded into a single class such as Journal for a slight gain of cohesion, but that would be less familiar to people, I believe. I have also treated OutOfMemoryError. Should we catch all Errors? Opinions? Klaus |
From: Klaus W. <kla...@gm...> - 2008-07-01 18:07:53
|
> This is certainly a good exercise -- it's fun to see the code getting > smaller. For a tiny moment I considered playing with the code myself, > but I'd better just point out the bugs and see what y'all come up > with. ;) Yes. Dont be a spoilsport :) > First bug: What happens if a crash occurs in the middle of writing the > snapshot? Since you're reusing the same file, you've truncated the > file merely by opening it for writing, so you've lost all your data. Thats a bug. Is it possible and safe to rename a file with an open writestream for it? Klaus |
From: Klaus W. <kla...@gm...> - 2008-07-01 17:31:06
|
Hmm.... Very nice. I particularly liked merging both files. :) Klaus > Merged the two files into one, which allowed better inlining > and a yet smaller and simpler file (and one less import :)). > > Bill > > > import java.io.EOFException; > import java.io.FileInputStream; > import java.io.FileNotFoundException; > import java.io.FileOutputStream; > import java.io.ObjectInputStream; > import java.io.ObjectOutputStream; > > public class PrevaylerJr { > private Object _system; > private ObjectOutputStream _storage; > > public PrevaylerJr(Object initialState, String storageFile) throws > Exception { > try { > FileInputStream fis = new FileInputStream(storageFile); > ObjectInputStream input = new ObjectInputStream(fis); > > _system = input.readObject(); > while (true) { > Command transaction = (Command)input.readObject(); > transaction.executeOn(_system); > } > } catch (FileNotFoundException e) { > _system = initialState; > } catch (EOFException expected) { > //End of journal reached. :) > } > FileOutputStream fos = new FileOutputStream(storageFile); > _storage = new ObjectOutputStream(fos); > _storage.writeObject(_system); > } > synchronized public Object executeTransaction(Command transaction) throws > Exception { > _storage.writeObject(transaction); > _storage.flush(); > return transaction.executeOn(_system); > } > synchronized public Object executeQuery(Command query){ > return query.executeOn(_system); > } > public static interface Command { > Object executeOn(Object system); > } > } > > Bill Burdick wrote: >> >> Correction; 26 semicolons. Forgot to trim out a duplicate variable after >> an inline. >> >> Bill > > [snip] >> >> Bill Burdick wrote: >>> >>> Inlined your privates, changed snapshot name and journal name to >>> constructor args, moved Command to PrevaylerJr.Command, AND added a journal >>> flush(). 27 semicolons and it completely fits on my monitor. >>> >>> Bill >> >> [snip] >>> >>> Klaus Wuestefeld wrote: >>>> >>>> Goal: To find the simplest possible prevalence layer that: >>>> >>>> A) Is 100% correct - It cannot produce inconsistent results or cause >>>> loss of data unless files we write get lost/corrupted. >>>> >>>> B) Is suitable for 90% of apps out there - For example: If >>>> synchronizing all queries is already fast enough for 90% of apps out >>>> there, we do that. If not, we add a read/write lock. >>>> >>>> Prevayler1 had 330 semicolons, excluding imports. >>>> >>>> The game shall start with the code below which has 33 semicolons, >>>> including imports. Can you find any bugs? Can you make it simpler? Is >>>> it unsuitable for 90% of apps out there? >>>> >>>> Your move... ;) >>>> >>>> >>>> ------ >>>> >>>> import java.io.EOFException; >>>> import java.io.FileInputStream; >>>> import java.io.FileNotFoundException; >>>> import java.io.FileOutputStream; >>>> import java.io.IOException; >>>> import java.io.ObjectInputStream; >>>> import java.io.ObjectOutputStream; >>>> >>>> public class PrevaylerJr { >>>> private static final String SNAPSHOT_FILE_NAME = "snapshot"; >>>> private static final String JOURNAL_FILE_NAME = >>>> "transaction_journal"; >>>> >>>> private final Object _system; >>>> private final ObjectOutputStream _journal; >>>> >>>> public PrevaylerJr(Object initialState) throws Exception { >>>> Object previousState = readSnapshot(); >>>> _system = previousState != null >>>> ? previousState >>>> : initialState; >>>> applyJournal(); >>>> takeSnaphot(); >>>> _journal = openOutputStream(JOURNAL_FILE_NAME); >>>> } >>>> >>>> synchronized public Object executeTransaction(Command transaction) >>>> throws Exception { >>>> _journal.writeObject(transaction); >>>> return transaction.executeOn(_system); >>>> } >>>> >>>> synchronized public Object executeQuery(Command query){ >>>> return query.executeOn(_system); >>>> } >>>> >>>> >>>> private void applyJournal() throws Exception { >>>> try { >>>> tryToApplyJournal(); >>>> } catch (EOFException expected) { >>>> //End of journal reached. :) >>>> } >>>> } >>>> >>>> private void tryToApplyJournal() throws Exception { >>>> ObjectInputStream input = openInputStream(JOURNAL_FILE_NAME); >>>> while (true) { >>>> Command transaction = (Command)input.readObject(); >>>> transaction.executeOn(_system); >>>> } >>>> } >>>> >>>> >>>> private Object readSnapshot() throws Exception { >>>> ObjectInputStream input; >>>> try { >>>> input = openInputStream(SNAPSHOT_FILE_NAME); >>>> } catch (FileNotFoundException e) { >>>> return null; >>>> } >>>> return input.readObject(); >>>> } >>>> private void takeSnaphot() throws IOException { >>>> openOutputStream(SNAPSHOT_FILE_NAME).writeObject(_system); >>>> } >>>> >>>> private ObjectOutputStream openOutputStream(String fileName) throws >>>> IOException { >>>> FileOutputStream fos = new FileOutputStream(fileName); >>>> return new ObjectOutputStream(fos); >>>> } >>>> >>>> private ObjectInputStream openInputStream(String fileName) throws >>>> IOException { >>>> FileInputStream fis = new FileInputStream(fileName); >>>> return new ObjectInputStream(fis); >>>> } >>>> >>>> } >>>> >>>> >>>> public interface Command { >>>> >>>> Object executeOn(Object system); >>>> } >>>> >>>> >>>> ------------------------------------------------------------------------- >>>> Check out the new SourceForge.net Marketplace. >>>> It's the best place to buy or sell services for >>>> just about anything Open Source. >>>> http://sourceforge.net/services/buy/index.php >>>> _______________________________________________ >>>> Prevayler-coders mailing list >>>> Pre...@li... >>>> https://lists.sourceforge.net/lists/listinfo/prevayler-coders >>>> >>>> >>> >> > > > ------------------------------------------------------------------------- > Check out the new SourceForge.net Marketplace. > It's the best place to buy or sell services for > just about anything Open Source. > http://sourceforge.net/services/buy/index.php > _______________________________________________ > Prevayler-coders mailing list > Pre...@li... > https://lists.sourceforge.net/lists/listinfo/prevayler-coders > > |
From: Bill B. <bi...@mo...> - 2008-07-01 15:47:50
|
Yo! I agree that this is a problem, but there could also be a power failure, etc. after you write a transaction but before it is synced with the disk (which actually happened with frightening frequency on a recent project that was using Sqlite and corrupting it because of that). I say let's handle robustness in another place, like a wrapper that backs up the old file before creating the new Prevayler, etc. This will keep PrevaylerJr tiny and easy to understand. Making things robust always increases complexity. I'm not sure how the latest Prevayler addresses power failures, etc, w.r.t. its journal, but to make a robust journal for our app that could handle power failures and the like in our system, we ended up using the following pattern (with nio to improve speed): Each record in the journal is preceded by a marker which can be "end" or "noop" (really, it should be "noop"). To append a record to the journal, use the following process: 1) remember the current position in the journal 2) append the record 3) append an "end" marker 4) sync the file 5) remember the end position 6) seek to the remembered position before the journal entry 7) overwrite the "end" marker there with a "noop" 8) seek to the end position 9) sync the file To replay a journal, you read up to the "end" marker. This pattern ensures that if there is any corruption due to power failure, etc. it is safely guarded after an "end" marker and will never be replayed. So you will lose the record, but you won't get a corrupt stream. You can also play games with counters at the beginning of the file instead of end markers, etc. The reason for the two syncs is that you can't guarantee the order that dirty pages will be written to disk, so you need to sync before you overwrite the earlier "end" marker to ensure that you don't get a "noop" there before the record is fully written to disk. Bill Justin T. Sampson wrote: > Howdy, > > This is certainly a good exercise -- it's fun to see the code getting > smaller. For a tiny moment I considered playing with the code myself, > but I'd better just point out the bugs and see what y'all come up > with. ;) > > First bug: What happens if a crash occurs in the middle of writing the > snapshot? Since you're reusing the same file, you've truncated the > file merely by opening it for writing, so you've lost all your data. > (This applies to Klaus's 2-file version as well as Bill's 1-file > version.) > > Cheers, > Justin > > > On Mon, Jun 30, 2008 at 10:44 PM, Bill Burdick <bi...@mo...> wrote: > > >> 22 semicolons. Merged the two files into one, which allowed better inlining >> and a yet smaller and simpler file (and one less import :)). >> >> Bill >> >> >> import java.io.EOFException; >> import java.io.FileInputStream; >> import java.io.FileNotFoundException; >> import java.io.FileOutputStream; >> import java.io.ObjectInputStream; >> import java.io.ObjectOutputStream; >> >> public class PrevaylerJr { >> private Object _system; >> private ObjectOutputStream _storage; >> >> public PrevaylerJr(Object initialState, String storageFile) throws >> Exception { >> try { >> FileInputStream fis = new FileInputStream(storageFile); >> ObjectInputStream input = new ObjectInputStream(fis); >> >> _system = input.readObject(); >> while (true) { >> Command transaction = (Command)input.readObject(); >> transaction.executeOn(_system); >> } >> } catch (FileNotFoundException e) { >> _system = initialState; >> } catch (EOFException expected) { >> //End of journal reached. :) >> } >> FileOutputStream fos = new FileOutputStream(storageFile); >> _storage = new ObjectOutputStream(fos); >> _storage.writeObject(_system); >> } >> synchronized public Object executeTransaction(Command transaction) throws >> Exception { >> _storage.writeObject(transaction); >> _storage.flush(); >> return transaction.executeOn(_system); >> } >> synchronized public Object executeQuery(Command query){ >> return query.executeOn(_system); >> } >> public static interface Command { >> Object executeOn(Object system); >> } >> } >> > > ------------------------------------------------------------------------- > Check out the new SourceForge.net Marketplace. > It's the best place to buy or sell services for > just about anything Open Source. > http://sourceforge.net/services/buy/index.php > _______________________________________________ > Prevayler-coders mailing list > Pre...@li... > https://lists.sourceforge.net/lists/listinfo/prevayler-coders > > |
From: Justin T. S. <ju...@kr...> - 2008-07-01 09:19:04
|
Hi Bill, This is a common question. The only real requirement for correctness is that executeTransaction() must not return before the transaction is journaled, and no query may see the effects of a transaction until that transaction is journaled. In fact, in the case of a full system crash it really doesn't matter whether the transaction is journaled before or after being applied to the prevalent system is memory, since the prevalent system in memory is lost when the system crashes anyway. Whatever did get journaled gets replayed when the system starts up again, and as long as the above requirement is met, that will be consistent with what any client saw before the crash. The "real" Prevayler also takes advantage of this ordering for a performance benefit: Queries can continue executing against the prevalent system while a transaction is being written to the journal. Transaction execution only locks out query execution "instantaneously" for the moment when the transaction is actually applied to the prevalent system. If journaling happened after execution, queries would have to wait for the transaction to be journaled, because otherwise they would violate that primary requirement above by seeing the effects of the transaction after it's executed but before it's journaled. Notice that I did say "full system crash" above, though. That's, like, a power failure, or at least a hard kill of the process. If by "crash" you include "the transaction throws an exception", you have some other things to consider. A basic requirement of the prevalent pattern is that transactions have to be deterministic, so if an exception is thrown while executing a transaction it will be thrown every time, so that's actually okay -- the effect on the prevalent system is the same every time. No big deal. If your transactions are not deterministic, there's nothing special about exceptions -- even if they don't throw exceptions, nondeterministic transactions may produce different effects every time they run. But we like to say that's a bug in the transaction, not in Prevayler. But here's the second bug I'll point out in PrevaylerJr: Even though we can be kind of snobbish about the determinism requirement as it relates to exceptions (including runtime exceptions), we can't really in good conscience ignore *errors*. If an OutOfMemoryError occurs during transaction execution, there's no telling what state the prevalent system is in. Since an OutOfMemoryError can occur at almost any moment of a program, we really can't hold the programmer responsible; it's an inherently nondeterministic event, but it has nothing to do with the transaction being buggy. So, what do you do when transaction execution throws an error? The current PrevaylerJr just propogates the error to the caller and accepts the next transaction or query for execution, which will then execute against a corrupted prevalent system, which is a Bad Thing. Cheers, Justin On Mon, Jun 30, 2008 at 10:55 PM, Bill Burdick <bi...@mo...> wrote: > Question about A: shouldn't executeTransaction() execute the command on the > system BEFORE writing it to the journal, in case there is a crash while > executing it on the system? > > Bill |
From: Justin T. S. <ju...@kr...> - 2008-07-01 08:48:56
|
Howdy, This is certainly a good exercise -- it's fun to see the code getting smaller. For a tiny moment I considered playing with the code myself, but I'd better just point out the bugs and see what y'all come up with. ;) First bug: What happens if a crash occurs in the middle of writing the snapshot? Since you're reusing the same file, you've truncated the file merely by opening it for writing, so you've lost all your data. (This applies to Klaus's 2-file version as well as Bill's 1-file version.) Cheers, Justin On Mon, Jun 30, 2008 at 10:44 PM, Bill Burdick <bi...@mo...> wrote: > 22 semicolons. Merged the two files into one, which allowed better inlining > and a yet smaller and simpler file (and one less import :)). > > Bill > > > import java.io.EOFException; > import java.io.FileInputStream; > import java.io.FileNotFoundException; > import java.io.FileOutputStream; > import java.io.ObjectInputStream; > import java.io.ObjectOutputStream; > > public class PrevaylerJr { > private Object _system; > private ObjectOutputStream _storage; > > public PrevaylerJr(Object initialState, String storageFile) throws > Exception { > try { > FileInputStream fis = new FileInputStream(storageFile); > ObjectInputStream input = new ObjectInputStream(fis); > > _system = input.readObject(); > while (true) { > Command transaction = (Command)input.readObject(); > transaction.executeOn(_system); > } > } catch (FileNotFoundException e) { > _system = initialState; > } catch (EOFException expected) { > //End of journal reached. :) > } > FileOutputStream fos = new FileOutputStream(storageFile); > _storage = new ObjectOutputStream(fos); > _storage.writeObject(_system); > } > synchronized public Object executeTransaction(Command transaction) throws > Exception { > _storage.writeObject(transaction); > _storage.flush(); > return transaction.executeOn(_system); > } > synchronized public Object executeQuery(Command query){ > return query.executeOn(_system); > } > public static interface Command { > Object executeOn(Object system); > } > } |
From: Bill B. <bi...@mo...> - 2008-07-01 07:10:25
|
Here's a groovy script that exercises PrevaylerJr a little... import PrevaylerJr import PrevaylerJr.Command public static class AddItem implements Command, Serializable { int i; private static final long serialVersionUID = 0L; def executeOn(Object sys) { sys[sys.size()] = "duh: $i" } } prev = new PrevaylerJr([:], "/tmp/prevayler") println "old value..." prev.executeQuery({system -> for (k in system) { println k } } as Command) println "adding 10 items" for (i = 0; i < 10; i++) { prev.executeTransaction(new AddItem(i: i)) } Bill |
From: Bill B. <bi...@mo...> - 2008-07-01 06:43:07
|
By the way, I thought I should mention that if you subtract the import header lines, I cut the original code in half. Just in case, you know, anyone is counting... :D Bill Bill Burdick wrote: > 19 semicolons after cleanup. Sorry for all the spam, but this was a > cool exercise. > > > Bill [snip] > Bill Burdick wrote: >> 22 semicolons. Merged the two files into one, which allowed better >> inlining and a yet smaller and simpler file (and one less import :)). >> >> Bill > [snip] >> Bill Burdick wrote: >>> Correction; 26 semicolons. Forgot to trim out a duplicate variable >>> after an inline. >>> >>> Bill >> [snip] >>> Bill Burdick wrote: >>>> Inlined your privates, changed snapshot name and journal name to >>>> constructor args, moved Command to PrevaylerJr.Command, AND added a >>>> journal flush(). 27 semicolons and it completely fits on my monitor. >>>> >>>> Bill >>> [snip] >>>> Klaus Wuestefeld wrote: >>>>> Goal: To find the simplest possible prevalence layer that: >>>>> >>>>> A) Is 100% correct - It cannot produce inconsistent results or cause >>>>> loss of data unless files we write get lost/corrupted. >>>>> >>>>> B) Is suitable for 90% of apps out there - For example: If >>>>> synchronizing all queries is already fast enough for 90% of apps out >>>>> there, we do that. If not, we add a read/write lock. >>>>> >>>>> Prevayler1 had 330 semicolons, excluding imports. >>>>> >>>>> The game shall start with the code below which has 33 semicolons, >>>>> including imports. Can you find any bugs? Can you make it simpler? Is >>>>> it unsuitable for 90% of apps out there? >>>>> >>>>> Your move... ;) >>>>> >>>>> >>>>> ------ >>>>> >>>>> import java.io.EOFException; >>>>> import java.io.FileInputStream; >>>>> import java.io.FileNotFoundException; >>>>> import java.io.FileOutputStream; >>>>> import java.io.IOException; >>>>> import java.io.ObjectInputStream; >>>>> import java.io.ObjectOutputStream; >>>>> >>>>> public class PrevaylerJr { >>>>> private static final String SNAPSHOT_FILE_NAME = "snapshot"; >>>>> private static final String JOURNAL_FILE_NAME = >>>>> "transaction_journal"; >>>>> >>>>> private final Object _system; >>>>> private final ObjectOutputStream _journal; >>>>> >>>>> public PrevaylerJr(Object initialState) throws Exception { >>>>> Object previousState = readSnapshot(); >>>>> _system = previousState != null >>>>> ? previousState >>>>> : initialState; >>>>> applyJournal(); >>>>> takeSnaphot(); >>>>> _journal = openOutputStream(JOURNAL_FILE_NAME); >>>>> } >>>>> >>>>> synchronized public Object executeTransaction(Command >>>>> transaction) >>>>> throws Exception { >>>>> _journal.writeObject(transaction); >>>>> return transaction.executeOn(_system); >>>>> } >>>>> >>>>> synchronized public Object executeQuery(Command query){ >>>>> return query.executeOn(_system); >>>>> } >>>>> >>>>> >>>>> private void applyJournal() throws Exception { >>>>> try { >>>>> tryToApplyJournal(); >>>>> } catch (EOFException expected) { >>>>> //End of journal reached. :) >>>>> } >>>>> } >>>>> >>>>> private void tryToApplyJournal() throws Exception { >>>>> ObjectInputStream input = openInputStream(JOURNAL_FILE_NAME); >>>>> while (true) { >>>>> Command transaction = (Command)input.readObject(); >>>>> transaction.executeOn(_system); >>>>> } >>>>> } >>>>> >>>>> >>>>> private Object readSnapshot() throws Exception { >>>>> ObjectInputStream input; >>>>> try { >>>>> input = openInputStream(SNAPSHOT_FILE_NAME); >>>>> } catch (FileNotFoundException e) { >>>>> return null; >>>>> } >>>>> return input.readObject(); >>>>> } >>>>> private void takeSnaphot() throws IOException { >>>>> openOutputStream(SNAPSHOT_FILE_NAME).writeObject(_system); >>>>> } >>>>> >>>>> private ObjectOutputStream openOutputStream(String fileName) >>>>> throws >>>>> IOException { >>>>> FileOutputStream fos = new FileOutputStream(fileName); >>>>> return new ObjectOutputStream(fos); >>>>> } >>>>> >>>>> private ObjectInputStream openInputStream(String fileName) >>>>> throws IOException { >>>>> FileInputStream fis = new FileInputStream(fileName); >>>>> return new ObjectInputStream(fis); >>>>> } >>>>> >>>>> } >>>>> >>>>> >>>>> public interface Command { >>>>> >>>>> Object executeOn(Object system); >>>>> } >>>>> >>>>> ------------------------------------------------------------------------- >>>>> >>>>> Check out the new SourceForge.net Marketplace. >>>>> It's the best place to buy or sell services for >>>>> just about anything Open Source. >>>>> http://sourceforge.net/services/buy/index.php >>>>> _______________________________________________ >>>>> Prevayler-coders mailing list >>>>> Pre...@li... >>>>> https://lists.sourceforge.net/lists/listinfo/prevayler-coders >>>>> >>>>> >>>> >>> >> > > ------------------------------------------------------------------------ > > ------------------------------------------------------------------------- > Check out the new SourceForge.net Marketplace. > It's the best place to buy or sell services for > just about anything Open Source. > http://sourceforge.net/services/buy/index.php > ------------------------------------------------------------------------ > > _______________________________________________ > Prevayler-coders mailing list > Pre...@li... > https://lists.sourceforge.net/lists/listinfo/prevayler-coders > |
From: Bill B. <bi...@mo...> - 2008-07-01 05:53:18
|
Question about A: shouldn't executeTransaction() execute the command on the system BEFORE writing it to the journal, in case there is a crash while executing it on the system? Bill Bill Burdick wrote: > 19 semicolons after cleanup. Sorry for all the spam, but this was a > cool exercise. > > > Bill > > > import java.io.EOFException; > import java.io.FileInputStream; > import java.io.FileNotFoundException; > import java.io.FileOutputStream; > import java.io.ObjectInputStream; > import java.io.ObjectOutputStream; > > public class PrevaylerJr { > private Object _system; > private ObjectOutputStream _storage; > > public PrevaylerJr(Object initialState, String storageFile) throws > Exception { > try { > ObjectInputStream input = new ObjectInputStream(new > FileInputStream(storageFile)); > > _system = input.readObject(); > while (true) { > ((Command)input.readObject()).executeOn(_system); > } > } catch (FileNotFoundException e) { > _system = initialState; > } catch (EOFException expected) { > //End of journal reached. :) > } > _storage = new ObjectOutputStream(new > FileOutputStream(storageFile)); > _storage.writeObject(_system); > } > synchronized public Object executeTransaction(Command transaction) > throws Exception { > _storage.writeObject(transaction); > _storage.flush(); > return transaction.executeOn(_system); > } > synchronized public Object executeQuery(Command query){ > return query.executeOn(_system); > } > public static interface Command { > Object executeOn(Object system); > } > } > > > Bill Burdick wrote: >> 22 semicolons. Merged the two files into one, which allowed better >> inlining and a yet smaller and simpler file (and one less import :)). >> >> Bill > [snip] >> Bill Burdick wrote: >>> Correction; 26 semicolons. Forgot to trim out a duplicate variable >>> after an inline. >>> >>> Bill >> [snip] >>> Bill Burdick wrote: >>>> Inlined your privates, changed snapshot name and journal name to >>>> constructor args, moved Command to PrevaylerJr.Command, AND added a >>>> journal flush(). 27 semicolons and it completely fits on my monitor. >>>> >>>> Bill >>> [snip] >>>> Klaus Wuestefeld wrote: >>>>> Goal: To find the simplest possible prevalence layer that: >>>>> >>>>> A) Is 100% correct - It cannot produce inconsistent results or cause >>>>> loss of data unless files we write get lost/corrupted. >>>>> >>>>> B) Is suitable for 90% of apps out there - For example: If >>>>> synchronizing all queries is already fast enough for 90% of apps out >>>>> there, we do that. If not, we add a read/write lock. >>>>> >>>>> Prevayler1 had 330 semicolons, excluding imports. >>>>> >>>>> The game shall start with the code below which has 33 semicolons, >>>>> including imports. Can you find any bugs? Can you make it simpler? Is >>>>> it unsuitable for 90% of apps out there? >>>>> >>>>> Your move... ;) >>>>> >>>>> >>>>> ------ >>>>> >>>>> import java.io.EOFException; >>>>> import java.io.FileInputStream; >>>>> import java.io.FileNotFoundException; >>>>> import java.io.FileOutputStream; >>>>> import java.io.IOException; >>>>> import java.io.ObjectInputStream; >>>>> import java.io.ObjectOutputStream; >>>>> >>>>> public class PrevaylerJr { >>>>> private static final String SNAPSHOT_FILE_NAME = "snapshot"; >>>>> private static final String JOURNAL_FILE_NAME = >>>>> "transaction_journal"; >>>>> >>>>> private final Object _system; >>>>> private final ObjectOutputStream _journal; >>>>> >>>>> public PrevaylerJr(Object initialState) throws Exception { >>>>> Object previousState = readSnapshot(); >>>>> _system = previousState != null >>>>> ? previousState >>>>> : initialState; >>>>> applyJournal(); >>>>> takeSnaphot(); >>>>> _journal = openOutputStream(JOURNAL_FILE_NAME); >>>>> } >>>>> >>>>> synchronized public Object executeTransaction(Command >>>>> transaction) >>>>> throws Exception { >>>>> _journal.writeObject(transaction); >>>>> return transaction.executeOn(_system); >>>>> } >>>>> >>>>> synchronized public Object executeQuery(Command query){ >>>>> return query.executeOn(_system); >>>>> } >>>>> >>>>> >>>>> private void applyJournal() throws Exception { >>>>> try { >>>>> tryToApplyJournal(); >>>>> } catch (EOFException expected) { >>>>> //End of journal reached. :) >>>>> } >>>>> } >>>>> >>>>> private void tryToApplyJournal() throws Exception { >>>>> ObjectInputStream input = openInputStream(JOURNAL_FILE_NAME); >>>>> while (true) { >>>>> Command transaction = (Command)input.readObject(); >>>>> transaction.executeOn(_system); >>>>> } >>>>> } >>>>> >>>>> >>>>> private Object readSnapshot() throws Exception { >>>>> ObjectInputStream input; >>>>> try { >>>>> input = openInputStream(SNAPSHOT_FILE_NAME); >>>>> } catch (FileNotFoundException e) { >>>>> return null; >>>>> } >>>>> return input.readObject(); >>>>> } >>>>> private void takeSnaphot() throws IOException { >>>>> openOutputStream(SNAPSHOT_FILE_NAME).writeObject(_system); >>>>> } >>>>> >>>>> private ObjectOutputStream openOutputStream(String fileName) >>>>> throws >>>>> IOException { >>>>> FileOutputStream fos = new FileOutputStream(fileName); >>>>> return new ObjectOutputStream(fos); >>>>> } >>>>> >>>>> private ObjectInputStream openInputStream(String fileName) >>>>> throws IOException { >>>>> FileInputStream fis = new FileInputStream(fileName); >>>>> return new ObjectInputStream(fis); >>>>> } >>>>> >>>>> } >>>>> >>>>> >>>>> public interface Command { >>>>> >>>>> Object executeOn(Object system); >>>>> } >>>>> >>>>> ------------------------------------------------------------------------- >>>>> >>>>> Check out the new SourceForge.net Marketplace. >>>>> It's the best place to buy or sell services for >>>>> just about anything Open Source. >>>>> http://sourceforge.net/services/buy/index.php >>>>> _______________________________________________ >>>>> Prevayler-coders mailing list >>>>> Pre...@li... >>>>> https://lists.sourceforge.net/lists/listinfo/prevayler-coders >>>>> >>>>> >>>> >>> >> > |
From: Bill B. <bi...@mo...> - 2008-07-01 05:49:04
|
19 semicolons after cleanup. Sorry for all the spam, but this was a cool exercise. Bill import java.io.EOFException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class PrevaylerJr { private Object _system; private ObjectOutputStream _storage; public PrevaylerJr(Object initialState, String storageFile) throws Exception { try { ObjectInputStream input = new ObjectInputStream(new FileInputStream(storageFile)); _system = input.readObject(); while (true) { ((Command)input.readObject()).executeOn(_system); } } catch (FileNotFoundException e) { _system = initialState; } catch (EOFException expected) { //End of journal reached. :) } _storage = new ObjectOutputStream(new FileOutputStream(storageFile)); _storage.writeObject(_system); } synchronized public Object executeTransaction(Command transaction) throws Exception { _storage.writeObject(transaction); _storage.flush(); return transaction.executeOn(_system); } synchronized public Object executeQuery(Command query){ return query.executeOn(_system); } public static interface Command { Object executeOn(Object system); } } Bill Burdick wrote: > 22 semicolons. Merged the two files into one, which allowed better > inlining and a yet smaller and simpler file (and one less import :)). > > Bill [snip] > Bill Burdick wrote: >> Correction; 26 semicolons. Forgot to trim out a duplicate variable >> after an inline. >> >> Bill > [snip] >> Bill Burdick wrote: >>> Inlined your privates, changed snapshot name and journal name to >>> constructor args, moved Command to PrevaylerJr.Command, AND added a >>> journal flush(). 27 semicolons and it completely fits on my monitor. >>> >>> Bill >> [snip] >>> Klaus Wuestefeld wrote: >>>> Goal: To find the simplest possible prevalence layer that: >>>> >>>> A) Is 100% correct - It cannot produce inconsistent results or cause >>>> loss of data unless files we write get lost/corrupted. >>>> >>>> B) Is suitable for 90% of apps out there - For example: If >>>> synchronizing all queries is already fast enough for 90% of apps out >>>> there, we do that. If not, we add a read/write lock. >>>> >>>> Prevayler1 had 330 semicolons, excluding imports. >>>> >>>> The game shall start with the code below which has 33 semicolons, >>>> including imports. Can you find any bugs? Can you make it simpler? Is >>>> it unsuitable for 90% of apps out there? >>>> >>>> Your move... ;) >>>> >>>> >>>> ------ >>>> >>>> import java.io.EOFException; >>>> import java.io.FileInputStream; >>>> import java.io.FileNotFoundException; >>>> import java.io.FileOutputStream; >>>> import java.io.IOException; >>>> import java.io.ObjectInputStream; >>>> import java.io.ObjectOutputStream; >>>> >>>> public class PrevaylerJr { >>>> private static final String SNAPSHOT_FILE_NAME = "snapshot"; >>>> private static final String JOURNAL_FILE_NAME = >>>> "transaction_journal"; >>>> >>>> private final Object _system; >>>> private final ObjectOutputStream _journal; >>>> >>>> public PrevaylerJr(Object initialState) throws Exception { >>>> Object previousState = readSnapshot(); >>>> _system = previousState != null >>>> ? previousState >>>> : initialState; >>>> applyJournal(); >>>> takeSnaphot(); >>>> _journal = openOutputStream(JOURNAL_FILE_NAME); >>>> } >>>> >>>> synchronized public Object executeTransaction(Command transaction) >>>> throws Exception { >>>> _journal.writeObject(transaction); >>>> return transaction.executeOn(_system); >>>> } >>>> >>>> synchronized public Object executeQuery(Command query){ >>>> return query.executeOn(_system); >>>> } >>>> >>>> >>>> private void applyJournal() throws Exception { >>>> try { >>>> tryToApplyJournal(); >>>> } catch (EOFException expected) { >>>> //End of journal reached. :) >>>> } >>>> } >>>> >>>> private void tryToApplyJournal() throws Exception { >>>> ObjectInputStream input = openInputStream(JOURNAL_FILE_NAME); >>>> while (true) { >>>> Command transaction = (Command)input.readObject(); >>>> transaction.executeOn(_system); >>>> } >>>> } >>>> >>>> >>>> private Object readSnapshot() throws Exception { >>>> ObjectInputStream input; >>>> try { >>>> input = openInputStream(SNAPSHOT_FILE_NAME); >>>> } catch (FileNotFoundException e) { >>>> return null; >>>> } >>>> return input.readObject(); >>>> } >>>> private void takeSnaphot() throws IOException { >>>> openOutputStream(SNAPSHOT_FILE_NAME).writeObject(_system); >>>> } >>>> >>>> private ObjectOutputStream openOutputStream(String fileName) >>>> throws >>>> IOException { >>>> FileOutputStream fos = new FileOutputStream(fileName); >>>> return new ObjectOutputStream(fos); >>>> } >>>> >>>> private ObjectInputStream openInputStream(String fileName) >>>> throws IOException { >>>> FileInputStream fis = new FileInputStream(fileName); >>>> return new ObjectInputStream(fis); >>>> } >>>> >>>> } >>>> >>>> >>>> public interface Command { >>>> >>>> Object executeOn(Object system); >>>> } >>>> >>>> ------------------------------------------------------------------------- >>>> >>>> Check out the new SourceForge.net Marketplace. >>>> It's the best place to buy or sell services for >>>> just about anything Open Source. >>>> http://sourceforge.net/services/buy/index.php >>>> _______________________________________________ >>>> Prevayler-coders mailing list >>>> Pre...@li... >>>> https://lists.sourceforge.net/lists/listinfo/prevayler-coders >>>> >>>> >>> >> > |
From: Bill B. <bi...@mo...> - 2008-07-01 05:42:03
|
22 semicolons. Merged the two files into one, which allowed better inlining and a yet smaller and simpler file (and one less import :)). Bill import java.io.EOFException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class PrevaylerJr { private Object _system; private ObjectOutputStream _storage; public PrevaylerJr(Object initialState, String storageFile) throws Exception { try { FileInputStream fis = new FileInputStream(storageFile); ObjectInputStream input = new ObjectInputStream(fis); _system = input.readObject(); while (true) { Command transaction = (Command)input.readObject(); transaction.executeOn(_system); } } catch (FileNotFoundException e) { _system = initialState; } catch (EOFException expected) { //End of journal reached. :) } FileOutputStream fos = new FileOutputStream(storageFile); _storage = new ObjectOutputStream(fos); _storage.writeObject(_system); } synchronized public Object executeTransaction(Command transaction) throws Exception { _storage.writeObject(transaction); _storage.flush(); return transaction.executeOn(_system); } synchronized public Object executeQuery(Command query){ return query.executeOn(_system); } public static interface Command { Object executeOn(Object system); } } Bill Burdick wrote: > Correction; 26 semicolons. Forgot to trim out a duplicate variable > after an inline. > > Bill [snip] > Bill Burdick wrote: >> Inlined your privates, changed snapshot name and journal name to >> constructor args, moved Command to PrevaylerJr.Command, AND added a >> journal flush(). 27 semicolons and it completely fits on my monitor. >> >> Bill > [snip] >> Klaus Wuestefeld wrote: >>> Goal: To find the simplest possible prevalence layer that: >>> >>> A) Is 100% correct - It cannot produce inconsistent results or cause >>> loss of data unless files we write get lost/corrupted. >>> >>> B) Is suitable for 90% of apps out there - For example: If >>> synchronizing all queries is already fast enough for 90% of apps out >>> there, we do that. If not, we add a read/write lock. >>> >>> Prevayler1 had 330 semicolons, excluding imports. >>> >>> The game shall start with the code below which has 33 semicolons, >>> including imports. Can you find any bugs? Can you make it simpler? Is >>> it unsuitable for 90% of apps out there? >>> >>> Your move... ;) >>> >>> >>> ------ >>> >>> import java.io.EOFException; >>> import java.io.FileInputStream; >>> import java.io.FileNotFoundException; >>> import java.io.FileOutputStream; >>> import java.io.IOException; >>> import java.io.ObjectInputStream; >>> import java.io.ObjectOutputStream; >>> >>> public class PrevaylerJr { >>> private static final String SNAPSHOT_FILE_NAME = "snapshot"; >>> private static final String JOURNAL_FILE_NAME = >>> "transaction_journal"; >>> >>> private final Object _system; >>> private final ObjectOutputStream _journal; >>> >>> public PrevaylerJr(Object initialState) throws Exception { >>> Object previousState = readSnapshot(); >>> _system = previousState != null >>> ? previousState >>> : initialState; >>> applyJournal(); >>> takeSnaphot(); >>> _journal = openOutputStream(JOURNAL_FILE_NAME); >>> } >>> >>> synchronized public Object executeTransaction(Command transaction) >>> throws Exception { >>> _journal.writeObject(transaction); >>> return transaction.executeOn(_system); >>> } >>> >>> synchronized public Object executeQuery(Command query){ >>> return query.executeOn(_system); >>> } >>> >>> >>> private void applyJournal() throws Exception { >>> try { >>> tryToApplyJournal(); >>> } catch (EOFException expected) { >>> //End of journal reached. :) >>> } >>> } >>> >>> private void tryToApplyJournal() throws Exception { >>> ObjectInputStream input = openInputStream(JOURNAL_FILE_NAME); >>> while (true) { >>> Command transaction = (Command)input.readObject(); >>> transaction.executeOn(_system); >>> } >>> } >>> >>> >>> private Object readSnapshot() throws Exception { >>> ObjectInputStream input; >>> try { >>> input = openInputStream(SNAPSHOT_FILE_NAME); >>> } catch (FileNotFoundException e) { >>> return null; >>> } >>> return input.readObject(); >>> } >>> private void takeSnaphot() throws IOException { >>> openOutputStream(SNAPSHOT_FILE_NAME).writeObject(_system); >>> } >>> >>> private ObjectOutputStream openOutputStream(String fileName) throws >>> IOException { >>> FileOutputStream fos = new FileOutputStream(fileName); >>> return new ObjectOutputStream(fos); >>> } >>> >>> private ObjectInputStream openInputStream(String fileName) >>> throws IOException { >>> FileInputStream fis = new FileInputStream(fileName); >>> return new ObjectInputStream(fis); >>> } >>> >>> } >>> >>> >>> public interface Command { >>> >>> Object executeOn(Object system); >>> } >>> >>> ------------------------------------------------------------------------- >>> >>> Check out the new SourceForge.net Marketplace. >>> It's the best place to buy or sell services for >>> just about anything Open Source. >>> http://sourceforge.net/services/buy/index.php >>> _______________________________________________ >>> Prevayler-coders mailing list >>> Pre...@li... >>> https://lists.sourceforge.net/lists/listinfo/prevayler-coders >>> >>> >> > |
From: Bill B. <bi...@mo...> - 2008-07-01 05:29:28
|
Correction; 26 semicolons. Forgot to trim out a duplicate variable after an inline. Bill import java.io.EOFException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class PrevaylerJr { private final Object _system; private final ObjectOutputStream _journal; public PrevaylerJr(Object initialState, String snapshotFile, String journalFile) throws Exception { Object previousState = null; try { previousState = openInputStream(snapshotFile).readObject(); } catch (FileNotFoundException e) { //NOTHING } _system = previousState != null ? previousState : initialState; try { ObjectInputStream input = openInputStream(journalFile); while (true) { Command transaction = (Command)input.readObject(); transaction.executeOn(_system); } } catch (EOFException expected) { //End of journal reached. :) } openOutputStream(snapshotFile).writeObject(_system); _journal = openOutputStream(journalFile); } synchronized public Object executeTransaction(Command transaction) throws Exception { _journal.writeObject(transaction); _journal.flush(); return transaction.executeOn(_system); } synchronized public Object executeQuery(Command query){ return query.executeOn(_system); } private ObjectOutputStream openOutputStream(String fileName) throws IOException { FileOutputStream fos = new FileOutputStream(fileName); return new ObjectOutputStream(fos); } private ObjectInputStream openInputStream(String fileName) throws IOException { FileInputStream fis = new FileInputStream(fileName); return new ObjectInputStream(fis); } public static interface Command { Object executeOn(Object system); } } Bill Burdick wrote: > Inlined your privates, changed snapshot name and journal name to > constructor args, moved Command to PrevaylerJr.Command, AND added a > journal flush(). 27 semicolons and it completely fits on my monitor. > > Bill [snip] > Klaus Wuestefeld wrote: >> Goal: To find the simplest possible prevalence layer that: >> >> A) Is 100% correct - It cannot produce inconsistent results or cause >> loss of data unless files we write get lost/corrupted. >> >> B) Is suitable for 90% of apps out there - For example: If >> synchronizing all queries is already fast enough for 90% of apps out >> there, we do that. If not, we add a read/write lock. >> >> Prevayler1 had 330 semicolons, excluding imports. >> >> The game shall start with the code below which has 33 semicolons, >> including imports. Can you find any bugs? Can you make it simpler? Is >> it unsuitable for 90% of apps out there? >> >> Your move... ;) >> >> >> ------ >> >> import java.io.EOFException; >> import java.io.FileInputStream; >> import java.io.FileNotFoundException; >> import java.io.FileOutputStream; >> import java.io.IOException; >> import java.io.ObjectInputStream; >> import java.io.ObjectOutputStream; >> >> public class PrevaylerJr { >> >> private static final String SNAPSHOT_FILE_NAME = "snapshot"; >> private static final String JOURNAL_FILE_NAME = >> "transaction_journal"; >> >> private final Object _system; >> private final ObjectOutputStream _journal; >> >> >> public PrevaylerJr(Object initialState) throws Exception { >> Object previousState = readSnapshot(); >> _system = previousState != null >> ? previousState >> : initialState; >> >> applyJournal(); >> takeSnaphot(); >> _journal = openOutputStream(JOURNAL_FILE_NAME); >> } >> >> synchronized public Object executeTransaction(Command transaction) >> throws Exception { >> _journal.writeObject(transaction); >> return transaction.executeOn(_system); >> } >> >> synchronized public Object executeQuery(Command query){ >> return query.executeOn(_system); >> } >> >> >> private void applyJournal() throws Exception { >> try { >> tryToApplyJournal(); >> } catch (EOFException expected) { >> //End of journal reached. :) >> } >> } >> >> private void tryToApplyJournal() throws Exception { >> ObjectInputStream input = openInputStream(JOURNAL_FILE_NAME); >> while (true) { >> Command transaction = (Command)input.readObject(); >> transaction.executeOn(_system); >> } >> } >> >> >> private Object readSnapshot() throws Exception { >> ObjectInputStream input; >> try { >> input = openInputStream(SNAPSHOT_FILE_NAME); >> } catch (FileNotFoundException e) { >> return null; >> } >> return input.readObject(); >> } >> >> private void takeSnaphot() throws IOException { >> openOutputStream(SNAPSHOT_FILE_NAME).writeObject(_system); >> } >> >> private ObjectOutputStream openOutputStream(String fileName) throws >> IOException { >> FileOutputStream fos = new FileOutputStream(fileName); >> return new ObjectOutputStream(fos); >> } >> >> private ObjectInputStream openInputStream(String fileName) throws >> IOException { >> FileInputStream fis = new FileInputStream(fileName); >> return new ObjectInputStream(fis); >> } >> >> } >> >> >> public interface Command { >> >> Object executeOn(Object system); >> >> } >> >> ------------------------------------------------------------------------- >> >> Check out the new SourceForge.net Marketplace. >> It's the best place to buy or sell services for >> just about anything Open Source. >> http://sourceforge.net/services/buy/index.php >> _______________________________________________ >> Prevayler-coders mailing list >> Pre...@li... >> https://lists.sourceforge.net/lists/listinfo/prevayler-coders >> >> > |
From: Bill B. <bi...@mo...> - 2008-07-01 05:24:22
|
Inlined your privates, changed snapshot name and journal name to constructor args, moved Command to PrevaylerJr.Command, AND added a journal flush(). 27 semicolons and it completely fits on my monitor. Bill import java.io.EOFException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class PrevaylerJr { private final Object _system; private final ObjectOutputStream _journal; public PrevaylerJr(Object initialState, String snapshotFile, String journalFile) throws Exception { Object result = null; try { result = openInputStream(snapshotFile).readObject(); } catch (FileNotFoundException e) { //NOTHING } Object previousState = result; _system = previousState != null ? previousState : initialState; try { ObjectInputStream input = openInputStream(journalFile); while (true) { Command transaction = (Command)input.readObject(); transaction.executeOn(_system); } } catch (EOFException expected) { //End of journal reached. :) } openOutputStream(snapshotFile).writeObject(_system); _journal = openOutputStream(journalFile); } synchronized public Object executeTransaction(Command transaction) throws Exception { _journal.writeObject(transaction); _journal.flush(); return transaction.executeOn(_system); } synchronized public Object executeQuery(Command query){ return query.executeOn(_system); } private ObjectOutputStream openOutputStream(String fileName) throws IOException { FileOutputStream fos = new FileOutputStream(fileName); return new ObjectOutputStream(fos); } private ObjectInputStream openInputStream(String fileName) throws IOException { FileInputStream fis = new FileInputStream(fileName); return new ObjectInputStream(fis); } public static interface Command { Object executeOn(Object system); } } Klaus Wuestefeld wrote: > Goal: To find the simplest possible prevalence layer that: > > A) Is 100% correct - It cannot produce inconsistent results or cause > loss of data unless files we write get lost/corrupted. > > B) Is suitable for 90% of apps out there - For example: If > synchronizing all queries is already fast enough for 90% of apps out > there, we do that. If not, we add a read/write lock. > > Prevayler1 had 330 semicolons, excluding imports. > > The game shall start with the code below which has 33 semicolons, > including imports. Can you find any bugs? Can you make it simpler? Is > it unsuitable for 90% of apps out there? > > Your move... ;) > > > ------ > > import java.io.EOFException; > import java.io.FileInputStream; > import java.io.FileNotFoundException; > import java.io.FileOutputStream; > import java.io.IOException; > import java.io.ObjectInputStream; > import java.io.ObjectOutputStream; > > public class PrevaylerJr { > > private static final String SNAPSHOT_FILE_NAME = "snapshot"; > private static final String JOURNAL_FILE_NAME = "transaction_journal"; > > private final Object _system; > private final ObjectOutputStream _journal; > > > public PrevaylerJr(Object initialState) throws Exception { > Object previousState = readSnapshot(); > _system = previousState != null > ? previousState > : initialState; > > applyJournal(); > takeSnaphot(); > _journal = openOutputStream(JOURNAL_FILE_NAME); > } > > synchronized public Object executeTransaction(Command transaction) > throws Exception { > _journal.writeObject(transaction); > return transaction.executeOn(_system); > } > > synchronized public Object executeQuery(Command query){ > return query.executeOn(_system); > } > > > private void applyJournal() throws Exception { > try { > tryToApplyJournal(); > } catch (EOFException expected) { > //End of journal reached. :) > } > } > > private void tryToApplyJournal() throws Exception { > ObjectInputStream input = openInputStream(JOURNAL_FILE_NAME); > while (true) { > Command transaction = (Command)input.readObject(); > transaction.executeOn(_system); > } > } > > > private Object readSnapshot() throws Exception { > ObjectInputStream input; > try { > input = openInputStream(SNAPSHOT_FILE_NAME); > } catch (FileNotFoundException e) { > return null; > } > return input.readObject(); > } > > private void takeSnaphot() throws IOException { > openOutputStream(SNAPSHOT_FILE_NAME).writeObject(_system); > } > > private ObjectOutputStream openOutputStream(String fileName) throws > IOException { > FileOutputStream fos = new FileOutputStream(fileName); > return new ObjectOutputStream(fos); > } > > private ObjectInputStream openInputStream(String fileName) throws IOException { > FileInputStream fis = new FileInputStream(fileName); > return new ObjectInputStream(fis); > } > > } > > > public interface Command { > > Object executeOn(Object system); > > } > > ------------------------------------------------------------------------- > Check out the new SourceForge.net Marketplace. > It's the best place to buy or sell services for > just about anything Open Source. > http://sourceforge.net/services/buy/index.php > _______________________________________________ > Prevayler-coders mailing list > Pre...@li... > https://lists.sourceforge.net/lists/listinfo/prevayler-coders > > |
From: Justin T. S. <ju...@kr...> - 2008-07-01 01:02:58
|
Okay, cool. I'll send you the first and last production releases of Prevayler 1 off-list. Cheers, Justin On Sun, Jun 29, 2008 at 4:42 PM, Laurian Gridinoc <la...@gm...> wrote: > 2008/6/28 Justin T. Sampson <ju...@kr...>: > >> Yeah, I managed to find all the Prevayler 1 releases hidden in >> SourceForge. None of them had been in CVS; development only moved to >> CVS once Prevayler 2 development had already started. >> >> What are you looking for in particular? I might be able to send you >> what you need easier than you could find it. > > I'm looking for the simplest implementation (the first) and I dream of > porting it to JavaScript somehow :) [I use server-side javascript] > > Cheers, > -- > Laurian Gridinoc, purl.org/net/laur |
From: Klaus W. <kla...@gm...> - 2008-06-30 21:32:44
|
Goal: To find the simplest possible prevalence layer that: A) Is 100% correct - It cannot produce inconsistent results or cause loss of data unless files we write get lost/corrupted. B) Is suitable for 90% of apps out there - For example: If synchronizing all queries is already fast enough for 90% of apps out there, we do that. If not, we add a read/write lock. Prevayler1 had 330 semicolons, excluding imports. The game shall start with the code below which has 33 semicolons, including imports. Can you find any bugs? Can you make it simpler? Is it unsuitable for 90% of apps out there? Your move... ;) ------ import java.io.EOFException; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class PrevaylerJr { private static final String SNAPSHOT_FILE_NAME = "snapshot"; private static final String JOURNAL_FILE_NAME = "transaction_journal"; private final Object _system; private final ObjectOutputStream _journal; public PrevaylerJr(Object initialState) throws Exception { Object previousState = readSnapshot(); _system = previousState != null ? previousState : initialState; applyJournal(); takeSnaphot(); _journal = openOutputStream(JOURNAL_FILE_NAME); } synchronized public Object executeTransaction(Command transaction) throws Exception { _journal.writeObject(transaction); return transaction.executeOn(_system); } synchronized public Object executeQuery(Command query){ return query.executeOn(_system); } private void applyJournal() throws Exception { try { tryToApplyJournal(); } catch (EOFException expected) { //End of journal reached. :) } } private void tryToApplyJournal() throws Exception { ObjectInputStream input = openInputStream(JOURNAL_FILE_NAME); while (true) { Command transaction = (Command)input.readObject(); transaction.executeOn(_system); } } private Object readSnapshot() throws Exception { ObjectInputStream input; try { input = openInputStream(SNAPSHOT_FILE_NAME); } catch (FileNotFoundException e) { return null; } return input.readObject(); } private void takeSnaphot() throws IOException { openOutputStream(SNAPSHOT_FILE_NAME).writeObject(_system); } private ObjectOutputStream openOutputStream(String fileName) throws IOException { FileOutputStream fos = new FileOutputStream(fileName); return new ObjectOutputStream(fos); } private ObjectInputStream openInputStream(String fileName) throws IOException { FileInputStream fis = new FileInputStream(fileName); return new ObjectInputStream(fis); } } public interface Command { Object executeOn(Object system); } |
From: Laurian G. <la...@gm...> - 2008-06-29 23:42:44
|
2008/6/28 Justin T. Sampson <ju...@kr...>: > Yeah, I managed to find all the Prevayler 1 releases hidden in > SourceForge. None of them had been in CVS; development only moved to > CVS once Prevayler 2 development had already started. > > What are you looking for in particular? I might be able to send you > what you need easier than you could find it. I'm looking for the simplest implementation (the first) and I dream of porting it to JavaScript somehow :) [I use server-side javascript] Cheers, -- Laurian Gridinoc, purl.org/net/laur |
From: Justin T. S. <ju...@kr...> - 2008-06-28 16:46:40
|
Yeah, I managed to find all the Prevayler 1 releases hidden in SourceForge. None of them had been in CVS; development only moved to CVS once Prevayler 2 development had already started. What are you looking for in particular? I might be able to send you what you need easier than you could find it. (And I've included all the Prevayler 1 releases in the Git repository I've created, which I'll be publishing Real Soon Now...) Cheers, Justin On Sat, Jun 28, 2008 at 6:34 AM, Laurian Gridinoc <la...@gr...> wrote: > Wow, I think I found it, dig in this archive > http://sourceforge.net/project/showfiles.php?group_id=117032&package_id=130280 > > It has Command.java and not Transaction :) > > Laurian > > 2008/6/28 Laurian Gridinoc <la...@gm...>: >> Hello, >> >> I tried >> cvs -z3 -d:pserver:ano...@pr...:/cvsroot/prevayler >> co -r1.1 -P prevayler >> >> and what I got does look very much as Prevayler 2, even if the >> Readme.txt says 1.03. >> >> Did anybody managed to retrieve from somewhere the original >> lightweight wonder code? >> >> Thanks, >> -- >> Laurian Gridinoc, purl.org/net/laur |
From: Laurian G. <la...@gr...> - 2008-06-28 13:34:05
|
Wow, I think I found it, dig in this archive http://sourceforge.net/project/showfiles.php?group_id=117032&package_id=130280 It has Command.java and not Transaction :) Laurian 2008/6/28 Laurian Gridinoc <la...@gm...>: > Hello, > > I tried > cvs -z3 -d:pserver:ano...@pr...:/cvsroot/prevayler > co -r1.1 -P prevayler > > and what I got does look very much as Prevayler 2, even if the > Readme.txt says 1.03. > > Did anybody managed to retrieve from somewhere the original > lightweight wonder code? > > Thanks, > -- > Laurian Gridinoc, purl.org/net/laur > -- Laurian Gridinoc, purl.org/net/laur |
From: Laurian G. <la...@gm...> - 2008-06-28 13:16:08
|
Hello, I tried cvs -z3 -d:pserver:ano...@pr...:/cvsroot/prevayler co -r1.1 -P prevayler and what I got does look very much as Prevayler 2, even if the Readme.txt says 1.03. Did anybody managed to retrieve from somewhere the original lightweight wonder code? Thanks, -- Laurian Gridinoc, purl.org/net/laur |