OOFILE 1.3b2d15 adds the ability to define a log file name and have most database actions logged. This is extremely useful when tracking down bugs with changes of state, particularly things like the database being unexpectedly in a different sort order.
Warning: the logs can grow very quickly. In particular a GUI application will generate a lot of entries as the rows are displayed in database browsers. Logs of several hundred kb are common.
Debug logging will also slow you down, but not as much as a memory debugger like SmartHeap or Spotlight.
Debug logging may help you identify unnecessary database operations, as well as outright bugs.
Add a
#define OOF_DEBUG_LOG_NAME "oof.debuglog"
as a global define for your project. It may be worth keeping a
separate build with logging, to avoid recompiling all files.
"oof.debuglog" is just a name chosen for this example. You can choose any name you like that's a legal file name. The test of logging being enabled is #ifdef OOF_DEBUG_LOG_NAME.
OOF_DEBUG_LOG is always defined and calls dbConnect::logComment which takes either a const char* or ostream& param.
Therefore you can embed calls like
OOF_DEBUG_LOG("Entering XXX about to save");
throughout your code and they will compile out if you don't
define OOF_DEBUG_LOG_NAME.
The log is opened and closed with each entry, to guarantee file writing. This is also useful if you want to get a small log for a given area of code, whilst running the debugger.
dbBrowseHelper::selectRecNo 0 on table 1124010 dbBrowseHelper::selectRecNo 0 on table 1124238 dbTable::cloneWithoutSelection() table: Q 111dcb0 (valid) Connection: 10fca80 RecState: eUnloaded Offset: 0 Clean Iter: 0 State: allRecs dbTable::setTableValid(true) table: Q 11c20d8 (valid) Connection: 10fca80 RecState: eUnloaded Offset: 0 Clean Iter: 0 State: empty dbTable::start() table: P 110a2e8 (valid) Connection: 10fca80 RecState: eUnloaded Offset: 0 Clean Iter: 0 State: allRecs dbTable::ContextChange() - requireExplicit table: P 110a2e8 (valid) Connection: 10fca80 RecState: eUnloaded Offset: 0 Clean Iter: 0 State: allRecs dbSorter::sortNow 10fdbb0 sorting: P (110a2e8) dbTable::cloneWithoutSelection() table: P 110a2e8 (valid) Connection: 10fca80 RecState: eUnloaded Offset: 0 Clean Iter: 0 State: allRecs dbTable::setTableValid(true) table: P 11c9348 (valid) Connection: 10fca80 RecState: eUnloaded Offset: 0 Clean Iter: 0 State: empty selectJustRecordPointer(313018)table: P 11c9348 (valid) Connection: 10fca80 RecState: eUnloaded Offset: 0 Clean Iter: 0 State: empty
If you use MicroQuill's SmartHeap product then defining OOF_SmartHeap will include smrtheap.hpp and perform pool validation at selected points to aid in detecting bugs such as memory overwrites. This runs a LOT slower but provides a high degree of assurance.
#define OOF_SmartHeap
#define MEM_DEBUG 1
#define DEFINE_NEW_MACRO 1
OOF_Debug is a #define flag, that will turn on debugging modes within OOFILE. These are in the nature of development-time checks and so you may not want them left in released applications! However, the errors they trigger will be handled by the standard error handler (dbConnect::raise), so you could theoretically cope with them yourself. Most of the OOF_Debug errors are programmer errors, and it should not be relied on as (say) a range-checking recovery mechanism.
If you write to an unallocated cell that is more than one past the previous high point (ie: not just an append) then OOF_DictRep::operator[](long) will report the error. This catches problems such as incorrect copying of objects (mainly our mistakes) or scrambling memory so that the index being used on the dictionary is a ridiculous value.
Conversion from a double to a long, or short and conversion from a long to a short are range-checked when the fields are assigned a value.
Attempting to add a record while read-locked will raise an error.
Attempts to set a read lock whilst write-locked and vice versa will raise an error, as will failing to match the number of ApplyLock calls to ReleaseLock's.