/**************** * Flush the cache. This cannot be used while in a transaction. */ int tdbio_sync() { CACHE_CTRL r; int did_lock = 0; if( db_fd == -1 ) open_db(); if( in_transaction ) log_bug("tdbio: syncing while in transaction\n"); if( !cache_is_dirty ) return 0; if (!take_write_lock ()) did_lock = 1; for( r = cache_list; r; r = r->next ) { if( r->flags.used && r->flags.dirty ) { int rc = write_cache_item( r ); if( rc ) return rc; } } cache_is_dirty = 0; if (did_lock) release_write_lock (); return 0; }
/**************** * Flush the cache. This cannot be used while in a transaction. */ int tdbio_sync() { CACHE_CTRL r; int did_lock = 0; if( db_fd == -1 ) open_db(); if( in_transaction ) log_bug("tdbio: syncing while in transaction\n"); if( !cache_is_dirty ) return 0; if( !is_locked ) { if( make_dotlock( lockhandle, -1 ) ) log_fatal("can't acquire lock - giving up\n"); else is_locked = 1; did_lock = 1; } for( r = cache_list; r; r = r->next ) { if( r->flags.used && r->flags.dirty ) { int rc = write_cache_item( r ); if( rc ) return rc; } } cache_is_dirty = 0; if( did_lock && !opt.lock_once ) { if( !release_dotlock( lockhandle ) ) is_locked = 0; } return 0; }
/**************** * Put data into the cache. This function may flush the * some cache entries if there is not enough space available. */ int put_record_into_cache( ulong recno, const char *data ) { CACHE_CTRL r, unused; int dirty_count = 0; int clean_count = 0; /* see whether we already cached this one */ for( unused = NULL, r = cache_list; r; r = r->next ) { if( !r->flags.used ) { if( !unused ) unused = r; } else if( r->recno == recno ) { if( !r->flags.dirty ) { /* Hmmm: should we use a a copy and compare? */ if( memcmp(r->data, data, TRUST_RECORD_LEN ) ) { r->flags.dirty = 1; cache_is_dirty = 1; } } memcpy( r->data, data, TRUST_RECORD_LEN ); return 0; } if( r->flags.used ) { if( r->flags.dirty ) dirty_count++; else clean_count++; } } /* not in the cache: add a new entry */ if( unused ) { /* reuse this entry */ r = unused; r->flags.used = 1; r->recno = recno; memcpy( r->data, data, TRUST_RECORD_LEN ); r->flags.dirty = 1; cache_is_dirty = 1; cache_entries++; return 0; } /* see whether we reached the limit */ if( cache_entries < MAX_CACHE_ENTRIES_SOFT ) { /* no */ r = xmalloc( sizeof *r ); r->flags.used = 1; r->recno = recno; memcpy( r->data, data, TRUST_RECORD_LEN ); r->flags.dirty = 1; r->next = cache_list; cache_list = r; cache_is_dirty = 1; cache_entries++; return 0; } /* cache is full: discard some clean entries */ if( clean_count ) { int n = clean_count / 3; /* discard a third of the clean entries */ if( !n ) n = 1; for( unused = NULL, r = cache_list; r; r = r->next ) { if( r->flags.used && !r->flags.dirty ) { if( !unused ) unused = r; r->flags.used = 0; cache_entries--; if( !--n ) break; } } assert( unused ); r = unused; r->flags.used = 1; r->recno = recno; memcpy( r->data, data, TRUST_RECORD_LEN ); r->flags.dirty = 1; cache_is_dirty = 1; cache_entries++; return 0; } /* no clean entries: have to flush some dirty entries */ if( in_transaction ) { /* but we can't do this while in a transaction * we increase the cache size instead */ if( cache_entries < MAX_CACHE_ENTRIES_HARD ) { /* no */ if( opt.debug && !(cache_entries % 100) ) log_debug("increasing tdbio cache size\n"); r = xmalloc( sizeof *r ); r->flags.used = 1; r->recno = recno; memcpy( r->data, data, TRUST_RECORD_LEN ); r->flags.dirty = 1; r->next = cache_list; cache_list = r; cache_is_dirty = 1; cache_entries++; return 0; } log_info(_("trustdb transaction too large\n")); return G10ERR_RESOURCE_LIMIT; } if( dirty_count ) { int n = dirty_count / 5; /* discard some dirty entries */ if( !n ) n = 1; if( !is_locked ) { if( make_dotlock( lockhandle, -1 ) ) log_fatal("can't acquire lock - giving up\n"); else is_locked = 1; } for( unused = NULL, r = cache_list; r; r = r->next ) { if( r->flags.used && r->flags.dirty ) { int rc = write_cache_item( r ); if( rc ) return rc; if( !unused ) unused = r; r->flags.used = 0; cache_entries--; if( !--n ) break; } } if( !opt.lock_once ) { if( !release_dotlock( lockhandle ) ) is_locked = 0; } assert( unused ); r = unused; r->flags.used = 1; r->recno = recno; memcpy( r->data, data, TRUST_RECORD_LEN ); r->flags.dirty = 1; cache_is_dirty = 1; cache_entries++; return 0; } BUG(); }
/* * Put data into the cache. This function may flush * some cache entries if the cache is filled up. * * Returns: 0 on success or an error code. */ static int put_record_into_cache (ulong recno, const char *data) { CACHE_CTRL r, unused; int dirty_count = 0; int clean_count = 0; /* See whether we already cached this one. */ for (unused = NULL, r = cache_list; r; r = r->next) { if (!r->flags.used) { if (!unused) unused = r; } else if (r->recno == recno) { if (!r->flags.dirty) { /* Hmmm: should we use a copy and compare? */ if (memcmp (r->data, data, TRUST_RECORD_LEN)) { r->flags.dirty = 1; cache_is_dirty = 1; } } memcpy (r->data, data, TRUST_RECORD_LEN); return 0; } if (r->flags.used) { if (r->flags.dirty) dirty_count++; else clean_count++; } } /* Not in the cache: add a new entry. */ if (unused) { /* Reuse this entry. */ r = unused; r->flags.used = 1; r->recno = recno; memcpy (r->data, data, TRUST_RECORD_LEN); r->flags.dirty = 1; cache_is_dirty = 1; cache_entries++; return 0; } /* See whether we reached the limit. */ if (cache_entries < MAX_CACHE_ENTRIES_SOFT) { /* No: Put into cache. */ r = xmalloc (sizeof *r); r->flags.used = 1; r->recno = recno; memcpy (r->data, data, TRUST_RECORD_LEN); r->flags.dirty = 1; r->next = cache_list; cache_list = r; cache_is_dirty = 1; cache_entries++; return 0; } /* Cache is full: discard some clean entries. */ if (clean_count) { int n; /* We discard a third of the clean entries. */ n = clean_count / 3; if (!n) n = 1; for (unused = NULL, r = cache_list; r; r = r->next) { if (r->flags.used && !r->flags.dirty) { if (!unused) unused = r; r->flags.used = 0; cache_entries--; if (!--n) break; } } /* Now put into the cache. */ assert (unused); r = unused; r->flags.used = 1; r->recno = recno; memcpy (r->data, data, TRUST_RECORD_LEN); r->flags.dirty = 1; cache_is_dirty = 1; cache_entries++; return 0; } /* No clean entries: We have to flush some dirty entries. */ if (in_transaction) { /* But we can't do this while in a transaction. Thus we * increase the cache size instead. */ if (cache_entries < MAX_CACHE_ENTRIES_HARD) { if (opt.debug && !(cache_entries % 100)) log_debug ("increasing tdbio cache size\n"); r = xmalloc (sizeof *r); r->flags.used = 1; r->recno = recno; memcpy (r->data, data, TRUST_RECORD_LEN); r->flags.dirty = 1; r->next = cache_list; cache_list = r; cache_is_dirty = 1; cache_entries++; return 0; } /* Hard limit for the cache size reached. */ log_info (_("trustdb transaction too large\n")); return GPG_ERR_RESOURCE_LIMIT; } if (dirty_count) { int n; /* Discard some dirty entries. */ n = dirty_count / 5; if (!n) n = 1; take_write_lock (); for (unused = NULL, r = cache_list; r; r = r->next) { if (r->flags.used && r->flags.dirty) { int rc; rc = write_cache_item (r); if (rc) return rc; if (!unused) unused = r; r->flags.used = 0; cache_entries--; if (!--n) break; } } release_write_lock (); /* Now put into the cache. */ assert (unused); r = unused; r->flags.used = 1; r->recno = recno; memcpy (r->data, data, TRUST_RECORD_LEN); r->flags.dirty = 1; cache_is_dirty = 1; cache_entries++; return 0; } /* We should never reach this. */ BUG(); }