+// recovery manager -- append transaction to recovery log
+// flush to disk when it overflows.
+
+logseqno bt_txnredo (BtDb *bt, BtPage source)
+{
+uint size = bt->mgr->page_size * bt->mgr->redopages - sizeof(BtLogHdr);
+uint amt = 0, src, type;
+BtLogHdr *hdr, *eof;
+logseqno lsn;
+uint flush;
+BtKey *key;
+BtVal *val;
+
+ // determine amount of redo recovery log space required
+
+ for( src = 0; src++ < source->cnt; ) {
+ key = keyptr(source,src);
+ val = valptr(source,src);
+ amt += key->len + val->len + sizeof(BtKey) + sizeof(BtVal);
+ amt += sizeof(BtLogHdr);
+ }
+
+ bt_mutexlock (bt->mgr->redo);
+
+ // see if new entry fits in buffer
+ // flush and reset if it doesn't
+
+ if( flush = amt > size - bt->mgr->redoend ) {
+ bt_mutexlock (bt->mgr->dump);
+
+ if( bt_dumpredo (bt) )
+ return 0;
+ }
+
+ // assign new lsn to transaction
+
+ lsn = ++bt->mgr->lsn;
+
+ // fill in new entries
+
+ for( src = 0; src++ < source->cnt; ) {
+ key = keyptr(source, src);
+ val = valptr(source, src);
+
+ switch( slotptr(source, src)->type ) {
+ case Unique:
+ type = BTRM_add;
+ break;
+ case Duplicate:
+ type = BTRM_dup;
+ break;
+ case Delete:
+ type = BTRM_del;
+ break;
+ case Update:
+ type = BTRM_upd;
+ break;
+ }
+
+ amt = key->len + val->len + sizeof(BtKey) + sizeof(BtVal);
+ amt += sizeof(BtLogHdr);
+
+ hdr = (BtLogHdr *)(bt->mgr->redobuff + bt->mgr->redoend);
+ hdr->len = amt;
+ hdr->type = type;
+ hdr->lsn = lsn;
+ hdr->lvl = 0;
+
+ // fill in key and value
+
+ memcpy ((unsigned char *)(hdr + 1), key, key->len + sizeof(BtKey));
+ memcpy ((unsigned char *)(hdr + 1) + key->len + sizeof(BtKey), val, val->len + sizeof(BtVal));
+
+ bt->mgr->redoend += amt;
+ }
+
+ eof = (BtLogHdr *)(bt->mgr->redobuff + bt->mgr->redoend);
+ memset (eof, 0, sizeof(BtLogHdr));
+
+ bt_releasemutex(bt->mgr->redo);
+
+ if( flush ) {
+ bt_flushlsn (bt);
+ bt_releasemutex(bt->mgr->dump);
+ }
+
+ return lsn;
+}
+