[haiku-commits] r35328 - haiku/trunk/src/system/kernel/cache

  • From: ingo_weinhold@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 28 Jan 2010 14:58:06 +0100 (CET)

Author: bonefish
Date: 2010-01-28 14:58:06 +0100 (Thu, 28 Jan 2010)
New Revision: 35328
Changeset: http://dev.haiku-os.org/changeset/35328/haiku

Modified:
   haiku/trunk/src/system/kernel/cache/block_cache.cpp
Log:
* Moved handling of busy blocks into separate functions.
* Added flags to avoid notifying the busy condition variable unnecessarily.
* get_writable_cached_block(): Unlock the cache while memcpy()ing/memset()ing
  the block's data. The idea is to reduce lock contention. Less effective
  than I hoped, though.


Modified: haiku/trunk/src/system/kernel/cache/block_cache.cpp
===================================================================
--- haiku/trunk/src/system/kernel/cache/block_cache.cpp 2010-01-28 11:25:25 UTC 
(rev 35327)
+++ haiku/trunk/src/system/kernel/cache/block_cache.cpp 2010-01-28 13:58:06 UTC 
(rev 35328)
@@ -74,6 +74,7 @@
        bool                    is_dirty : 1;
        bool                    unused : 1;
        bool                    discard : 1;
+       bool                    busy_waiters : 1;
        cache_transaction* transaction;
        cache_transaction* previous_transaction;
 
@@ -111,6 +112,7 @@
 
        ConditionVariable busy_condition;
        uint32                  busy_count;
+       bool                    busy_block_waiters;
 
        uint32                  num_dirty_blocks;
        bool                    read_only;
@@ -933,6 +935,7 @@
        transaction_hash(NULL),
        buffer_cache(NULL),
        busy_count(0),
+       busy_block_waiters(false),
        num_dirty_blocks(0),
        read_only(readOnly)
 {
@@ -1075,6 +1078,7 @@
        block->is_dirty = false;
        block->unused = false;
        block->discard = false;
+       block->busy_waiters = false;
 #if BLOCK_CACHE_DEBUG_CHANGED
        block->compare = NULL;
 #endif
@@ -1216,6 +1220,70 @@
 //     #pragma mark - private block functions
 
 
+/*!    Cache must be locked.
+*/
+static void
+mark_block_busy(block_cache* cache, cached_block* block)
+{
+       block->busy = true;
+       cache->busy_count++;
+}
+
+
+/*!    Cache must be locked.
+*/
+static void
+mark_block_unbusy(block_cache* cache, cached_block* block)
+{
+       block->busy = false;
+       cache->busy_count--;
+
+       if (cache->busy_block_waiters || block->busy_waiters) {
+               cache->busy_block_waiters = false;
+               block->busy_waiters = false;
+               cache->busy_condition.NotifyAll();
+       }
+}
+
+
+/*!    Cache must be locked.
+*/
+static void
+wait_for_busy_block(block_cache* cache, cached_block* block)
+{
+       // wait for all blocks to be read in/written back
+       ConditionVariableEntry entry;
+       cache->busy_condition.Add(&entry);
+       block->busy_waiters = true;
+
+       mutex_unlock(&cache->lock);
+
+       entry.Wait();
+
+       mutex_lock(&cache->lock);
+}
+
+
+/*!    Cache must be locked.
+*/
+static void
+wait_for_busy_blocks(block_cache* cache)
+{
+       while (cache->busy_count != 0) {
+               // wait for all blocks to be read in/written back
+               ConditionVariableEntry entry;
+               cache->busy_condition.Add(&entry);
+               cache->busy_block_waiters = true;
+
+               mutex_unlock(&cache->lock);
+
+               entry.Wait();
+
+               mutex_lock(&cache->lock);
+       }
+}
+
+
 /*!    Removes a reference from the specified \a block. If this was the last
        reference, the block is moved into the unused list.
        In low memory situations, it will also free some blocks from that list,
@@ -1337,14 +1405,7 @@
                *_allocated = true;
        } else if (block->busy) {
                // The block is currently busy - wait and try again later
-               ConditionVariableEntry entry;
-               cache->busy_condition.Add(&entry);
-
-               mutex_unlock(&cache->lock);
-
-               entry.Wait();
-
-               mutex_lock(&cache->lock);
+               wait_for_busy_block(cache, block);
                goto retry;
        }
 
@@ -1352,8 +1413,7 @@
                // read block into cache
                int32 blockSize = cache->block_size;
 
-               cache->busy_count++;
-               block->busy = true;
+               mark_block_busy(cache, block);
                mutex_unlock(&cache->lock);
 
                ssize_t bytesRead = read_pos(cache->fd, blockNumber * blockSize,
@@ -1369,10 +1429,7 @@
                TB(Read(cache, block));
 
                mutex_lock(&cache->lock);
-               block->busy = false;
-               cache->busy_count--;
-
-               cache->busy_condition.NotifyAll();
+               mark_block_unbusy(cache, block);
        }
 
        if (block->unused) {
@@ -1417,9 +1474,16 @@
 
        // if there is no transaction support, we just return the current block
        if (transactionID == -1) {
-               if (cleared)
+               if (cleared) {
+                       mark_block_busy(cache, block);
+                       mutex_unlock(&cache->lock);
+
                        memset(block->current_data, 0, cache->block_size);
 
+                       mutex_lock(&cache->lock);
+                       mark_block_unbusy(cache, block);
+               }
+
                if (!block->is_dirty) {
                        cache->num_dirty_blocks++;
                        block->is_dirty = true;
@@ -1477,7 +1541,13 @@
                        return NULL;
                }
 
+               mark_block_busy(cache, block);
+               mutex_unlock(&cache->lock);
+
                memcpy(block->original_data, block->current_data, 
cache->block_size);
+
+               mutex_lock(&cache->lock);
+               mark_block_unbusy(cache, block);
        }
        if (block->parent_data == block->current_data) {
                // remember any previous contents for the parent transaction
@@ -1490,15 +1560,29 @@
                        return NULL;
                }
 
+               mark_block_busy(cache, block);
+               mutex_unlock(&cache->lock);
+
                memcpy(block->parent_data, block->current_data, 
cache->block_size);
+
+               mutex_lock(&cache->lock);
+               mark_block_unbusy(cache, block);
+
                transaction->sub_num_blocks++;
        } else if (transaction != NULL && transaction->has_sub_transaction
                && block->parent_data == NULL && wasUnchanged)
                transaction->sub_num_blocks++;
 
-       if (cleared)
+       if (cleared) {
+               mark_block_busy(cache, block);
+               mutex_unlock(&cache->lock);
+
                memset(block->current_data, 0, cache->block_size);
 
+               mutex_lock(&cache->lock);
+               mark_block_unbusy(cache, block);
+       }
+
        block->is_dirty = true;
        TB(Get(cache, block));
        TB2(BlockData(cache, block, "get writable"));
@@ -2023,7 +2107,7 @@
                                while (count < kMaxCount
                                        && (block = 
(cached_block*)hash_next(cache->hash,
                                                        &iterator)) != NULL) {
-                                       if (block->is_dirty && 
!block->is_writing)
+                                       if (block->is_dirty && 
!block->is_writing && !block->busy)
                                                blocks[count++] = block;
                                }
 
@@ -2051,8 +2135,10 @@
                                        block_list::Iterator iterator
                                                = 
transaction->blocks.GetIterator();
 
-                                       for (; count < kMaxCount && 
iterator.HasNext(); count++) {
-                                               blocks[count] = iterator.Next();
+                                       while (count < kMaxCount && 
iterator.HasNext()) {
+                                               cached_block* block = 
iterator.Next();
+                                               if (!block->busy)
+                                                       blocks[count++] = block;
                                        }
                                }
 
@@ -2779,18 +2865,9 @@
 
        mutex_lock(&cache->lock);
 
-       while (cache->busy_count != 0) {
-               // wait for all blocks to be read in/written back
-               ConditionVariableEntry entry;
-               cache->busy_condition.Add(&entry);
+       // wait for all blocks to become unbusy
+       wait_for_busy_blocks(cache);
 
-               mutex_unlock(&cache->lock);
-
-               entry.Wait();
-
-               mutex_lock(&cache->lock);
-       }
-
        // free all blocks
 
        uint32 cookie = 0;


Other related posts:

  • » [haiku-commits] r35328 - haiku/trunk/src/system/kernel/cache - ingo_weinhold