//-< OODBS.CPP >-----------------------------------------------------*--------* // GOODS Version 1.0 (c) 1992 GARRET * ? * // ( Garret object oriented data storage ) * /\| * // Virtual objects level * / \ * // Created: 14-Feb-92 K.A. Knizhnik * / [] \ * // Last update: 16-May-94 K.A. Knizhnik * GARRET * //-------------------------------------------------------------------*--------* #include #include "oodbs.hpp" #define ODB_CACHE_SIZE 256 // maximal number of cache elements #define ODB_CACHE_LIMIT ULONG_MAX // maximal total size of cache elements global Object_Database* Object_Database::Default; local Dbs_Object Barrier; local Dbs_Object Nil; #ifdef __ZTC__ export Dbs_Object* Odb_Nil_Ptr; global Dbs_Object* Odb_Nil_Ptr = &Nil; #else export Dbs_Object* const Odb_Nil_Ptr; global Dbs_Object* const Odb_Nil_Ptr = &Nil; #endif // // Cache element methods // void Dbs_Object::Alloc ( o_size_t New_Size ) { if ( Size > 0 ) delete[] (Buffer - sizeof(Dbs_Object*)); char* Buf = new char[ sizeof(Dbs_Object*) + New_Size ]; if( Buf == NULL ) Fatal( "No memory\n" ); *(Dbs_Object**)Buf = this; Buffer = Buf + sizeof(Dbs_Object*); Size = New_Size; } void Dbs_Object::Remove() { ASSERT( Fixed == 0 ); Save(); Size = 0; Unlink(); Hash_Remove( this ); delete[] (Buffer - sizeof(Dbs_Object*)); } // // Storage intreface functions // void Object_Database::Open( void ) { for ( int i = 0; i < Stores_Number; i++ ) Store[i]->Open( i, this ); } void Object_Database::Close ( void ) { Clear(); for ( int i = Stores_Number; -- i >= 0; Store[i]->Close() ); } // // Object cache methods // Object_Cache::Object_Cache( int Number, Dbs_Store** Files, V_Table* Table ) : File_Manager ( Number , Files ) { Total = 0; Header.Prune(); Header.Fixed = 0; Init_Table = Table; Cache = new Dbs_Object[ ODB_CACHE_SIZE ]; Dbs_Object* Obj = Cache; for( int i = ODB_CACHE_SIZE; -- i >= 0; Obj ++ ) Obj->Size = 0, Obj->Next = Obj + 1; (Obj-1)->Next = NULL; Free_Chain = Cache; Hash_Set( Hash_Table, &Barrier, items(Hash_Table) ); } void Object_Cache::Flush() { Dbs_Object* Obj = &Header; while( (Obj = (Dbs_Object*)Obj->Next) != &Header ) Obj->Save(); for( int i = Stores_Number; -- i >= 0; Store[i]->Flush() ); } void Object_Cache::Clear ( void ) { Dbs_Object* Obj = &Header; while( (Obj = (Dbs_Object*)Obj->Prev) != &Header ) Remove( Obj ); } Physical Object_Cache::Find ( large Address, tiny Mode ) { Dbs_Object *Obj, **Chain = &Hash_Table[ tiny(Hash_Coding(Address)) ]; ASSERT ( long(Address) < 0 ); while ( (Obj = *Chain)->Address > Address ) Chain = Hash_Next(Obj); if ( Obj->Address == Address ) { Obj->Unlink (); Obj->Link ( &Header ); Obj->State |= Mode; return Obj->Buffer; } if ( Free_Chain == NULL ) { for( Obj = (Dbs_Object*)Header.Prev; Obj->Fixed; Obj = (Dbs_Object*)Obj->Prev ); ASSERT( Obj != &Header); Obj->Save(); Obj->Unlink(); if ( Chain == Hash_Next(Obj) ) goto Link; Hash_Remove ( Obj ); } else { Obj = Free_Chain; Free_Chain = (Dbs_Object*) Free_Chain->Next; } Hash_Insert ( Chain, Obj ); Link: Obj->Address = Address; Obj->State = Mode; Obj->Fixed = 0; Store[ Odb_File(Address) ]->Read( Obj ); Obj->Link( &Header ); File_Object* Ptr = (File_Object*) Obj->Buffer; #ifdef TYPE_INFO if( Ptr->Dbs_Ident >= 0 ) Init_Table[ Ptr->Dbs_Ident ] ( Ptr ); #endif return Ptr; } void Object_Cache::Remove( Dbs_Object* Obj ) { Total -= Obj->Size; Obj->Remove(); Obj->Next = Free_Chain, Free_Chain = Obj; } void Object_Cache::Realloc( Dbs_Object* Obj, o_size_t Size ) { Size = (Size + Dbs_Slot_Size - 1) & ~(Dbs_Slot_Size - 1); if( (Total += Size - Obj->Size) > ODB_CACHE_LIMIT ) { Dbs_Object *Lru = &Header, *Mru = (Dbs_Object*)Header.Next; while( (Lru = (Dbs_Object*)Lru->Prev) != Mru && Total > ODB_CACHE_LIMIT ) if( !Lru->Fixed ) Remove( Lru ); } Obj->Alloc( Size ); } void Object_Cache::Compaction() { Dbs_Object *Lru = &Header, *Mru = (Dbs_Object*)Header.Next; while( (Lru = (Dbs_Object*)Lru->Prev) != Mru ) if( !Lru->Fixed ) Remove( Lru ); } // // Object virtual allocation mechanism // void Object_Cache::Near ( Virtual Address ) { ASSERT ( (long)Address < 0 ); Store[Odb_File(Address)]->Near( Odb_Offset( Address ) ); } Physical Object_Cache::Malloc ( Dbs_Store* File, o_size_t Size ) { Dbs_Object *Obj, *Node, **Chain; if ( Free_Chain == NULL ) { for( Obj = (Dbs_Object*)Header.Prev; Obj->Fixed; Obj = (Dbs_Object*)Obj->Prev ); ASSERT ( Obj != &Header); Obj->Save (); Hash_Remove ( Obj ); Obj->Unlink(); } else { Obj = Free_Chain; Free_Chain = (Dbs_Object*) Free_Chain->Next; } if( Size > Obj->Size ) Realloc( Obj, Size ); Obj->Link( &Header ); *(o_size_t*)Obj->Buffer = Size; large Address = Odb_Address( File->Ident, File->Malloc( Size ) ); Chain = &Hash_Table[ tiny(Hash_Coding(Address)) ]; while ( (Node = *Chain)->Address > Address ) Chain = Hash_Next(Node); Hash_Insert( Chain, Obj ); Obj->Address = Address; Obj->State = Dbs_Object::Write; Obj->Fixed = 0; Obj->Store = File; return Obj->Buffer; } void Object_Cache::Free ( Physical Address ) { Dbs_Object* Obj = Odb_Get(Address); Obj->Store->Free( Odb_Offset(Obj->Address), *(o_size_t*)Obj->Buffer ); Obj->State = 0; Remove( Obj ); }