System like Googles search engine are 100% online, they use the idea of machines sets and stages where they roll out new versions the code, boot up the system and then enable/disable parts of the system as they trial the new algorithms.
So how can this be done? Well there are many approaches but the probably break down to 2 main categories.
- Enablement Switches
- Runtime replaceable code parts.
- Advantage:
- micro level Control
- micro level Control
- Disadvantage:
- Generally this requires the constant check of a bool in hash or shared mem.
- Code is statical linked so if its wrong you will need to replace the whole processes code
- Generally this requires the constant check of a bool in hash or shared mem.
- Advantage:
- Dynamically able to add/replace libs at runtime when things go wrong or a clear tweak is visable
- Dynamically able to add/replace libs at runtime when things go wrong or a clear tweak is visable
- Disadvantage:
- It is Marco level. Ie requires more larger chunks of code to be loaded/unload
- cant handle extensive interface changes over the plugin interface.
- It is Marco level. Ie requires more larger chunks of code to be loaded/unload
// compile with:
// g++ -I"c:\tools\boost_1_45_0" -L"c:\tools\boost_1_45_0\stage\lib" -static enable_control_flag.cpp -o enable_control_flag.exe
//#include <boost/interprocess/shared_memory_object.hpp>
#include <boost/interprocess/windows_shared_memory.hpp>
#include <boost/interprocess/mapped_region.hpp>
//#include <boost/thread/thread.hpp>
#include <boost/functional/hash.hpp>
#include <iostream>
#include <iomanip>
#include <string>
// for windows Sleep!
#include <Windows.h>
#define KEY_MAX 64
struct EnableControlSwitch
{
//realy this is just for a chuck of shared memory
EnableControlSwitch() :
state_(false),
hash_(0)
{}
uint32_t hash_;
bool state_;
char key_[KEY_MAX];
//expiry date...
//creator process... so u can trak where its coming from.
};
using namespace boost::interprocess;
class EnableControl
{
public:
enum {
MAX_ENTRIES = 256, //best to keep this as a power of 2 for speed
MEM_SIZE = (MAX_ENTRIES*sizeof(EnableControlSwitch))
};
static EnableControl& instance()
{
static EnableControl me;
return me;
}
EnableControlSwitch& create(const std::string& key) { return get(key, true); }
EnableControlSwitch& get(const std::string& key,
bool create = false)
{
//locate or register
if(key.length() > KEY_MAX-1) throw std::runtime_error("Key to big");
uint32_t hash = boost::hash_value(key);
uint32_t loc = hash;
while (hash != 0)
{
uint32_t idx = loc % MAX_ENTRIES;
if(switches_[idx].hash_ == 0)
{
if (!create)
throw std::runtime_error("Unknown Key");
//free location!
//lockless version... assume atomic...
switches_[idx].hash_ = hash;
if(switches_[idx].hash_ == hash)
{
//proceed
std::memcpy(switches_[idx].key_,
key.c_str(),
key.length());
switches_[idx].key_[key.length()] = '\0';
return switches_[idx];
}
}
else if(switches_[idx].hash_ == hash)
{
return switches_[idx];
}
else
{
//nothing went wrong and it was occupied.. next possible place
loc = loc / MAX_ENTRIES;
}
}
throw std::runtime_error("To many key conflicts");
}
bool& state(const std::string& key)
{
EnableControlSwitch& aSwitch = get(key);
return aSwitch.state_;
}
void enable(const std::string key) { state(key) = true; }
void disable(const std::string key) { state(key) = false; }
std::ostream& printAll(std::ostream& out) const
{
for(uint32_t idx = 0; idx < MAX_ENTRIES; idx++)
{
if(switches_[idx].hash_ != 0)
out << std::hex
<< "Idx:" << idx
<< " Hash:" << switches_[idx].hash_
<< " Key:" << switches_[idx].key_
<< " State:" << switches_[idx].state_
<< "\n";
}
return out;
}
private:
EnableControl() :
shm_(NULL),
region_(NULL)
{
//setup shared mem
shm_ = new windows_shared_memory(open_or_create, "SharedEnableControls", read_write, MEM_SIZE);
region_ = new mapped_region(*shm_, read_write);
std::memset(region_->get_address(), 0, region_->get_size());
switches_ = static_cast<EnableControlSwitch*>(region_->get_address());
}
~EnableControl()
{
delete region_;
delete shm_;
}
windows_shared_memory* shm_;
mapped_region* region_;
EnableControlSwitch* switches_;
};
std::ostream& operator<<(std::ostream& out, EnableControl const& control)
{
return control.printAll (out);
}
void master()
{
//should use an allocator... but lets keep it simple for now...
EnableControl& ctrl = EnableControl::instance();
const EnableControlSwitch& a = ctrl.create("a"); //high speed Enable point (share mem ref copy)
const EnableControlSwitch& b = ctrl.create("b");
const EnableControlSwitch& c = ctrl.create("c");
const EnableControlSwitch& exit = ctrl.create("exit");
while (!exit.state_)
{
try
{
std::cout << EnableControl::instance();
std::cout << "sleeping..\n";
//boost::this_thread::sleep(boost::posix_time::seconds(1));
Sleep(1000);
if(a.state_)
std::cout << "a\n";
if(b.state_)
std::cout << "b\n";
if(c.state_)
std::cout << "c\n";
}
catch(std::exception& e)
{
std::cout << e.what();
}
}
}
void slave(std::string cmd, std::string key)
{
try
{
if(cmd == "status")
std::cout << EnableControl::instance();
else if(cmd == "enable")
EnableControl::instance().enable(key);
else if(cmd == "disable")
EnableControl::instance().disable(key);
else if(cmd == "info")
std::cout << "Key:" << key << " is " << (EnableControl::instance().state(key) ? "ON" : "OFF") << "\n";
else
std::cout << "Unknown Command:" << cmd << " Key:" << key << "\n";
}
catch(std::exception& e)
{
std::cout << "Error: " << e.what() << "\n";
}
}
int main(int argc, char const * const *argv)
{
//this is a 2 process system
// master is run with no parameters
// slave is one of the aboved listed commands + the option key.
if (argc == 1)
master();
else if (argc == 2)
slave(argv[1],"");
else
slave(argv[1],argv[2]);
}
Some improvements the come to mind are: - At compile time, compute the the string hash using boost::mpl::strings, to squeeze some extra mill secs in at the start up. but that is serious over kill IMHO. Better to improve the hash collision algorithm.
- Add the ability to delete hash entries.
- Add the ability to add pages for switches so that the compile time switch limit can be exceeded.
- A way to cleanly initialization the switch system.