I’d like to take a moment to talk about persistence. In general, what I mean by that is storing stuff to disk or some other medium that persists (hah) beyond when the application is shut down. Back in July, I mentioned a little about the issues I was having. Mostly, storing to database isn’t fast enough for me because of the amount of data and how it needs to be stored. I looked at a lot of options including pretty much all of the Python ORMs. I did however miss Zope’s object store, but… How better to learn about Object Oriented Data Stores than to write one myself?
I wrote the actual OODS in about a weekend. Currently, it generates a unique id for an instance of a class and from that a filename to pickle that class to. That sounds pretty easy, right? Not so much. It has to handle nested classes (and save the inner classes to their own files). It has to handle circular references within classes, and it has to be pretty solid. What I came up with does all this.
In addition, I thought it would be nice to include some database-like features such as performing queries. So, you can create indexes on class member variables and perform queries on them as you like. The query language is pretty simple and straight forward, I think:
ds = DataStore()
result = ds.query("Users").fetchResults(q.firstname == "Frank" & q.age >= 20)
That would return all users with “Frank” as their first name who were also over 20 years old. Fun stuff. Queries run off of indexes, so they should be pretty darn fast. Speaking of fast, I’d like to mention that for a fair sized world, saving only takes a couple of seconds. It used to be a couple of minutes. Plus, I haven’t noticed any jittering due to the physics engine on the server not being able to keep up as was normal when saving to DB.
There are a lot of future features I’d like to add. One of the features that has been designed in but not implemented is the ability for it to connect to a store over PB, and automatically do so when trying to open a store that is locked. A little bit simpler than that is to make a configurable storage tree so you can specify different data stores depending on class or other values. In particular, this would be good for sectioning off things that actually do fit into a database to a real database. You could also use it for high availability and other fun things that MV3D doesn’t need in its persistence mechanism. Remember (speaking to myself too here), MV3D only persists stuff a) for simplicity during development, and b) in case master and secondary servers go down.
Something that may make sense to do soon is to send the store index and any query indexes to a database because a database would be very good at handling that. And finally, creating a method to do transactions and either commit them or roll them back would be pretty nifty. Once again, this isn’t something that really helps MV3D’s needs at all. Oh yeah, one more thing, doing the relational db equiv of joins may be handy, dunno.
Anyway, I’m considering releasing this separate from MV3D. I’m interested to hear what people think of that possibility. I suspect it would have uses outside of 3D games, especially if some of the features I mentioned were implemented.
Oh yes, of course all of this is compatible with Twisted and everything either runs async or deferred into a thread.
I’m still having a little trouble realizing that even though I’m not currently running my dev MV3D server, I can start it up at any time and hop right in to the world the same way it was. It’s actually been a timesaver while testing the issues I had integrating the datastore into MV3D.
Speaking of that, I mentioned that I wrote the datestore in about a weekend? Well, it’s taken a lot of work to integrate it into MV3D, but it is working very well now. Most of the problems relate to the unpresistability of ode stuff. What happens now is everything that uses physics registers a callback that gets called when everything is loaded. The callback sets up its physics attributes. There are all sorts of interdependencies to worry about, and I haven’t looked at a lot of them in a year, so it was not fun to fix. For instance, one of the issues I solved today was that after the first save/restore, objects other than people would fall through the ground. I examined the data on the server many times– usually this happens when the objects aren’t in the same physical space as the rest of the world, but this wasn’t the case. It ended up being that ODE areas need to register themselves with their realm so that the realm can handle collision detection inter and intra area. Yeah that took quite a few hours of frustration to finally track down. It all works great now though.
What’s next?
One feature I didn’t mention about the datastore: vacuuming. When things get “deleted” from the datastore, they are removed from the indexes, but not from disk. So every once in a while, you’ll want to check all the files on disk against the index and delete them if they aren’t in there.
After that, I’m thinking about some client enhancements. Mostly stuff to make testing faster such as a config file for the client that lets me skip the Ogre screen size selection and connect/select pc windows. With that will probably come some ui stuff for client configuration as well as having the client handle the list of connections. Currently, it’s hard coded, so if you don’t want one that’s on the list, you need to enter it manually.
I’m also thinking about refactoring. There’s a lot that could use it, and it would be nice to catch up on unit tests to go along with refactored code (which would include switching the unit tests to use trial). I need to find a way to do integration type testing for MV3D.. Anyone have ideas? I have a non graphical client that can connect to a server as a pc and do stuff. It’s annoying, but I guess I could go with that approach.
That’s all for now. Still need help in the art department. :-/