[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