2

I am working on a game where a player is switched between servers based on their location in the game world to give the illusion of a single server while maintaining scalability. When a player joins the server their data is loaded from a database (MongoDB) and when they quit or change server their data is saved.

My problem arises from cases where a players data is modified from a separate server from the player which needs to happen occasionally. The data in the database is changed but when the player leaves or changes server the data is overwritten: Example Image

To solve this problem I was thinking of storing only modified data as usually the data you want is the most recently changed. However when trying to find ways to do this I have noticed a lack of cases where this has been done. Is there any good reasons not to do this and use another method to ensure modified data is not overwritten? The only problem I could think of is data consistency where fields are updated and only some of them are overwritten potentially putting the player in an invalid state, which could be avoided fairly easily by updating all dependent fields together.

If there any other reasons against persisting only a selection of an object or any other ways to solve this problem that doesn't introduce any major problems I would love to hear of them.

user2248702
  • 2,741
  • 7
  • 41
  • 69
  • 1
    You might need to consider that even though you have explained your case adequately it is still a little too broad a question in general. What you are asking for really ( and can search for ) is the general "is dirty" concept. Which means data that has actually "changed" is the "only" data you want to actually modify. On the end storage concept, MongoDB and other engines all have ways to "only" modify that data. Once you have identified what you want to modify of course. –  Jun 06 '15 at 13:49
  • Just for comment. On the "cute" side. If you submitted an "object" to MongoDB that actually does not differ from the existing object in any way then nothing will actually be committed as a write operation. But what you seem to be asking here really is a way to see "what data" has actually changed, and then only commit those as a change operation. As said earlier, a bit broad. –  Jun 06 '15 at 13:52
  • @user3561036 This question was more about possible problems with only persisting parts of objects and alternatives to doing this than about the actual implementation. – user2248702 Jun 06 '15 at 14:07

1 Answers1

2

This is a classic example of underlying state change between DB and code.

Add an integer to your player profile/data document; call it v. Let's assume v = 6.

When the player joins, the server loads the record. The server knows it's "local" view of the data is v = 6. When the player leaves, the code will call

findAndModify({query: {"userID":"ID1","v":6}, update: {"$inc": { v: 1}, "$set": { fldtochange: newval, anotherfldtochange: newval2  } } });

We show literal 6 here for simplicity but it would be a variable populated during the server load. This command will succeed ONLY if the original value of v = 6 is intact. If someone has changed it, no update will occur. You can take a variety of paths to recover including a re-read of the data and doing a delta to the state in your local server. If v = 6 is still there, it is atomically incremented +1 (e.g. to 7) and the rest of the fields set with new values.

Buzz Moschetti
  • 7,057
  • 3
  • 23
  • 33
  • A bit of a late comment, but sometimes when updating the object I am using update with upsert. If the query contains a version number that doesn't match anything then a document is created. Is there a way that I can use update with upsert without creating additional documents? – user2248702 Jun 27 '15 at 05:12