how do servers work with databases?

Started by
13 comments, last by Antheus 15 years, 4 months ago
Quote:Original post by Ryan Lepidi

Wouldn't that mean retrieving all user objects just to do the search?


It might. Object databases operate on objects - relational databases on, well, relational queries.

This is why choice of data representation matters. Considering you want to retrieve "all that have over $500". First determine what "all" means, than what "have over $500" means.

In SQL-based syntax, you might want to select all IDs from player table where Money column has value over 500. Result of such query would be an array of IDs, or better yet, a set of rows each containing an id.

In object database, there would be Player object, which would have Money property. So if you somehow query for (Player.Money > 500), you receive a set of Player objects.

The most trivial form of database caching can be achieved via memcached. That cache is basically a map (SQL_query, Query_result). When you wish to perform an SQL query, you first pass the query to cache. If cache contains such a query, it returns previous result, if not, you query the database directly. Obvious issues such as stale data and concurrency considerations apply.

It should be obvious that each type of database is suitable for a particular task. While object databases do support queries, they are better suited for OO approach, which ad-hoc query of (money>500) isn't.


In MMO state the ability to generate delta updates is often desirable. Instead of writing entire object, when something changes, such as money, you generate delta update, something in the form of (ID, Money_key, 500) tuple.

Object cache in this case could listen to delta updates and know which properties of an object changed. Then, after X seconds or after Y updates, it would perform relevant SQL queries to update those values.

The benefit of such approach is that at any given time, only a small subset of properties will be changing. If two players are in combat, their health will be changing twice per second. By using such cache, this would result only in one SQL query once in a while, as cache would see fit.

This approach achieves two things. It relieves the SQL server of many small queries, and additionally allows all changes to be committed as single transaction, rather than many small transactions.
Advertisement
The object database (or cache) should keep an index of properties. If you index the "money" property, then finding the set of objects with the "money" property greater than $500 isn't very hard.

You can view the general backing store of an object as a simple table:

Object ID, Property, Value

The "object" is then the self-union of that table for all tuples of Object Id == your id.

However, databases don't like N-way self-joins like that (a 9-way self-join of ours basically killed Oracle a few years ago...), so you might want to create a table per property instead. Whether an object has a given property or not is determined by selecting that objects' ID out of that property table.

As long as you cache the joined object in RAM, and only write changes back to the database, either of those approaches can be both efficient and flexible.
enum Bool { True, False, FileNotFound };
Ok I'm trying to figure out how I can implement this. Let me know what you guys think - is there anything I'm doing inefficiently or wrong? Am I forgetting anything that is going to kill me later? I am using Stackless Python 2.6.1 (3.0 isn't out yet).

If you aren't familiar with python, a good feature of it is you can essentially "hook" the function that is called when a specific field of a class is called. Basically that means that I can use this function to see if a specific field is initialized when it is called; if it has, I return it, if not, that means I need to grab it from the database, set it, then return it. So that is how I plan on using an object frontend with the database backend.

Given what I said above, objects are only loaded into memory as needed. This means that I can't do a "Select all players with money > 500" query since not even all of the objects are there to query. In this case, I just skip the cache and call the database.

When I update a value in an object, I hook the call feature again and I keep a dictionary (like a map in c++) that has all the variables as keys and a boolean value on each that is set to TRUE if it has been changed and FALSE otherwise. When it's time to send the updates, only the values that have changed are updated, and all flags are set back to FALSE.

Any thoughts?
Quote:that is how I plan on using an object frontend with the database backend


Your scheme sounds like something that implements the lazy update. However, doing lazy object inflation is going to introduce lag each time you want to get any property from an object, the first time. This will likely lead to poor user-visible performance. I would inflate the entire object if any part of the object is needed, because running a query for all properties from the database at once is likely to be significantly more efficient than running single queries for each property.


enum Bool { True, False, FileNotFound };
Quote:Original post by Ryan Lepidi

This means that I can't do a "Select all players with money > 500" query since not even all of the objects are there to query.


Why would you want your server to run such query in the first place? For an RPG/RTS, the most touched properties will probably be position/orientation and health/energy/mana.

How many objects will be on one server? Tens of thousands shouldn't be a problem as such, at least not memory-wise.

And what kind of simulation will it be?

This topic is closed to new replies.

Advertisement