aboutsummaryrefslogtreecommitdiffstats
path: root/g10/tdbio.c
diff options
context:
space:
mode:
Diffstat (limited to 'g10/tdbio.c')
-rw-r--r--g10/tdbio.c108
1 files changed, 103 insertions, 5 deletions
diff --git a/g10/tdbio.c b/g10/tdbio.c
index 76e606e0e..1954929ae 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -56,9 +56,11 @@ struct cache_ctrl_struct {
char data[TRUST_RECORD_LEN];
};
-#define MAX_CACHE_ENTRIES 200
+#define MAX_CACHE_ENTRIES_SOFT 200 /* may be increased due while in a */
+#define MAX_CACHE_ENTRIES_HARD 1000 /* transaction to this one */
static CACHE_CTRL cache_list;
static int cache_entries;
+static int cache_is_dirty;
/* a type used to pass infomation to cmp_krec_fpr */
struct cmp_krec_fpr_struct {
@@ -76,6 +78,7 @@ struct cmp_sdir_struct {
static char *db_name;
static int db_fd = -1;
+static int in_transaction;
static void open_db(void);
@@ -143,8 +146,10 @@ put_record_into_cache( ulong recno, const char *data )
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 ) )
+ 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;
@@ -163,11 +168,12 @@ put_record_into_cache( ulong recno, const char *data )
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 ) { /* no */
+ if( cache_entries < MAX_CACHE_ENTRIES_SOFT ) { /* no */
r = m_alloc( sizeof *r );
r->flags.used = 1;
r->recno = recno;
@@ -175,6 +181,7 @@ put_record_into_cache( ulong recno, const char *data )
r->flags.dirty = 1;
r->next = cache_list;
cache_list = r;
+ cache_is_dirty = 1;
cache_entries++;
return 0;
}
@@ -199,10 +206,31 @@ put_record_into_cache( ulong recno, const char *data )
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( !(cache_entries % 100) )
+ log_info("increasing tdbio cache size\n");
+ r = m_alloc( 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("hard cache size limit reached\n");
+ return G10ERR_RESOURCE_LIMIT;
+ }
if( dirty_count ) {
int n = dirty_count / 5; /* discard some dirty entries */
if( !n )
@@ -226,6 +254,7 @@ put_record_into_cache( ulong recno, const char *data )
r->recno = recno;
memcpy( r->data, data, TRUST_RECORD_LEN );
r->flags.dirty = 1;
+ cache_is_dirty = 1;
cache_entries++;
return 0;
}
@@ -233,16 +262,27 @@ put_record_into_cache( ulong recno, const char *data )
}
+int
+tdbio_is_dirty()
+{
+ return cache_is_dirty;
+}
+
/****************
- * Sync the cache to disk
+ * Flush the cache. This cannot be used while in a transaction.
*/
-
int
tdbio_sync()
{
CACHE_CTRL r;
+ if( in_transaction )
+ log_bug("tdbio: syncing while in transaction\n");
+
+ if( !cache_is_dirty )
+ return 0;
+
for( r = cache_list; r; r = r->next ) {
if( r->flags.used && r->flags.dirty ) {
int rc = write_cache_item( r );
@@ -250,6 +290,63 @@ tdbio_sync()
return rc;
}
}
+ cache_is_dirty = 0;
+ return 0;
+}
+
+
+
+/****************
+ * Simple transactions system:
+ * Everything between begin_transaction and end/cancel_transaction
+ * is not immediatly written but at the time of end_transaction.
+ *
+ */
+int
+tdbio_begin_transaction()
+{
+ int rc;
+
+ if( in_transaction )
+ log_bug("tdbio: nested transactions\n");
+ /* flush everything out */
+ rc = tdbio_sync();
+ if( rc )
+ return rc;
+ in_transaction = 1;
+ return 0;
+}
+
+int
+tdbio_end_transaction()
+{
+ if( !in_transaction )
+ log_bug("tdbio: no active transaction\n");
+ in_transaction = 0;
+ return tdbio_sync();
+}
+
+int
+tdbio_cancel_transaction()
+{
+ CACHE_CTRL r;
+
+ if( !in_transaction )
+ log_bug("tdbio: no active transaction\n");
+
+ /* remove all dirty marked entries, so that the original ones
+ * are read back the next time */
+ if( cache_is_dirty ) {
+ for( r = cache_list; r; r = r->next ) {
+ if( r->flags.used && r->flags.dirty ) {
+ r->flags.used = 0;
+ cache_entries--;
+ }
+ }
+ cache_is_dirty = 0;
+ }
+
+ in_transaction = 0;
return 0;
}
@@ -293,6 +390,7 @@ tdbio_set_dbname( const char *new_dbname, int create )
fname, strerror(errno) );
else
log_info( _("%s: directory created\n"), fname );
+ copy_options_file( fname );
}
else
log_fatal( _("%s: directory does not exist!\n"), fname );