Created a peer-aware DatabaseConfigRegistry that broadcasts changed runtime

configuration information to other peers so that they all remain in sync.

Also nixed constructor arguments to the peer manager so that it can be created
at server construct time like all other managers and be available for the
twisty maze of inter-registration that takes place during the manager init
process.


git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4814 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
Michael Bayne
2007-08-16 20:53:17 +00:00
parent b18ebdbc53
commit f90a39207f
5 changed files with 159 additions and 46 deletions
@@ -0,0 +1,124 @@
//
// $Id$
//
// Narya library - tools for developing networked games
// Copyright (C) 2002-2007 Three Rings Design, Inc., All Rights Reserved
// http://www.threerings.net/code/narya/
//
// This library is free software; you can redistribute it and/or modify it
// under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation; either version 2.1 of the License, or
// (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
package com.threerings.admin.server;
import java.util.ArrayList;
import java.util.logging.Level;
import com.samskivert.io.PersistenceException;
import com.samskivert.jdbc.depot.PersistenceContext;
import com.samskivert.util.Invoker;
import com.threerings.io.SimpleStreamableObject;
import com.threerings.io.Streamable;
import com.threerings.util.StreamableTuple;
import com.threerings.presents.dobj.AttributeChangedEvent;
import com.threerings.presents.dobj.DObject;
import com.threerings.presents.peer.server.PeerManager;
import static com.threerings.admin.Log.log;
/**
* A database backed config registry that registers with the peer system and synchronizes with its
* peers when configuration fields are changed.
*/
public class PeeredDatabaseConfigRegistry extends DatabaseConfigRegistry
{
public PeeredDatabaseConfigRegistry (PersistenceContext ctx, Invoker invoker,
PeerManager peermgr)
throws PersistenceException
{
super(ctx, invoker, "");
_peermgr = peermgr;
}
@Override // from ConfigRegistry
protected ObjectRecord createObjectRecord (String path, DObject object)
{
return new PeerDatabaseObjectRecord(path, object);
}
protected class PeerDatabaseObjectRecord extends DatabaseObjectRecord
implements PeerManager.StaleCacheObserver
{
public PeerDatabaseObjectRecord (String path, DObject object)
{
super(path, object);
_peermgr.addStaleCacheObserver(PEER_CACHE_PREFIX + _path, this);
}
// from interface PeerManager.StaleCacheObserver
public void changedCacheData (Streamable data)
{
@SuppressWarnings("unchecked") StreamableTuple<String,Object> change =
(StreamableTuple<String,Object>)data;
// note that we should ignore the attribute change event we're about to generate
// because it is not a real configuration change but rather a sync
try {
object.changeAttribute(change.left, change.right);
_pendingSyncs.add(change.left);
} catch (Exception e) {
log.log(Level.WARNING, "Config attribute sync failed " + change + ".", e);
}
}
@Override // from ObjectRecord
public void attributeChanged (AttributeChangedEvent event)
{
// if this was a pending sync event, don't pass it to our parent as it is not a real
// configuration change event
if (!_pendingSyncs.remove(event.getName())) {
super.attributeChanged(event);
}
}
@Override // from ObjectRecord
protected void updateValue (String name, Object value)
{
super.updateValue(name, value);
fieldUpdated(name, value);
}
@Override // from ObjectRecord
protected void serialize (String name, String key, Object value)
{
super.serialize(name, key, value);
fieldUpdated(name, value);
}
protected void fieldUpdated (String field, Object value)
{
// broadcast to the other nodes that this value has changed
_peermgr.broadcastStaleCacheData(
PEER_CACHE_PREFIX + _path, new StreamableTuple<String,Object>(field, value));
}
protected ArrayList<String> _pendingSyncs = new ArrayList<String>();
}
protected PeerManager _peermgr;
/** Prefixed to our cache invalidation notifications. */
protected static final String PEER_CACHE_PREFIX = "PeerConfigCache:";
}