How To Use EditGrid to Create a Database With A Slick User Interface With Zero Lines of Code
February 27th, 2008Morphing Grid by Dan Allison.
Ever find yourself with a data collection, and you can see the steps in your head, create a form, create a table? It’s a dry task that gets dryer by the minute once you find yourself once again creating that paged results table for the contact us or event registration form you’ve created a thousand times before.
I can’t tell you how much slicker it is to send that data directly to an EditGrid workbook. It is a quick and easy database that is intuitive for your users. Instead of a paged html table, their information is available as rich full-featured spreadsheet.
comments
Disabled Form Elements Are Not Submitted
January 6th, 2008Not in Firefox, at least.
Sheaf
December 15th, 2007Sheaf Toss by Ian Langworth.
Last Saturday morning, on my way to Fair Grinds for my morning coffee, something occurred to me about persistent object storage. I’m less certain as to why. I’ve not thought about that component of my application development in a long time. I implemented persistent storage using the basics of the malloc algorithm in a project that I called Bento.
Pages of Blocks with Identifiers
When I got to Fair Grinds I began to exchange instant messages with Brian Kerr or Ann Arbor, Michigan. I described the idea as follows.
A fixed page length, 8k or 16k. The address is a file position plus a short. It is a big address, I know. The blocks are stored in a page with a number to identify the blocks followed by the object length followed by the block data. To find a block, to the file position, load the page into memory, skip through the blocks until you find the one with the matching block number.
Within a page the block is sought so that within a page blocks can be relocated within the page. If a block is deleted, the contents following the block are shifted up. The moved blocks can still be found because we are skipping through the page form an offset.
Then Brian started asking questions and sorting out details. It was good to have someone think about the problem.
If you have a block larger than a single page, you break it up among pages. You use however many empty pages necessary to hold the block and put the remainder in a page that contains many blocks.
The file format supports journaling, so there is a concept of isolation. Isolation is modeled with a Mutator object. Changes to the file are called a mutation, rather than a transaction, since transaction implies a lot more hocus-pocus.
While the file format can handle concurrent requests, it cannot handle concurrent requests on the same block. It is up to the application developer to ensure that no two threads mutate the same block at the same time. It is up to the application developer to ensure that no thread reads a mutating block. The only manipulation that is permitted concurrently is read. Block allocations are going to be visible only to the thread that allocated them. Writes and frees are going to require synchronization on the part of the application.
In memory, a sorted map of lists of blocks with free space remaining is kept sorted on the amount remaining rounded down to an alignment. When a block is allocated it is rounded up to the next alignment and we search for the block with the smallest amount remaining that can fit the block. That block is used.
Separately, there is a list of pages that have been entirely emptied through deallocations.
The file format uses ByteBuffer objects kept in memory as buffers that represent the contents on disk. The ByteBuffer objects indicate what the disk will look like when the contents of the page are journaled. They can be out of sync with the file, but that is OK. This discrepancy between our in memory representation of the file and the on disk representation of the file allow us to implement journaling.
Commits to this file format are journaled. There are two journals available, an external file journal and an internal journal that uses pages in the file. For the internal journals the file format keeps a block of pointers in the header of the file. The default number of pointers is 64. To create a journal, one of the pointers is set to the address of the first page in a linked list of pages. This is set in the ByteBuffer that is in memory, however and not on disk. The address of the start of the linked list of journal pages is now written out until the journal commits. It is written out last and the file channel is forced to flush. Thus, on disk the pointers will only ever point to a complete journal.
In addition to a linked list of journal pages of journal actions, like allocate, write and free, the journal needs to allocate temporary blocks where the mutation can write changes without disturbing the actual block in memory or on disk. The temporary block contains the applications intent. It is copied over to the actual block during commit.
Delete Makes the File Grow
I set out to implement the file format. I’d hoped to have tests running on Monday. I begged off engagements. I sat before my computer and worked through each next logical task. I was not finished on Monday, so I forced myself to stop and resume my civic pursuits, while fiddling with the code and the concepts in my free time.
By Friday, the idea of the block identifier has run it’s course, before the code was complete.
An external journal meant that this file format would create a nice and compact file format. An internal journal would fill the file with empty journal pages. What really tripped me up was when I realized deletion could not be implemented as simply shifting the blocks following a deleted block up if I wanted the deletion to be journaled. The destination and the source of the copy were on the same page. If the page were to be corrupted their would be no way to recreate it. I would have to allocate copies of blocks following the deleted block in the journal. They would be safely on disk as part of the journal commit. The delete would then copy the blocks over from the journal.
This meant that a delete would actually cause the file to grow and grow large. If the first block on a page is deleted, a temporary block has to be allocated for all the other pages in the block. I couldn’t imagine myself very happy with a larger file.
Can the file ever shrink? Sure. If the pages at the end of the file empty, then we can truncate the file. We can always be on the lookout for empty pages at the end of a mutation and rewind the file.
But then, imagine a case where an application deletes a very large collection of objects. These deletions consume all the free pages for the journal. Then the deletions begin to create new journal pages at the end of the file. If another thread allocates a new object, the other thread couldn’t make use of all the free space created in isolation so it would have to allocate a block from a new page at the end of the file. When the thread with the deletions completes, it will free all of the journal pages, but the file cannot be rewound because there is a user page following all the freed journal pages.
The file would have a huge swath of empty pages just before the last page in the file. They would be reused eventually, but how counter-intuitive to delete objects and have the database grow in size on disk. That would be so hard to explain to people. It feels wrong.
I started to think about indirection, and a name for a new project.
Not a Blog Post, Not a Wiki Page, I Want An Ongoing Conversation
December 4th, 2007Lance Hill sent me a link to another article by Adam Nossiter in the New York Times. Nossiter is off drinking at the trough of Uptown’s conventional wisdom in his article Whites Take a Majority on New Orleans’s Council.
There is a post at Think New Orleans called Is Adam Nossiter a Tool? That question stands. I don’t want to write a new article about the matter, but rather have people continue to discuss the issue under the existing article. What I really want is a website that will allow me to feature this article once again, or rather bring this subject up in the context of the conversations that took place before. It is very important to preserve both the existing discussion and the timeline of events.
Which is something that is common to most of my civic writing. I do want to encourage participation in the conversation, so I want to resurrect the existing conversation, with the exisiting participants. Most people subscribe to email notifications of comments of a particular post. To notify them that Adam Nossiter is banging on about race and quoting Greg Rigamer, I need to continue the discussion under the previous post.
Although, I’m pleased that WordPress is now performing acceptably, both blogs and Wikis fail to make my efforts in New Orleans easier.
PLEAC-Groovy
December 3rd, 2007I came across this resource months ago. I forgot about it until I recently discovered an email that I sent to the author expressing my awe. It is a translation of the Perl Cookbook into Groovy.
I Want To Put My Asides Aside
August 6th, 2007That is going to be my programming project tomorrow. Putting my asides in the sidebar of the index page. I’d like to have categories breakout out with a main content channel and asides. I want my asides to be permitted to be longer than one paragraph as well. Asides are also called life streams. For added effect it could be animated on mouse over, or it could scroll itself.
Enter Mix
July 18th, 2007I’ve been thinking about what a real build system for Java will be.
It will be dependency management system. One that does not execute a task unless necessary. One that maintains it’s own tree of dependencies. It knows how to check the expiration of file dependencies and networked dependencies.
Targets are not names of procedures, but artifacts that are constructed. This is how it is done in dependency management systems such as Make. Targets are represented by actual artifacts, such as object files produced by a C compiler, or an executable produced by a linker.
There will be imaginary targets, as well. Imaginary targets will force a build. Programmatic targets are imaginary targets that expire based on application specific logic.
Targets are built using rules. There are specific rules and generic rules. Specific rules might create a specific jar from a collection of class files. A generic rule might describe how to turn a C file into an object file.
It will be Java, all Java. You will invoke it using Java.
java -jar mix.jar compile
A Mix project is expressed in the Java programming language. No XML. No external languages. No property files, except those managed by Mix itself.
Mix will depend on a JDK 1.4 solution at every turn, forgoing the en vogue library, the shinny objects of the moment, in order to reduce the footprint of the build system. (You won’t have to download Commons Logging.)
Mix will be a client/server application. It will create a process that will listen on a port for commands. Commands are sent as serialized objects. Startup times are greatly reduced.
Reporting will be done with standards compliant XHTML that follows a strict set of formatting rules, for the application of the CSS stylesheet of your choice. No XML data dump. No transforms. Direct to something that you can read. Each build will create a website with a dashboard index and reports from each task.
Dependency management extends to external dependencies; libraries. Your build can use a local cache of any remote repository. To add a resource, you fire off Mix at the command line with a name and URL. A checksum will be generated and you will be prompted to add the resource and checksum pair to your build.
The resource now is available to your Mix project as an InputStream that can be read and written to file anywhere you like or you can reference the file in the local cache.
When you deploy the application and someone else builds your project on their machine, the resource manager will pull the resource and perform the checksum automatically.
As noted above, the tasks are written in Java. You can use a default task as the action to take for a target. You can use a chain of tasks that will be performed one after another. You can build write your own task in Java, it will get compiled an executed the next time you invoke Mix.
Thus, Mix is a dependency system for your command line Java applications.
Asides on the Side
July 17th, 2007I want to move my Asides to the sidebar in all my blogs. Little thoughts news in brief. I like having a carefully crafted message at the top of the main channel of my blogs.
| « Previous Entries |




