#define USE_FTR
#include <PalmOS.h>
#include <VFSMgr.h>
#include <68k/system/PmPalmOSNVFS.h>
#ifndef STANDALONE
#include "Backup.h"
#endif
#ifndef memHeapFlagReadOnly
# define memHeapFlagReadOnly 0x0001
#endif
// To use DBCacheFlush() code in another application modify these defines:
#define CREATOR appCreator
#define FIRST_FTR_ID 1
void DBCacheFlush( Boolean fast );
#ifdef DA
void DA_Main( void )
{
DBCacheFlush( true );
}
#endif
static void SetRecyclable( UInt16 card, LocalID id )
{
UInt16 attr;
if ( id == NULL )
return;
if ( errNone == DmDatabaseInfo( card, id, NULL, &attr, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ) {
attr = attr | dmHdrAttrRecyclable;
DmSetDatabaseInfo( card, id, NULL, &attr, NULL,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL );
}
}
static Boolean HaveNVFS( void )
{
Err err;
UInt32 value;
err = FtrGet( sysFtrCreator, sysFtrNumDmAutoBackup, &value );
return ( err == errNone && value != 0 );
}
static void Progress( Boolean show )
{
#if 0
Coord w;
Coord h;
if ( ! show )
return;
WinGetDisplayExtent( &w, &h );
WinDrawPixel( SysRandom(0)%w, SysRandom(0)%h );
#endif
}
// Flushing via feature memory (Does not work well for lower NVFS version [bellow TX])
// Better in defragmentation
static void FtrFlush( UInt16 storageHeapId, Boolean savedScreen )
{
#define BLOCK_SIZE 65536 // 32768
Int32 needed ;
UInt16 fNum ;
Int32 i ;
void *f ;
UInt32 size ;
UInt32 dbCacheTotal = MemHeapSize( storageHeapId|dbCacheFlag );
// First algorithm
fNum = FIRST_FTR_ID;
for( i=70 ; 10 <= i ; i-=10 )
{
Progress( savedScreen );
size = dbCacheTotal*i/100 ;
if( FtrPtrNew( CREATOR, fNum, size, &f) == 0 )
fNum++ ;
}
needed = dbCacheTotal / BLOCK_SIZE;
for( i=0 ; i < needed ; i++ )
{
Progress( savedScreen );
if( FtrPtrNew( CREATOR, fNum, BLOCK_SIZE, &f) != 0 )
break ;
fNum++ ;
}
for( i=FIRST_FTR_ID ; i < fNum ; i++ )
FtrPtrFree( CREATOR, i );
// Second algorithm
for( fNum=FIRST_FTR_ID ; ; fNum++ )
{
UInt32 free ;
Progress( savedScreen );
MemHeapFreeBytes( storageHeapId|dbCacheFlag, &free, &size );
if( size < 500 )
break ;
if( FtrPtrNew( CREATOR, fNum, size, &f) != 0 )
break ;
do {
Progress( savedScreen );
size += BLOCK_SIZE ;
}
while( MemPtrResize(f, size) == 0 ) ;
}
for( i=FIRST_FTR_ID ; i < fNum ; i++ )
FtrPtrFree( CREATOR, i );
}
void GetFlushName( Char* s )
{
*s++ = 'F';
*s++ = 'l';
*s++ = 'u';
*s++ = 's';
*s++ = '-';
*s++ = 't';
*s++ = 'm';
*s++ = 'p';
*s++ = '.';
*s++ = 'f';
*s++ = 'l';
*s++ = 'u';
*s++ = 's';
*s++ = 'h';
*s = 0;
}
// Flushing via DB writes.
// Procedure suitable for all NVFS versions
static void DBFlush( UInt16 storageHeapId, Boolean savedScreen )
{
#define BLK_SIZE 30000
UInt32 dbCacheTotal ;
DmOpenRef ref = NULL ;
// Get available DB space.
// Must be both bellow the DbCache capacity and bellow the free storage space.
{
#define MIN_FREE_STORAGE 100000L
UInt32 free, maxBytes;
MemHeapFreeBytes( storageHeapId, &free, &maxBytes ) ;
if( free < MIN_FREE_STORAGE )
return ;
dbCacheTotal = MemHeapSize( storageHeapId|dbCacheFlag );
if( dbCacheTotal > free )
dbCacheTotal = free ;
dbCacheTotal -= MIN_FREE_STORAGE ;
}
// Open tmp recyclable database
{
char flushName[ dmDBNameLength ];
LocalID dbId;
GetFlushName( flushName );
dbId = DmFindDatabase( 0, flushName );
if( dbId != NULL )
DmDeleteDatabase( 0, dbId );
DmCreateDatabase( 0, flushName, CREATOR, 'temp', false );
dbId = DmFindDatabase( 0, flushName );
if( dbId != NULL )
{
//SetRecyclable
SetRecyclable( 0, dbId );
ref = DmOpenDatabase( 0, dbId, dmModeReadWrite ) ;
if( ref == NULL )
DmDeleteDatabase( 0, dbId );
}
}
if( ref != NULL )
{
// Fill DB records
Int32 nNeededRecs = dbCacheTotal / BLK_SIZE ;
while( nNeededRecs-- > 0 )
{
UInt16 location = dmMaxRecordIndex;
Progress( savedScreen );
if( DmNewRecord( ref, &location, BLK_SIZE) == NULL )
break;
}
// Cleanup
{
// This would save quite a few seconds (prevents unneeded commit to NVFS),
// but does not work on T650.
// UInt16 n_recs = DmNumRecords( ref ) ;
// while( n_recs-- != 0 )
// DmDeleteRecord( ref, n_recs ) ;
DmCloseDatabase( ref ) ; // This deletes the DB
}
}
}
UInt32 CacheSize( UInt32* freeP, UInt32* chunkP )
{
UInt16 numHeaps = MemNumHeaps(0);
UInt16 i;
for( i=0 ; i < numHeaps; i++ )
{
UInt16 heapId = MemHeapID(0, i);
if( !MemHeapDynamic(heapId) )
{
UInt16 heapFlags = MemHeapFlags( heapId ) ;
if( (heapFlags & 0x1) == 0 ) // memHeapFlagReadOnly==0x01
{
UInt32 free;
UInt32 chunk;
MemHeapFreeBytes( heapId|dbCacheFlag, &free, &chunk );
if ( freeP != NULL )
*freeP = free;
if ( chunkP != NULL )
*chunkP = chunk;
return MemHeapSize( heapId|dbCacheFlag );
}
}
}
return 0;
}
void GetMessage( Char* m )
{
*m++ = 'F';
*m++ = 'l';
*m++ = 'u';
*m++ = 's';
*m++ = 'h';
*m++ = 'i';
*m++ = 'n';
*m++ = 'g';
*m++ = '.';
*m++ = '.';
*m++ = '.';
*m = 0;
}
void DBCacheFlush( Boolean fast )
{
// Attention!!!
//
// No system processing is allowed during DbCache flush. (That's way user abort is not implemented.)
// Otherwise the OS may negatively influence the results. (Proved on T650.)
UInt16 numHeaps = MemNumHeaps(0);
UInt16 i;
WinHandle oldWinH;
void* bits;
RectangleType r;
Err err;
Boolean savedScreen;
if ( ! HaveNVFS() )
return;
oldWinH = WinSetDrawWindow( WinGetDisplayWindow() );
WinGetDrawWindowBounds( &r );
bits = WinSaveBits( &r, &err );
if ( err != errNone ) {
savedScreen = false;
}
else {
RectangleType rect;
Char message[ 60 ];
Coord messageSize;
savedScreen = true;
GetMessage( message );
messageSize = FntCharsWidth( message, StrLen( message ) );
rect.topLeft.x = 80 - messageSize / 2 - 14;
rect.extent.x = messageSize + 28;
rect.topLeft.y = 70-4;
rect.extent.y = 28;
WinEraseRectangle( &rect, 0 );
WinDrawRectangleFrame( dialogFrame, &rect );
WinDrawChars( message, StrLen( message ), 80 - messageSize / 2, 80 - 5 );
}
// Get storage heap characteristics
for( i=0 ; i < numHeaps; i++ )
{
UInt16 heapId = MemHeapID(0, i);
if( !MemHeapDynamic(heapId) )
{
UInt16 heapFlags = MemHeapFlags( heapId ) ;
if( (heapFlags & 0x1) == 0 ) // memHeapFlagReadOnly==0x01
{
DmSync() ;
if ( ! fast )
DBFlush( heapId, savedScreen ) ;
FtrFlush( heapId, savedScreen ) ;
DmSync() ;
break ;
}
}
}
if ( savedScreen ) {
WinRestoreBits( bits, 0, 0 );
MemPtrFree( bits );
}
WinSetDrawWindow( oldWinH );
}