/////////////////////////////////////////////////////////// // Cache /////////////////////////////////////////////////////////// #include "ablib09.h" #define RWCACHE_SIZE 100 // funzione di default: prende una chiave a caso chiave const TString & TRWrecord_cache::getkey2discard() { THash_object * o=get_some_obj(); CHECK(o,"E' stata chiamata la funzione getkey2discard con la cache vuota"); return o->key(); } //Scarica una parte della cache void TRWrecord_cache::discard(const TString & vittima) { if (items()) //Usa l'items di TFile_cahe che richiame l'items dell'assoc_array _cache { if (_flags.is_key(vittima)) //_flags è un assoc_array di TRWcache, usa is_key di assoc_array { const char fl=((TString &)_flags[vittima])[1]; // record modificato o nuovo int err; TRectype & rec=(TRectype & )TRecord_cache::get(vittima); file().curr()=rec; if (fl == 'D') { err=file().rewrite(); if (err!=NOERR) error_box("Errore nella riscrittura della cache"); } else { err=file().write(); if (err!=NOERR) if (err == _isreinsert) file().rewrite(); else error_box("Errore nella scrittura della cache"); } _flags.remove(vittima); }//Se non esiste nel assoc_array di TRWcache _cache.remove(vittima); } } const TRectype& TRWrecord_cache::get(const char* chiave) { if (items()>=RWCACHE_SIZE) discard(getkey2discard()); const TRectype & rec=TRecord_cache::get(chiave); if (io_result() != NOERR) { // record non trovato: è nuovo _flags.add(chiave,new TString("N")); } return rec; } void TRWrecord_cache::put(const TRectype &r) { test_firm(); TToken_string cachekey; if (!r.empty()) { const RecDes* recd = r.rec_des(); // Descrizione del record della testata const KeyDes& kd = recd->Ky[key_number()-1]; // Elenco dei campi della chiave for (int i = file().tab() ? 1: 0; i < kd.NkFields; i++) // Riempie la chiave selezionata { const int nf = kd.FieldSeq[i] % MaxFields; const RecFieldDes& rf = recd->Fd[nf]; cachekey.add(r.get(rf.Name)); } } TObject* obj = _cache.objptr(cachekey); if (obj != NULL) { // esiste in cache ; tenta di settare il flag a "D"irty; se il flag esiste già è a TRectype & rec=(TRectype &)*obj; rec=r; _flags.add(cachekey , new TString("D")); } else { // non esiste in cache obj = rec2obj(r); _cache.add(cachekey, obj); // qui assume che non esista nemmeno su file, perciò sia "N"uovo; al flush correggerà l'errore _flags.add(cachekey , new TString("N")); } if (items()>=RWCACHE_SIZE) discard(getkey2discard()); } //Vuota una cache void TRWrecord_cache::clear() { while (items()>0) { const TString & vittima=getkey2discard(); if (_flags.is_key(vittima)) _flags.remove(vittima); _cache.remove(vittima); } } //Forza la scrittura sulla cache void TRWrecord_cache::flush() { while (items()>0) { discard(TRWrecord_cache::getkey2discard()); } } THash_object * TRWrecord_cache::get_some_obj() { if (items()==0) //Usa l'items() di TFilecache fa items() di un assoc_array _cahce return NULL; THash_object * o; while ((o=_cache.get_hashobj()) == NULL) ; //Ritorna l'oggetto e la relativa chiave dell'assoc_array _cache return o; } //Costruttori vari TRWrecord_cache::TRWrecord_cache(TLocalisamfile *f, int key, bool lock) :TRecord_cache(f,key) { if (lock) file().lock(); } TRWrecord_cache::TRWrecord_cache(int num, int key, bool lock) :TRecord_cache(num,key) { if (lock) file().lock(); } TRWrecord_cache::~TRWrecord_cache() { flush(); }