I've almost finished implementing type 2 SCD as mentioned here:
http://en.wikipedia.org/wiki/Slowly_changing_dimension
looks like it's about 200 lines of template code, less than I thought would be needed
essentially, I have two template classes: TimeTraveler< typename T > and TimeMachine< typename T>
TimeTraveler represents an entity which changes over time - it will hold all the instances of DB records which represents the same entity over contiguous time periods - I also have an internal template class that decorates the core object with tm_begin, tm_end, and tm_seqno (time machine attributes). TimeTraveler ensures that the instances have increasing tm_seqno and contiguous tm_begin, tm_end periods.
TimeMachine will hold all instances of TimeTraveler for easy lookup of entities with a key. Each TimeMachine has its own DateTime so you can pull up all instances for a given time.
An important feature of TimeTraveler is not allowing update, insert, and deletes to be directly called to the DB. In fact, you want to create new time-contiguous records every time you intend to do one of these operations. To implement this model, accessors are strictly const. However, there is one method where you can ask for a mutable instance (internally, we will make a copy of the newest record and return a handle to this instance back to the user for modification). Internally, we keep track of which instances are dirty and need writing back out to the DB (inserts since old records are immutable).
In one call to TimeMachine, we will scan for all dirty records and dump out a CSV file for easy loading via LOAD DATA INFILE.
To ensure data consistency in the face of multithreading, we must be careful with assigning tm_seqno. The algorithm here is, provide a function whose sole argument is the number of instances (new seqno) needed. The caller will scan TimeMachine for dirty records (essentially, new records since historical records are immutable), count them up, and pass this number in (call it n). The function must, then, lock the database, query for the top seqno allocated, add n to this number, update the top seqno in the database, and then unlock the database. This atomicity is needed so that a call from a different thread will not interfere with this block of operations.
This last block is just a note to myself - the last part which I will implement next