[crossfire] C++/Qt server version
Mark Wedel
mwedel at sonic.net
Tue Nov 25 02:20:38 CST 2008
Alex Schultz wrote:
> On Mon, 24 Nov 2008 22:06:40 -0800
> Mark Wedel <mwedel at sonic.net> wrote:
>
>> Shared strings: While perhaps no reason to get rid of them, I also
>> wonder how necessary they are now days. They do simplify
>> comparisons. And with C++ and proper class descriptions, they can be
>> made to be safe (have to use class functions to modify the name,
>> and it knows to do the right thing). But shared strings date back a
>> long time in crossfire, to when systems had much less memory and this
>> wasmore a concern. They certainly do still save space, but the amount
>> of space saved may not be worth the extra handling. It should
>> certainly be reviewed - many design decisions date back to when
>> computers where much less capable than they are now, and may not make
>> much sense.
>
> I'm note sure exactly how much space is saved, but I think there's a
> high chance they may still be desirable due to the shear amount of
> floor tile objects and such in CF if someone is running through a large
> number of large maps. Now it's possible the benefit might be small
> these days but in any case, I don't think that making decisions about
> shared strings can go much further without getting real data on how
> much space they save.
I looked on metalforge, and with the strings command, this is what came back:
3879 entries, 2476263 refs, 8196 links.
So a good amount of space is being saved. But if we presume an average length
of 10 for the strings, it amounts to 24 MB. The calculation is trickier - on
the one side, there is overhead of the shared string structure itself in
crossfire, but the counter is that if malloc is being used, it has some overhead
of its own, so the difference there may not be that great.
I suspect a much greater space savings may result in using C++ classes for
objects, and allocating the type specific section of the object as needed. For
example, for all those floor tiles, they really don't use much beyond the most
basic fields of the object structure (name, x, y, etc). They don't need
anything of the str, dex, hp fields, resistances, etc. So if objects were
redone such that it was like 'oh, this is an equippable object - let me allocate
the pointer for that', and 'oh, this is a floor object - nothing more is
needed', one could get a pretty big space savings.
Because of those 2476263 strings, probably almost every one of them is
attached to some object. In fact, looking at metalforge, it looks like about 70
MB of space is used for objects. So C++ inheritance could save a lot of that space.
>
> <snip>
>
>> Distributed server archetype: Need more details - having redundancy
>> (client rerouting with minimal data loss) might not be worth the
>> effort - have to make sure you don't have two servers trying to
>> control the same area, recovery when one comes back on-line, etc.
>> But being distributed (this server is responsible for scorn region,
>> this one for navar city, etc) to reduce load may make sense, with
>> there being smarts to transfer character detail between those, etc.
>> In terms of server failure/crash, the client could improve that
>> experience - most servers restart when they crash, so it is really to
>> the client to pop up a window with something like 'connection lost -
>> trying to reconnect (with spinning disk or something)'.
>>
>> Multithread server: I think this is a must - computers are moving
>> more and more towards multiple cores, and less towards raw speed, and
>> for crossfire to make use of those really requires multithreading. I
>> always thought that multithreading at the map level would make the
>> most sense - this potentially lets one use many threads (and thus
>> cores) and is probably the simplest way to go.
>
> I was recently thinking about server multithreading, and now I'm
> thinking, why bother with threads? Why not do a model like
> one-process-per-every-few-maps instead of multithreading? It eliminates
> potential issues with mutexes and locking and such, transfering things
> between the processes could be done by IPC. The further advantage of
> going with a multi-process model instead of multi-thread model, is that
> much of the very same code could be adapted to make a distributed
> server possible if anyone ever thinks there's a need. I don't
> currently think there's a need for a distributed server system, but a
> multi-process model would lend well to adapting to distributed at a
> later date. Furthermore, a multi-process model would also make server
> crashes less disruptive because they'd usually just kill off a map or 3
> instead of everywhere. Perhaps we should make a pros/cons chart to
> outline the merits of multi-process and multi-thread to compare?
Maybe. Note that being able to run on a single box is a necessity, since that
probably would be the way many folks run the system.
note that processes tend to be a lot heavier than threads. And moving data
back and forth is trickier.
In a multithreaded model, you'd make a few locks, and could move the player
structure from one map to the next. In a multi process model, you'd need to
transfer all of the data - not just the player, but all the inventory,
statistics on all of those, etc. And you may need to given them new inventory
tags, since the ones they had in the old server may conflict (which then
requires some extra work in the protocol - object tag 12345 is now 5678)
Also, I think re-joining existing servers may be more difficult. If I'm in
scorn and go off into a new building, and that building is not currently active,
it goes and forks off a new process and the existing file descriptor lives OK.
However, if that building already has process associated with it (another player
entered it), we can't fork - instead, my client has to get directed to that
other process. And most likely, that means a different port (13329, 13330, ...)
on that server.
That is doable, but does require yet some other process to monitor all those
forked processes out there to know what is available and what to connect to.
Also, for folks running servers behind firewalls (probably most everyone) it
means opening a potentially large number of ports.
For same reason, it makes things like chats harder - one could make a good
case those could/should get moved out of bad in any case, but in the current
model, each process would only really be able to talk to clients it knows about.
All of this is doable - may require proxy type programs. It's unclear if its
really a simpler solution.
Note that most of these issues apply in the distributed model, but I'd
personally see that as more static (if it is region based, probably a config
file that says what the different regions are and ip:port number they run on -
if I'm running that on my single server, I'd know what ports to open up). And
for some of that, the limitations may make sense (a person can't chat with
someone in navar, etc).
If things are rewritten in C++ with classes, then locking probably gets done
in the base classes, so may not be that hard - don't really know. There is the
disadvantage that if one thread crashes, it basically takes all the threads with
it (one could try to recover, but probably make things worse not better because
data may be in a bad state - perhaps depends on the nature of the fault. If
something in the malloc or other low level libraries, you're in bad shape. But
if it is something in crossfire which it considers fatal but doesn't necessarily
mean data corruption, it may just be a case of freeing what data one can and
terminating that thread). You're probably still better off restarting the server
- it doesn't take that long now days.
More information about the crossfire
mailing list