Transactions

I assume transaction support in the stack will be discussed in more detail with the release of the stack extension guide. However, I was wondering if I could get a few questions answered.

We are looking at building a PersistanceManager which would be fairly similar to the DataManager but with better ACID garuntees. We were thinking of using JDO to do that. (Aka litterly the PersistanceManager)… However, we would like to hide the transactional nature of it from the developer and bury it in the Manager implementation. Call it DurableManager for lack of a better name…

Will the stack API allow integration of additional transactional contexts. (Aka we want to use both the DataManager’s transactional context as well as the JDO transactional context at the same time). Using the DataManager for short lived non-shared state management and the DurableManager for long lived shared data management. (NOTE: This means that when a Task runs we would like to integrate the JDO’s transaction.begin() and when it finishes without an exception it would call transaction.commit() or if an exception was thrown it would call transaction.rollback() all behind the senes or in the manager implementation)…

Yes.

Services can participate in the transaction. You will have to associate your transactional context with the system transaction (the simplest most common way is with a Map in your service), but you will get called for prepare/commit/abort to do whatever you need to do.

JK

Another question. JDO has the ability to be single threaded of multithreaded. I know Sun has gone to great pains to try and make the application level appear as a single threaded model. But I am guessing I will have to build the JDOPersistanceManager to be multithread safe? Is that correct? Or can I rely on Sun’s single thread model to ensure that the manager will never have concurrent calls made to it?

The underlying system is indeed multi-threaded, and you’ll see that behavior. That said, there are a few properties that you can rely on to make this easier:

  • Transactions are associated with a single thread. This means that a given transaction will always proceed synchronously. The Service you write will see multiple concurrent transactions, but each thread will be handling a different transaction. If you need to manage any per-transaction state, it will not have any concurrency issues.
  • Threads are associated with a single transaction, for the lifetime of that transaction. This means that a given thread will only process one transaction at a time. If you need to store thread-local state (etc.) you can.
  • What you actually end up writing is a Manager and a Service. The Manager defines the interface that the Application uses, and typically calls into the Service to do much of its “real” work. The Manager actually sees the same single-threaded view as an Application. It’s only the Service that needs to think about concurrent access and Transaction state. So, you can always factor your code to take advantage of this relationship, if it makes things easier.

Does that help clarify what’s going on?

With all that said, let me ask a question :slight_smile: What exactly are you trying to use the existing DataManager for in your system? It sounds like it will no longer be managing persistent data, so I’m not sure what role it’s playing. Put another way, why a new manager instead of a new implementation against the existing DataManager interface? Then you could just swap out our DataManager and any other games can use your new implementation. Also, can you qualify what you mean by “better ACID guarantees”? I’m curious what’s not being provided right now, and whether you think there’s something important that we should provide…

seth

Yes thank you…

We have two types of objects in our application. Session oriented (non-shared), and long-term shared. We plan on using the DataManager to handle the session oriented (non-shared) objects such as a user for example. There will be numerous state properties of a user that need to exist for the lifespan of the user’s session or for a game session but no longer. On the other hand we have data that is maintained in RDBMs outside of the game server. Our Game Server application will be but one entity that accesses that data. While most of our clients are java, serialized data does not make for good quieries if you know what I mean. And a simple name oriented primary key is insufficient for our data structures.

Examples of applications that share data with our application include data entry, reporting, web applications, database based batch processes that do various things, etc…

It seems the DataPersistance mechanism in the game server is sufficient when all the data is being maintained and handled internal to the game server and nowhere else. But if you have a piece of data that the game server and a web server both need access to for different purposes?? Well it doesn’t work real well there… And well disk is getting cheaper by the day but never-the-less it doesn’t make much sense to have multiple copies of your data… Trying to keep it in synch would not be worth the effort.

I was under the understanding that the Durability requirements of the DataManager were relaxed to improve performance. For state items (ake session oreinted stuff) that is fine and desirable. (Thus the reason we still intend to use it). But when you are commiting a sale of say a $50,000 object with all the associated credit look ups etc you need absolute garuntees of durability plus you need extended control over the transaction.

As for replacing the DataManager I was not aware that could be done. Even so there are a number of very relevant uses for it even if shared data isn’t one of them.

Some people might say our application is a game. But it is not in the typical sense. Its real money and real business that is driving it…

Hi floersh. Thanks for the detail, and sorry to be slow in following-up.

The DataManager implementation that we’re providing gets any relaxed semantics from its use of BerkleyDB. You could certainly configure BDB to provide the guarantees you need, so this is really a configuration detail, not an artifact of the DataManager itself. That said, it doesn’t sound like you need to take that performance hit for all your data, and it also sounds like you need SQL-ish query and sharing abilities, so a new interface probably does make sense. FYI, you can indeed write alternate implementations of DataManager. We provide a default one, because some implementation is required to run the system, but you can always swap out what we’re providing.

Now, just so you know, the current stack has a limitation that will find if you try to build the Service you described. The currently implemented Transaction Coordinator is a simple, single-node implementation that doesn’t work with external coordinators and cannot support more than a single durable participant in a given transaction. Since what you need to implement would have to be a durable participant, the current stack does not support your use case. This is a known limitation of our implementation, and the only reason we haven’t addressed it is that we simply haven’t had the time and resources. We plan to support the use case you describe. We may try to make the Coordinator pluggable, so that you could write your own to support this case, or we may wait until we can build a richer implementation ourselves. In the meantime, please let me know if you want to talk in more detail about what’s going on here.

To other folks: please let me know if this kind of use-case is important to you. It will help us figure out how to prioritize this development work!

seth

Yes I would definately like more info on this. I am currently working on a Manager API for integrating JDO PersistanceManagers into the stack (Of course it is currently constrained by the fact that I have no idea what the stack allows and doesn’t allow.)… Part of that will eventually involve connection pooling, thread integration, as well as transaction integration. It sounds as if the transaction integration and thread control may be a bit more difficult or even impossible?

I did some analysis of our requirements and have found only two real use cases. The first is a single transaction for any given user generated event (aka user message)… The second is multiple independant transactions. I figured a child task could allow us to achieve that. I have yet to find a case where we needed inner transactions nor optamistic transactions. However, the transactions will in all cases span a number of objects. Obviously, otherwise we wouldn’t really need transactions…

Now my knowledge of your server’s internals is limited at this point. But the transaction coordination of JDO is a combination of code level and database level. Obviously transactions are begun, commited, rolled back at the application level. But the interoperability of the transaction within the data sphere is accomplished via the various JDBC isolation levels. My current train of thought suggests that for each task I would get a PersistanceManager from a pool of PersistanceManagers and bind it and its transaction object to the task. When prepare() was called within the stack it would call the transaction begin() method. Likewise, when abort() or comit() where called on the context it would pass those on to rollback() and comit() on the transaction.

As the task executed it would access JDO PersistanceCapable objects as needed by the implementation. Each of these objects would or would not be able to access/change their various properties based on the transaction isolation level of the under lying JDBC connection the PersistanceManager was using?? So in essance wouldn’t the coordinator in this case be the database? How does the Sun Game Server effect that? Does it have something to do with the existing DataManager interoperating with this additional PersistanceManager?

I guess I am not sure what you are talking about when you refer to the Coordinator and whether it is the JDO world or the DataManager world the issue applies to…

Now one area of concern for me was what would happen if a ManagedObject held a reference to a PersistanceCapable object? I am not sure at this point. But I do have a solution assuming it becomes an issue. And that is via another Manager called the DelegateManager which provides application custom Delegate implementations to the runtime environment. These Delegates would provide, via JDOQL, access to various top level JDO objects negating any need to maintain references to them. Any particular task could load the objects it needs when it needs them to do the operations it needs to do and release them. And thus our ManagedObjects would simply need to keep reference to the keys necessary to locate the particular object instance. Those keys being simple Serializable objects. Of course JDBC transaction isolation levels would allow synchronization across the various nodes of a cluster as it relates to loading/persisting the state of these JDO objects.

Now JDO implementations do some cache optimization. I am not sure exactly how I might go about dealing with that. I guess maybe the Coordination you speak of may effect how that is managed?

Hi floersh. I think this discussion will be an easier one to have once the code/docs are published. Basically, Darkstar has its own notion of participants, transactions, etc. The Services are the participants, and they can join a Darkstar transaction. Darkstar transactions do not allow any kind of nesting, though they certainly do allow you to queue up future tasks. When a Darkstar transaction commits, all joined participants are called to prepare and commit.

Because we have our own notion of the transactional context, we also need our own coordinator. This is the thing that creates transaction state, handles participation and voting, knows how to abort transactions, etc. This is the thing that, currently, only supports a single Durable participant. As I said, this is a known limitation, and one that we plan to address. This might be handled with a new implementation, or even by using an external coordinator (e.g., XA).

Now, of course, any given participant may have its own notion of transactions that it manages with external services, like a database. Certainly our DataService implementation uses Berkeley DB transactions. When the DataService is called to commit, it in turn has to manage the transaction it has open with the database. This is expected behavior, and something we will certainly continue to support. Ditto threads; we know that Services will need their own threaded facilities, and in fact the guide that Jeff is writing includes something along these lines.

Let me know if you have any specific details you want to walk through, but otherwise we should probably wait until you can see the APIs, so we can talk in a little more detail, and so I don’t have to be so mysterious :slight_smile:

seth

I can certainly wait. Its not that far in the future and we have a huge sell job here internal to do anyway that will, I am sure, take longer…

Thanks for the info