]> git.ozlabs.org Git - ccan/blobdiff - ccan/tdb2/free.c
tdb2: expand more slowly.
[ccan] / ccan / tdb2 / free.c
index e2b9cb18c5043a98a173eca52fecab4c22ad3dae..c03680cfd943557d883daeee50b5ede41b707e75 100644 (file)
@@ -713,13 +713,10 @@ enum TDB_ERROR set_header(struct tdb_context *tdb,
 /* Expand the database. */
 static enum TDB_ERROR tdb_expand(struct tdb_context *tdb, tdb_len_t size)
 {
-       uint64_t old_size;
+       uint64_t old_size, rec_size, map_size;
        tdb_len_t wanted;
        enum TDB_ERROR ecode;
 
-       /* We need room for the record header too. */
-       wanted = sizeof(struct tdb_used_record) + size;
-
        /* Need to hold a hash lock to expand DB: transactions rely on it. */
        if (!(tdb->flags & TDB_NOLOCK)
            && !tdb->file->allrecord_lock.count && !tdb_has_hash_locks(tdb)) {
@@ -727,14 +724,6 @@ static enum TDB_ERROR tdb_expand(struct tdb_context *tdb, tdb_len_t size)
                                  "tdb_expand: must hold lock during expand");
        }
 
-       /* always make room for at least 100 more records, and at
-           least 25% more space. */
-       if (size * TDB_EXTENSION_FACTOR > tdb->file->map_size / 4)
-               wanted = size * TDB_EXTENSION_FACTOR;
-       else
-               wanted = tdb->file->map_size / 4;
-       wanted = adjust_size(0, wanted);
-
        /* Only one person can expand file at a time. */
        ecode = tdb_lock_expand(tdb, F_WRLCK);
        if (ecode != TDB_SUCCESS) {
@@ -749,6 +738,32 @@ static enum TDB_ERROR tdb_expand(struct tdb_context *tdb, tdb_len_t size)
                return TDB_SUCCESS;
        }
 
+       /* limit size in order to avoid using up huge amounts of memory for
+        * in memory tdbs if an oddball huge record creeps in */
+       if (size > 100 * 1024) {
+               rec_size = size * 2;
+       } else {
+               rec_size = size * 100;
+       }
+
+       /* always make room for at least rec_size more records, and at
+          least 25% more space. if the DB is smaller than 100MiB,
+          otherwise grow it by 10% only. */
+       if (old_size > 100 * 1024 * 1024) {
+               map_size = old_size / 10;
+       } else {
+               map_size = old_size / 4;
+       }
+
+       if (map_size > rec_size) {
+               wanted = map_size;
+       } else {
+               wanted = rec_size;
+       }
+
+       /* We need room for the record header too. */
+       wanted = adjust_size(0, sizeof(struct tdb_used_record) + wanted);
+
        ecode = tdb->methods->expand_file(tdb, wanted);
        if (ecode != TDB_SUCCESS) {
                tdb_unlock_expand(tdb, F_WRLCK);