/*
PowerDNS Versatile Database Driven Nameserver
- Copyright (C) 2002 PowerDNS.COM BV
+ Copyright (C) 2002 - 2014 PowerDNS.COM BV
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2
#include <algorithm>
#include "arguments.hh"
#include "lock.hh"
+#include "iputils.hh"
#include <boost/foreach.hpp>
#include "namespaces.hh"
}
-StatRing::StatRing(unsigned int size)
+template<typename T, typename Comp>
+StatRing<T,Comp>::StatRing(unsigned int size)
{
- d_size=size;
- d_items.resize(d_size);
- d_lock=0;
- d_pos=0;
- d_lock=new pthread_mutex_t;
- pthread_mutex_init(d_lock, 0);
+ d_items.set_capacity(size);
+ pthread_mutex_init(&d_lock, 0);
}
-void StatRing::resize(unsigned int newsize)
+template<typename T, typename Comp>
+void StatRing<T,Comp>::account(const T& t)
{
- if(d_size==newsize)
- return;
- Lock l(d_lock);
-
- // this is the hard part, shrink
- if(newsize<d_size) {
- unsigned int startpos=0;
- if (d_pos>newsize)
- startpos=d_pos-newsize;
-
- vector<string>newring;
- for(unsigned int i=startpos;i<d_pos;++i) {
- newring.push_back(d_items[i%d_size]);
- }
-
- d_items=newring;
- d_size=newring.size();
- d_pos=min(d_pos,newsize);
- }
+ Lock l(&d_lock);
+ d_items.push_back(t);
+}
- if(newsize>d_size) {
- d_size=newsize;
- d_items.resize(d_size);
- }
+template<typename T, typename Comp>
+unsigned int StatRing<T,Comp>::getSize()
+{
+ Lock l(&d_lock);
+ return d_items.capacity();
}
-StatRing::~StatRing()
+template<typename T, typename Comp>
+void StatRing<T,Comp>::resize(unsigned int newsize)
{
- // do not clean up d_lock, it is shared
+ Lock l(&d_lock);
+ d_items.set_capacity(newsize);
}
-void StatRing::setHelp(const string &str)
+
+template<typename T, typename Comp>
+void StatRing<T,Comp>::setHelp(const string &str)
{
d_help=str;
}
-string StatRing::getHelp()
+template<typename T, typename Comp>
+string StatRing<T,Comp>::getHelp()
{
return d_help;
}
-static bool popisort(const pair<string,int> &a, const pair<string,int> &b)
-{
- return (a.second > b.second);
-}
-vector<pair<string,unsigned int> >StatRing::get() const
+template<typename T, typename Comp>
+vector<pair<T, unsigned int> >StatRing<T,Comp>::get() const
{
- Lock l(d_lock);
- map<string,unsigned int> res;
- for(vector<string>::const_iterator i=d_items.begin();i!=d_items.end();++i) {
- if(!i->empty())
- res[*i]++;
+ Lock l(&d_lock);
+ map<T,unsigned int, Comp> res;
+ for(typename boost::circular_buffer<T>::const_iterator i=d_items.begin();i!=d_items.end();++i) {
+ res[*i]++;
}
- vector<pair<string,unsigned int> > tmp;
- for(map<string,unsigned int>::const_iterator i=res.begin();i!=res.end();++i)
+ vector<pair<T ,unsigned int> > tmp;
+ for(typename map<T, unsigned int>::const_iterator i=res.begin();i!=res.end();++i)
tmp.push_back(*i);
sort(tmp.begin(),tmp.end(),popisort);
void StatBag::declareRing(const string &name, const string &help, unsigned int size)
{
- d_rings[name]=StatRing(size);
+ d_rings[name]=StatRing<string>(size);
d_rings[name].setHelp(help);
}
-vector<pair<string, unsigned int> > StatBag::getRing(const string &name)
+void StatBag::declareComboRing(const string &name, const string &help, unsigned int size)
{
- return d_rings[name].get();
+ d_comborings[name]=StatRing<ComboAddress, ComboAddress::addressOnlyLessThan >(size);
+ d_comborings[name].setHelp(help);
}
-void StatRing::reset()
+
+vector<pair<string, unsigned int> > StatBag::getRing(const string &name)
{
- Lock l(d_lock);
- for(vector<string>::iterator i=d_items.begin();i!=d_items.end();++i) {
- if(!i->empty())
- *i="";
+ if(d_rings.count(name))
+ return d_rings[name].get();
+ else {
+ typedef pair<ComboAddress, unsigned int> stor_t;
+ vector<stor_t> raw =d_comborings[name].get();
+ vector<pair<string, unsigned int> > ret;
+ BOOST_FOREACH(const stor_t& stor, raw) {
+ ret.push_back(make_pair(stor.first.toString(), stor.second));
+ }
+ return ret;
}
+
+}
+
+template<typename T, typename Comp>
+void StatRing<T,Comp>::reset()
+{
+ Lock l(&d_lock);
+ d_items.clear();
}
void StatBag::resetRing(const string &name)
{
- d_rings[name].reset();
+ if(d_rings.count(name))
+ d_rings[name].reset();
+ else
+ d_comborings[name].reset();
}
void StatBag::resizeRing(const string &name, unsigned int newsize)
{
- d_rings[name].resize(newsize);
+ if(d_rings.count(name))
+ d_rings[name].resize(newsize);
+ else
+ d_comborings[name].resize(newsize);
}
unsigned int StatBag::getRingSize(const string &name)
{
- return d_rings[name].getSize();
+ if(d_rings.count(name))
+ return d_rings[name].getSize();
+ else
+ return d_comborings[name].getSize();
}
-
string StatBag::getRingTitle(const string &name)
{
- return d_rings[name].getHelp();
+ if(d_rings.count(name))
+ return d_rings[name].getHelp();
+ else
+ return d_comborings[name].getHelp();
}
vector<string>StatBag::listRings()
{
vector<string> ret;
- for(map<string,StatRing>::const_iterator i=d_rings.begin();i!=d_rings.end();++i)
+ for(map<string,StatRing<string> >::const_iterator i=d_rings.begin();i!=d_rings.end();++i)
+ ret.push_back(i->first);
+ for(map<string,StatRing<ComboAddress, ComboAddress::addressOnlyLessThan> >::const_iterator i=d_comborings.begin();i!=d_comborings.end();++i)
ret.push_back(i->first);
+
return ret;
}
bool StatBag::ringExists(const string &name)
{
- return d_rings.count(name);
+ return d_rings.count(name) || d_comborings.count(name);
}
+
+template class StatRing<std::string>;
+template class StatRing<ComboAddress, ComboAddress::addressOnlyLessThan >;
#define STATBAG_HH
#include <pthread.h>
#include <map>
+#include <functional>
#include <string>
#include <vector>
#include "lock.hh"
#include "namespaces.hh"
+#include "iputils.hh"
+#include <boost/circular_buffer.hpp>
+template<typename T, typename Comp=std::less<T> >
class StatRing
{
public:
StatRing(unsigned int size=10000);
- ~StatRing();
- void account(const string &item)
- {
- Lock l(d_lock);
- d_items[d_pos++ % d_size]=item;
- }
+ void account(const T &item);
- unsigned int getSize()
- {
- return d_size;
- }
+ unsigned int getSize();
void resize(unsigned int newsize);
void reset();
void setHelp(const string &str);
string getHelp();
- vector<pair<string,unsigned int> >get() const;
+
+ vector<pair<T, unsigned int> > get() const;
private:
- unsigned int d_size;
- unsigned int d_pos;
- vector<string> d_items;
- pthread_mutex_t *d_lock;
+ static bool popisort(const pair<T,int> &a, const pair<T,int> &b)
+ {
+ return (a.second > b.second);
+ }
+
+ boost::circular_buffer<T> d_items;
+ mutable pthread_mutex_t d_lock;
string d_help;
};
{
map<string, AtomicCounter *> d_stats;
map<string, string> d_keyDescrips;
- map<string,StatRing>d_rings;
+ map<string,StatRing<string> >d_rings;
+ map<string,StatRing<ComboAddress, ComboAddress::addressOnlyLessThan> >d_comborings;
typedef boost::function<uint64_t(const std::string&)> func_t;
typedef map<string, func_t> funcstats_t;
funcstats_t d_funcstats;
void declare(const string &key, const string &descrip, func_t func); //!< Before you can store or access a key, you need to declare it
void declareRing(const string &name, const string &title, unsigned int size=10000);
+ void declareComboRing(const string &name, const string &help, unsigned int size=10000);
vector<pair<string, unsigned int> >getRing(const string &name);
string getRingTitle(const string &name);
- void ringAccount(const string &name, const string &item)
+ void ringAccount(const char* name, const string &item)
{
- if(d_doRings)
+ if(d_doRings) {
+ if(!d_rings.count(name))
+ throw runtime_error("Attempting to account to non-existent ring");
+
d_rings[name].account(item);
+ }
}
+ void ringAccount(const char* name, const ComboAddress &item)
+ {
+ if(d_doRings) {
+ if(!d_comborings.count(name))
+ throw runtime_error("Attempting to account to non-existent comboring");
+ d_comborings[name].account(item);
+ }
+ }
+
void doRings()
{
d_doRings=true;