Ejemplo n.º 1
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 (!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;
}
Ejemplo n.º 2
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;
}
Ejemplo n.º 3
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();
}
Ejemplo n.º 4
0
/*
 * 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();
}