summaryrefslogtreecommitdiff
path: root/cpp/src/Ice/EvictorBase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/Ice/EvictorBase.cpp')
-rw-r--r--cpp/src/Ice/EvictorBase.cpp280
1 files changed, 280 insertions, 0 deletions
diff --git a/cpp/src/Ice/EvictorBase.cpp b/cpp/src/Ice/EvictorBase.cpp
new file mode 100644
index 00000000000..9afcf60df95
--- /dev/null
+++ b/cpp/src/Ice/EvictorBase.cpp
@@ -0,0 +1,280 @@
+// **********************************************************************
+//
+// Copyright (c) 2003
+// ZeroC, Inc.
+// Billerica, MA, USA
+//
+// All Rights Reserved.
+//
+// Ice is free software; you can redistribute it and/or modify it under
+// the terms of the GNU General Public License version 2 as published by
+// the Free Software Foundation.
+//
+// **********************************************************************
+
+#include <Ice/EvictorBase.h>
+#include <Ice/LocalException.h>
+#include <Ice/Properties.h>
+#include <Ice/Communicator.h>
+#include <Ice/ObjectAdapter.h>
+#include <Ice/LoggerUtil.h>
+#include <iomanip>
+
+using namespace std;
+using namespace Ice;
+
+Ice::EvictorBase::EvictorBase()
+ : _size(0),
+ _initialized(false),
+ _hits(0),
+ _misses(0),
+ _evictions(0),
+ _traceLevel(0),
+ _communicator(0)
+{
+}
+
+void
+Ice::EvictorBase::setSize(Int size)
+{
+ if(size < 1)
+ {
+ return; // Ignore stupid values.
+ }
+
+ IceUtil::Mutex::Lock lock(_mutex);
+ _size = size;
+ evictServants();
+}
+
+Int
+Ice::EvictorBase::getSize() const
+{
+ IceUtil::Mutex::Lock lock(_mutex);
+ return _size;
+}
+
+ObjectPtr
+Ice::EvictorBase::locate(const Current& c, LocalObjectPtr& cookie)
+{
+ IceUtil::Mutex::Lock lock(_mutex);
+
+ if(!_initialized) // Lazy initialization of evictor size and tracing.
+ {
+ _initialized = true;
+ initialize(c);
+ }
+
+ //
+ // Check if we have an entry for the servant already.
+ //
+ EvictorCookiePtr ec = new EvictorCookie;
+ cookie = ec;
+ EvictorMap::iterator i = _map.find(c.id);
+ if(i != _map.end())
+ {
+ //
+ // Got an entry already, dequeue the entry from its current position.
+ //
+ ec->entry = i->second;
+ _queue.erase(ec->entry->pos);
+
+ ++_hits; // Update statistics.
+ if(_traceLevel >= 3)
+ {
+ Trace out(_communicator->getLogger(), "Ice::Evictor");
+ if(c.id.category.empty())
+ {
+ out << "default category";
+ }
+ else
+ {
+ out << "category`" << c.id.category << "'";
+ }
+ out << ": cache hit for name `" << c.id.name << "'";
+ out.flush();
+ }
+ }
+ else
+ {
+ //
+ // Don't have an entry yet. Ask the application to instantiate a servant
+ // and create a new entry in the map.
+ //
+ ec->entry = new EvictorEntry;
+ ec->entry->servant = instantiate(c, ec->entry->userCookie); // Down-call to application-supplied method.
+ if(!ec->entry->servant)
+ {
+ throw ObjectNotExistException(__FILE__, __LINE__);
+ }
+ ec->entry->useCount = 0;
+ _map[c.id] = ec->entry;
+
+ ++_misses; // Update statistics.
+ if(_traceLevel >= 2)
+ {
+ Trace out(_communicator->getLogger(), "Ice::Evictor");
+ if(c.id.category.empty())
+ {
+ out << "default category";
+ }
+ else
+ {
+ out << "category`" << c.id.category << "'";
+ }
+ out << ": cache miss for name `" << c.id.name << "'";
+ out.flush();
+ }
+ }
+
+ //
+ // Increment the use count of the servant and enqueue the entry at the front,
+ // so we get LRU order.
+ //
+ ++(ec->entry->useCount);
+ _queue.push_front(c.id);
+ ec->entry->pos = _queue.begin();
+
+ //
+ // If we added an entry, that might make another entry eligible for eviction.
+ //
+ if(i == _map.end())
+ {
+ evictServants();
+ }
+
+ return ec->entry->servant;
+}
+
+void
+Ice::EvictorBase::finished(const Current&, const ObjectPtr&, const LocalObjectPtr& cookie)
+{
+ IceUtil::Mutex::Lock lock(_mutex);
+
+ EvictorCookiePtr ec = EvictorCookiePtr::dynamicCast(cookie);
+
+ //
+ // Decrement use count and check if there is something to evict.
+ //
+ --(ec->entry->useCount);
+ evictServants();
+}
+
+void
+Ice::EvictorBase::deactivate(const string& category)
+{
+ IceUtil::Mutex::Lock lock(_mutex);
+
+ if(_traceLevel >= 1)
+ {
+ Trace out(_communicator->getLogger(), "Ice::Evictor");
+ out << "deactivating ";
+ if(category.empty())
+ {
+ out << "default category";
+ }
+ else
+ {
+ out << "category `" << category << "'";
+ }
+ out << ", number of cached servants = " << _map.size();
+ out.flush();
+
+ out << "#evictions = " << _evictions;
+ out << ", #hits = " << _hits;
+ out << ", #misses = " << _misses;
+ double total = (double)_hits + (double)_misses;
+ double ratio = total == 0 ? 100 : ((double)_hits * 100 / total);
+ out << ", %hits = " << fixed << setprecision(2) << ratio << "%";
+ out.flush();
+ }
+
+ _size = 0;
+ evictServants();
+}
+
+void
+Ice::EvictorBase::evictServants()
+{
+ //
+ // If the evictor queue has grown larger than the limit,
+ // look at the excess elements to see whether any of them
+ // can be evicted.
+ //
+ for(int i = _map.size() - _size; i > 0; --i)
+ {
+ EvictorQueue::reverse_iterator p = _queue.rbegin();
+ assert(p != _queue.rend());
+ EvictorMap::iterator mPos = _map.find(*p);
+ assert(mPos != _map.end());
+ if(mPos->second->useCount == 0)
+ {
+ if(_traceLevel >= 2)
+ {
+ Trace out(_communicator->getLogger(), "Ice::Evictor");
+ if((*p).category.empty())
+ {
+ out << "default category";
+ }
+ else
+ {
+ out << "category `" << (*p).category << "'";
+ }
+ out << ": evicting `" << (*p).name << "'";
+ out.flush();
+ }
+
+ evict(*p, mPos->second->servant, mPos->second->userCookie); // Down-call to application-supplied method.
+ _queue.erase(mPos->second->pos);
+ _map.erase(mPos);
+ ++_evictions; // Update statistics.
+ }
+ }
+}
+
+void
+Ice::EvictorBase::initialize(const Current& c)
+{
+ _communicator = c.adapter->getCommunicator();
+
+ PropertiesPtr p = _communicator->getProperties();
+ int num;
+
+ //
+ // Check evictor size properties.
+ //
+ if((num = p->getPropertyAsInt("Ice.Evictor.Size")) > 0)
+ {
+ _size = num;
+ }
+ if((num = p->getPropertyAsInt(c.adapter->getName() + ".Evictor.Size")) > 0)
+ {
+ _size = num;
+ }
+ if(!c.id.category.empty()
+ && (num = p->getPropertyAsInt(c.adapter->getName() + "." + c.id.category + ".Evictor.Size")) > 0)
+ {
+ _size = num;
+ }
+ if(_size < 1)
+ {
+ _size = defaultSize;
+ }
+
+ //
+ // Check evictor trace properties.
+ //
+ if(!p->getProperty("Ice.Evictor.Trace").empty())
+ {
+ _traceLevel = p->getPropertyAsInt("Ice.Evictor.Trace");
+ }
+ if(!p->getProperty(c.adapter->getName() + ".Evictor.Trace").empty())
+ {
+ _traceLevel = p->getPropertyAsInt(c.adapter->getName() + ".Evictor.Trace");
+ }
+ if(!c.id.category.empty()
+ && !p->getProperty(c.adapter->getName() + "." + c.id.category + ".Evictor.Trace").empty())
+ {
+ _traceLevel = p->getPropertyAsInt(c.adapter->getName() + "." + c.id.category + ".Evictor.Trace");
+ }
+}