]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2045. [func] use lock buckets for acache entries to limit memory
authorTatuya JINMEI 神明達哉 <jinmei@isc.org>
Wed, 28 Jun 2006 08:28:49 +0000 (08:28 +0000)
committerTatuya JINMEI 神明達哉 <jinmei@isc.org>
Wed, 28 Jun 2006 08:28:49 +0000 (08:28 +0000)
consumption. [RT #16183]

CHANGES
lib/dns/acache.c

diff --git a/CHANGES b/CHANGES
index 0ac1acb5c1ab7af95c7991be32e15a7ec2e9103c..d4215627a0b6088c59a9e91e00bc1163e698a67d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,5 @@
-2045.  [placeholder]   rt16183
+2045.  [func]          use lock buckets for acache entries to limit memory
+                       consumption. [RT #16183]
 
 2044.  [port]          add support for atomic operations for Itanium.
                        [RT #16179]
index 5d68616ed1b33367dc36ae2c22b5984508f1e38b..6b8ff8b9576c07834e7d08b2fea1d573d0794e98 100644 (file)
@@ -14,7 +14,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: acache.c,v 1.16 2006/05/03 00:07:50 marka Exp $ */
+/* $Id: acache.c,v 1.17 2006/06/28 08:28:49 jinmei Exp $ */
 
 #include <config.h>
 
@@ -75,6 +75,8 @@
 #define DNS_ACACHE_MINSIZE             2097152 /* Bytes.  2097152 = 2 MB */
 #define DNS_ACACHE_CLEANERINCREMENT    1000    /* Number of entries. */
 
+#define DEFAULT_ACACHE_ENTRY_LOCK_COUNT        1009    /*%< Should be prime. */
+
 #if defined(ISC_RWLOCK_USEATOMIC) && defined(ISC_PLATFORM_HAVEATOMICSTORE)
 #define ACACHE_USE_RWLOCK 1
 #endif
@@ -177,6 +179,12 @@ struct dns_acache {
        isc_mem_t                       *mctx;
        isc_refcount_t                  refs;
 
+#ifdef ACACHE_USE_RWLOCK
+       isc_rwlock_t                    *entrylocks;
+#else
+       isc_mutex_t                     *entrylocks;
+#endif
+
        isc_mutex_t                     lock;
 
        int                             live_cleaners;
@@ -197,11 +205,7 @@ struct dns_acache {
 struct dns_acacheentry {
        unsigned int            magic;
 
-#ifdef ACACHE_USE_RWLOCK
-       isc_rwlock_t            lock;
-#else
-       isc_mutex_t             lock;
-#endif
+       unsigned int            locknum;
        isc_refcount_t          references;
 
        dns_acache_t            *acache;
@@ -303,7 +307,8 @@ shutdown_entries(dns_acache_t *acache) {
             entry = entry_next) {
                entry_next = ISC_LIST_NEXT(entry, link);
 
-               ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+               ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+                           isc_rwlocktype_write);
 
                /*
                 * If the cleaner holds this entry, it will be unlinked and
@@ -317,7 +322,8 @@ shutdown_entries(dns_acache_t *acache) {
                        entry->callback = NULL;
                }
 
-               ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+               ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+                             isc_rwlocktype_write);
 
                if (acache->cleaner.current_entry != entry)
                        dns_acache_detachentry(&entry);
@@ -413,8 +419,6 @@ destroy_entry(dns_acacheentry_t *entry) {
         */
        clear_entry(acache, entry);
 
-       ACACHE_DESTROYLOCK(&entry->lock);
-
        isc_mem_put(acache->mctx, entry, sizeof(*entry));
 
        dns_acache_detach(&acache);
@@ -422,6 +426,8 @@ destroy_entry(dns_acacheentry_t *entry) {
 
 static void
 destroy(dns_acache_t *acache) {
+       int i;
+
        REQUIRE(DNS_ACACHE_VALID(acache));
 
        ATRACE("destroy");
@@ -437,6 +443,12 @@ destroy(dns_acache_t *acache) {
        if (acache->task != NULL)
                isc_task_detach(&acache->task);
 
+       for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
+               ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
+       isc_mem_put(acache->mctx, acache->entrylocks,
+                   sizeof(*acache->entrylocks) *
+                   DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+
        DESTROYLOCK(&acache->cleaner.lock);
 
        DESTROYLOCK(&acache->lock);
@@ -817,12 +829,13 @@ acache_incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
 
        while (n_entries-- > 0) {
                isc_boolean_t is_stale = ISC_FALSE;
-               
+
                INSIST(entry != NULL);
 
                next = ISC_LIST_NEXT(entry, link);
 
-               ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+               ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+                           isc_rwlocktype_write);
 
                is_stale = entry_stale(cleaner, entry, now32, interval);
                if (is_stale) {
@@ -835,7 +848,8 @@ acache_incremental_cleaning_action(isc_task_t *task, isc_event_t *event) {
                        cleaner->ncleaned++;
                }
 
-               ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+               ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+                             isc_rwlocktype_write);
 
                if (is_stale)
                        dns_acache_detachentry(&entry);
@@ -1047,6 +1061,8 @@ dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
        acache->shutting_down = ISC_FALSE;
 
        acache->task = NULL;
+       acache->entrylocks = NULL;
+
        result = isc_task_create(taskmgr, 1, &acache->task);
        if (result != ISC_R_SUCCESS) {
                UNEXPECTED_ERROR(__FILE__, __LINE__,
@@ -1065,6 +1081,25 @@ dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
        for (i = 0; i < DBBUCKETS; i++)
                ISC_LIST_INIT(acache->dbbucket[i]);
 
+       acache->entrylocks = isc_mem_get(mctx, sizeof(*acache->entrylocks) *
+                                        DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+       if (acache->entrylocks == NULL) {
+               result = ISC_R_NOMEMORY;
+               goto cleanup;
+       }
+       for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++) {
+               result = ACACHE_INITLOCK(&acache->entrylocks[i]);
+               if (result != ISC_R_SUCCESS) {
+                       while (i-- > 0)
+                               ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
+                       isc_mem_put(mctx, acache->entrylocks,
+                                   sizeof(*acache->entrylocks) *
+                                   DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+                       acache->entrylocks = NULL;
+                       goto cleanup;
+               }
+       }
+
        acache->live_cleaners = 0;
        result = acache_cleaner_init(acache, timermgr, &acache->cleaner); 
        if (result != ISC_R_SUCCESS)
@@ -1084,6 +1119,13 @@ dns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx,
        DESTROYLOCK(&acache->lock);
        isc_refcount_decrement(&acache->refs, NULL);
        isc_refcount_destroy(&acache->refs);
+       if (acache->entrylocks != NULL) {
+               for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
+                       ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
+               isc_mem_put(mctx, acache->entrylocks,
+                           sizeof(*acache->entrylocks) *
+                           DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+       }
        isc_mem_put(mctx, acache, sizeof(*acache));
        isc_mem_detach(&mctx);
 
@@ -1249,7 +1291,8 @@ dns_acache_putdb(dns_acache_t *acache, dns_db_t *db) {
         * original holder has canceled callback,) destroy it here.
         */
        while ((entry = ISC_LIST_HEAD(dbentry->originlist)) != NULL) {
-               ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+               ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+                           isc_rwlocktype_write);
 
                /*
                 * Releasing olink first would avoid finddbent() in
@@ -1264,13 +1307,15 @@ dns_acache_putdb(dns_acache_t *acache, dns_db_t *db) {
                        (entry->callback)(entry, &entry->cbarg);
                entry->callback = NULL;
 
-               ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+               ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+                             isc_rwlocktype_write);
 
                if (acache->cleaner.current_entry != entry)
                        dns_acache_detachentry(&entry);
        }
        while ((entry = ISC_LIST_HEAD(dbentry->referlist)) != NULL) {
-               ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+               ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+                           isc_rwlocktype_write);
 
                ISC_LIST_UNLINK(dbentry->referlist, entry, rlink);
                if (acache->cleaner.current_entry != entry)
@@ -1281,7 +1326,8 @@ dns_acache_putdb(dns_acache_t *acache, dns_db_t *db) {
                        (entry->callback)(entry, &entry->cbarg);
                entry->callback = NULL;
 
-               ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+               ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+                             isc_rwlocktype_write);
 
                if (acache->cleaner.current_entry != entry)
                        dns_acache_detachentry(&entry);
@@ -1313,6 +1359,7 @@ dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
 {
        dns_acacheentry_t *newentry;
        isc_result_t result;
+       isc_uint32_t r;
 
        REQUIRE(DNS_ACACHE_VALID(acache));
        REQUIRE(entryp != NULL && *entryp == NULL);
@@ -1341,15 +1388,11 @@ dns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb,
                return (ISC_R_NOMEMORY);
        }
 
-       result = ACACHE_INITLOCK(&newentry->lock);
-       if (result != ISC_R_SUCCESS) {
-               isc_mem_put(acache->mctx, newentry, sizeof(*newentry));
-               return (result);
-       };
-
+       isc_random_get(&r);
+       newentry->locknum = r % DEFAULT_ACACHE_ENTRY_LOCK_COUNT;
+       
        result = isc_refcount_init(&newentry->references, 1);
        if (result != ISC_R_SUCCESS) {
-               ACACHE_DESTROYLOCK(&newentry->lock);
                isc_mem_put(acache->mctx, newentry, sizeof(*newentry));
                return (result);
        };
@@ -1390,6 +1433,8 @@ dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
        isc_result_t result = ISC_R_SUCCESS;
        dns_rdataset_t *erdataset;
        isc_stdtime32_t now32;
+       dns_acache_t *acache;
+       int locknum;
 
        REQUIRE(DNS_ACACHEENTRY_VALID(entry));
        REQUIRE(zonep == NULL || *zonep == NULL);
@@ -1398,8 +1443,11 @@ dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
        REQUIRE(nodep != NULL && *nodep == NULL);
        REQUIRE(fname != NULL);
        REQUIRE(msg != NULL);
-       
-       ACACHE_LOCK(&entry->lock, isc_rwlocktype_read);
+       acache = entry->acache;
+       REQUIRE(DNS_ACACHE_VALID(acache));
+
+       locknum = entry->locknum;
+       ACACHE_LOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
 
        isc_stdtime_convert32(now, &now32);
        acache_storetime(entry, now32);
@@ -1429,7 +1477,7 @@ dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
                        ardataset = NULL;
                        result = dns_message_gettemprdataset(msg, &ardataset);
                        if (result != ISC_R_SUCCESS) {
-                               ACACHE_UNLOCK(&entry->lock,
+                               ACACHE_UNLOCK(&acache->entrylocks[locknum],
                                              isc_rwlocktype_read);
                                goto fail;
                        }
@@ -1449,7 +1497,7 @@ dns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep,
        entry->acache->stats.hits++; /* XXXMLG danger: unlocked! */
        entry->acache->stats.queries++;
 
-       ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_read);
+       ACACHE_UNLOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
 
        return (result);
 
@@ -1486,7 +1534,7 @@ dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry,
        REQUIRE(DNS_ACACHEENTRY_VALID(entry));
 
        LOCK(&acache->lock);    /* XXX: need to lock it here for ordering */
-       ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+       ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
 
        /* Set zone */
        if (zone != NULL)
@@ -1578,7 +1626,8 @@ dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry,
         */
        dns_acache_attachentry(entry, &dummy_entry);
 
-       ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+       ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+                     isc_rwlocktype_write);
 
        acache->stats.adds++;
        UNLOCK(&acache->lock);
@@ -1588,7 +1637,8 @@ dns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry,
  fail:
        clear_entry(acache, entry);
 
-       ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+       ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+                     isc_rwlocktype_write);
        UNLOCK(&acache->lock);
 
        return (result);
@@ -1602,7 +1652,7 @@ dns_acache_cancelentry(dns_acacheentry_t *entry) {
        INSIST(DNS_ACACHE_VALID(acache));
 
        LOCK(&acache->lock);
-       ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+       ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
 
        /*
         * Release dependencies stored in this entry as much as possible.
@@ -1616,7 +1666,8 @@ dns_acache_cancelentry(dns_acacheentry_t *entry) {
        entry->callback = NULL;
        entry->cbarg = NULL;
 
-       ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+       ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+                     isc_rwlocktype_write);
        UNLOCK(&acache->lock);
 }