* Added function block_cache_discard() that flushes blocks from the block cache,

discarding their changes. This functionality currently only works correctly
  when no transactions are used.
* Started test application for the block cache, doesn't do anything yet.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@28496 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2008-11-04 14:49:33 +00:00
parent 5ae0bbaad0
commit 5b812019b4
7 changed files with 202 additions and 87 deletions
+39 -37
View File
@@ -33,70 +33,72 @@ extern "C" {
#endif #endif
/* transactions */ /* transactions */
extern int32 cache_start_transaction(void *_cache); extern int32 cache_start_transaction(void *cache);
extern status_t cache_sync_transaction(void *_cache, int32 id); extern status_t cache_sync_transaction(void *cache, int32 id);
extern status_t cache_end_transaction(void *_cache, int32 id, extern status_t cache_end_transaction(void *cache, int32 id,
transaction_notification_hook hook, void *data); transaction_notification_hook hook, void *data);
extern status_t cache_abort_transaction(void *_cache, int32 id); extern status_t cache_abort_transaction(void *cache, int32 id);
extern int32 cache_detach_sub_transaction(void *_cache, int32 id, extern int32 cache_detach_sub_transaction(void *cache, int32 id,
transaction_notification_hook hook, void *data); transaction_notification_hook hook, void *data);
extern status_t cache_abort_sub_transaction(void *_cache, int32 id); extern status_t cache_abort_sub_transaction(void *cache, int32 id);
extern status_t cache_start_sub_transaction(void *_cache, int32 id); extern status_t cache_start_sub_transaction(void *cache, int32 id);
extern status_t cache_add_transaction_listener(void *_cache, int32 id, extern status_t cache_add_transaction_listener(void *cache, int32 id,
int32 events, transaction_notification_hook hook, int32 events, transaction_notification_hook hook,
void *data); void *data);
extern status_t cache_remove_transaction_listener(void *_cache, int32 id, extern status_t cache_remove_transaction_listener(void *cache, int32 id,
transaction_notification_hook hook, void *data); transaction_notification_hook hook, void *data);
extern status_t cache_next_block_in_transaction(void *_cache, int32 id, extern status_t cache_next_block_in_transaction(void *cache, int32 id,
bool mainOnly, long *_cookie, off_t *_blockNumber, bool mainOnly, long *_cookie, off_t *_blockNumber,
void **_data, void **_unchangedData); void **_data, void **_unchangedData);
extern int32 cache_blocks_in_transaction(void *_cache, int32 id); extern int32 cache_blocks_in_transaction(void *cache, int32 id);
extern int32 cache_blocks_in_main_transaction(void *_cache, int32 id); extern int32 cache_blocks_in_main_transaction(void *cache, int32 id);
extern int32 cache_blocks_in_sub_transaction(void *_cache, int32 id); extern int32 cache_blocks_in_sub_transaction(void *cache, int32 id);
/* block cache */ /* block cache */
extern void block_cache_delete(void *_cache, bool allowWrites); extern void block_cache_delete(void *cache, bool allowWrites);
extern void *block_cache_create(int fd, off_t numBlocks, size_t blockSize, extern void *block_cache_create(int fd, off_t numBlocks, size_t blockSize,
bool readOnly); bool readOnly);
extern status_t block_cache_sync(void *_cache); extern status_t block_cache_sync(void *cache);
extern status_t block_cache_sync_etc(void *_cache, off_t blockNumber, extern status_t block_cache_sync_etc(void *cache, off_t blockNumber,
size_t numBlocks); size_t numBlocks);
extern status_t block_cache_make_writable(void *_cache, off_t blockNumber, extern void block_cache_discard(void *cache, off_t blockNumber,
size_t numBlocks);
extern status_t block_cache_make_writable(void *cache, off_t blockNumber,
int32 transaction); int32 transaction);
extern void *block_cache_get_writable_etc(void *_cache, off_t blockNumber, extern void *block_cache_get_writable_etc(void *cache, off_t blockNumber,
off_t base, off_t length, int32 transaction); off_t base, off_t length, int32 transaction);
extern void *block_cache_get_writable(void *_cache, off_t blockNumber, extern void *block_cache_get_writable(void *cache, off_t blockNumber,
int32 transaction); int32 transaction);
extern void *block_cache_get_empty(void *_cache, off_t blockNumber, extern void *block_cache_get_empty(void *cache, off_t blockNumber,
int32 transaction); int32 transaction);
extern const void *block_cache_get_etc(void *_cache, off_t blockNumber, extern const void *block_cache_get_etc(void *cache, off_t blockNumber,
off_t base, off_t length); off_t base, off_t length);
extern const void *block_cache_get(void *_cache, off_t blockNumber); extern const void *block_cache_get(void *cache, off_t blockNumber);
extern status_t block_cache_set_dirty(void *_cache, off_t blockNumber, extern status_t block_cache_set_dirty(void *cache, off_t blockNumber,
bool isDirty, int32 transaction); bool isDirty, int32 transaction);
extern void block_cache_put(void *_cache, off_t blockNumber); extern void block_cache_put(void *cache, off_t blockNumber);
/* file cache */ /* file cache */
extern void *file_cache_create(dev_t mountID, ino_t vnodeID, off_t size); extern void *file_cache_create(dev_t mountID, ino_t vnodeID, off_t size);
extern void file_cache_delete(void *_cacheRef); extern void file_cache_delete(void *cacheRef);
extern void file_cache_enable(void *_cacheRef); extern void file_cache_enable(void *cacheRef);
extern bool file_cache_is_enabled(void *_cacheRef); extern bool file_cache_is_enabled(void *cacheRef);
extern status_t file_cache_disable(void *_cacheRef); extern status_t file_cache_disable(void *cacheRef);
extern status_t file_cache_set_size(void *_cacheRef, off_t size); extern status_t file_cache_set_size(void *cacheRef, off_t size);
extern status_t file_cache_sync(void *_cache); extern status_t file_cache_sync(void *cache);
extern status_t file_cache_read(void *_cacheRef, void *cookie, off_t offset, extern status_t file_cache_read(void *cacheRef, void *cookie, off_t offset,
void *bufferBase, size_t *_size); void *bufferBase, size_t *_size);
extern status_t file_cache_write(void *_cacheRef, void *cookie, off_t offset, extern status_t file_cache_write(void *cacheRef, void *cookie, off_t offset,
const void *buffer, size_t *_size); const void *buffer, size_t *_size);
/* file map */ /* file map */
extern void *file_map_create(dev_t mountID, ino_t vnodeID, off_t size); extern void *file_map_create(dev_t mountID, ino_t vnodeID, off_t size);
extern void file_map_delete(void *_map); extern void file_map_delete(void *map);
extern void file_map_set_size(void *_map, off_t size); extern void file_map_set_size(void *map, off_t size);
extern void file_map_invalidate(void *_map, off_t offset, off_t size); extern void file_map_invalidate(void *map, off_t offset, off_t size);
extern status_t file_map_set_mode(void *_map, uint32 mode); extern status_t file_map_set_mode(void *map, uint32 mode);
extern status_t file_map_translate(void *_map, off_t offset, size_t size, extern status_t file_map_translate(void *map, off_t offset, size_t size,
struct file_io_vec *vecs, size_t *_count, size_t align); struct file_io_vec *vecs, size_t *_count, size_t align);
/* entry cache */ /* entry cache */
@@ -820,6 +820,7 @@
#define block_cache_create fssh_block_cache_create #define block_cache_create fssh_block_cache_create
#define block_cache_sync fssh_block_cache_sync #define block_cache_sync fssh_block_cache_sync
#define block_cache_sync_etc fssh_block_cache_sync_etc #define block_cache_sync_etc fssh_block_cache_sync_etc
#define block_cache_discard fssh_block_cache_discard
#define block_cache_make_writable fssh_block_cache_make_writable #define block_cache_make_writable fssh_block_cache_make_writable
#define block_cache_get_writable_etc fssh_block_cache_get_writable_etc #define block_cache_get_writable_etc fssh_block_cache_get_writable_etc
#define block_cache_get_writable fssh_block_cache_get_writable #define block_cache_get_writable fssh_block_cache_get_writable
+2
View File
@@ -70,6 +70,8 @@ extern void * fssh_block_cache_create(int fd, fssh_off_t numBlocks,
extern fssh_status_t fssh_block_cache_sync(void *_cache); extern fssh_status_t fssh_block_cache_sync(void *_cache);
extern fssh_status_t fssh_block_cache_sync_etc(void *_cache, extern fssh_status_t fssh_block_cache_sync_etc(void *_cache,
fssh_off_t blockNumber, fssh_size_t numBlocks); fssh_off_t blockNumber, fssh_size_t numBlocks);
extern void fssh_block_cache_discard(void *_cache,
fssh_off_t blockNumber, fssh_size_t numBlocks);
extern fssh_status_t fssh_block_cache_make_writable(void *_cache, extern fssh_status_t fssh_block_cache_make_writable(void *_cache,
fssh_off_t blockNumber, int32_t transaction); fssh_off_t blockNumber, int32_t transaction);
extern void * fssh_block_cache_get_writable_etc(void *_cache, extern void * fssh_block_cache_get_writable_etc(void *_cache,
+73 -28
View File
@@ -74,6 +74,7 @@ struct cached_block {
bool is_writing : 1; bool is_writing : 1;
bool is_dirty : 1; bool is_dirty : 1;
bool unused : 1; bool unused : 1;
bool discard : 1;
cache_transaction *transaction; cache_transaction *transaction;
cache_transaction *previous_transaction; cache_transaction *previous_transaction;
@@ -122,12 +123,13 @@ struct block_cache : DoublyLinkedListLinkImpl<block_cache> {
void RemoveUnusedBlocks(int32 maxAccessed = LONG_MAX, void RemoveUnusedBlocks(int32 maxAccessed = LONG_MAX,
int32 count = LONG_MAX); int32 count = LONG_MAX);
void FreeBlock(cached_block *block); void RemoveBlock(cached_block* block);
cached_block *NewBlock(off_t blockNumber); void FreeBlock(cached_block* block);
void Free(void *buffer); cached_block* NewBlock(off_t blockNumber);
void *Allocate(); void Free(void* buffer);
void* Allocate();
static void LowMemoryHandler(void *data, uint32 resources, int32 level); static void LowMemoryHandler(void* data, uint32 resources, int32 level);
private: private:
cached_block *_GetUnusedBlock(); cached_block *_GetUnusedBlock();
@@ -909,6 +911,7 @@ block_cache::NewBlock(off_t blockNumber)
block->parent_data = NULL; block->parent_data = NULL;
block->is_dirty = false; block->is_dirty = false;
block->unused = false; block->unused = false;
block->discard = false;
#if BLOCK_CACHE_DEBUG_CHANGED #if BLOCK_CACHE_DEBUG_CHANGED
block->compare = NULL; block->compare = NULL;
#endif #endif
@@ -917,6 +920,14 @@ block_cache::NewBlock(off_t blockNumber)
} }
void
block_cache::RemoveBlock(cached_block* block)
{
hash_remove(hash, block);
FreeBlock(block);
}
void void
block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count) block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
{ {
@@ -932,14 +943,12 @@ block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
block->block_number, block->accessed)); block->block_number, block->accessed));
// this can only happen if no transactions are used // this can only happen if no transactions are used
if (block->is_dirty) if (block->is_dirty && !block->discard)
write_cached_block(this, block, false); write_cached_block(this, block, false);
// remove block from lists // remove block from lists
iterator.Remove(); iterator.Remove();
hash_remove(hash, block); RemoveBlock(block);
FreeBlock(block);
if (--count <= 0) if (--count <= 0)
break; break;
@@ -1022,17 +1031,20 @@ put_cached_block(block_cache *cache, cached_block *block)
} }
if (--block->ref_count == 0 if (--block->ref_count == 0
&& block->transaction == NULL && block->transaction == NULL && block->previous_transaction == NULL) {
&& block->previous_transaction == NULL) { // This block is not used anymore, and not part of any transaction
// put this block in the list of unused blocks if (block->discard) {
block->unused = true; cache->RemoveBlock(block);
if (block->original_data != NULL || block->parent_data != NULL) } else {
panic("put_cached_block(): %p (%Ld): %p, %p\n", block, block->block_number, block->original_data, block->parent_data); // put this block in the list of unused blocks
cache->unused_blocks.Add(block); block->unused = true;
// block->current_data = cache->allocator->Release(block->current_data); ASSERT(block->original_data == NULL
&& block->parent_data == NULL);
cache->unused_blocks.Add(block);
}
} }
// free some blocks according to the low memory state // Free some blocks according to the low memory state
// (if there is enough memory left, we don't free any) // (if there is enough memory left, we don't free any)
int32 free = 1; int32 free = 1;
@@ -1111,8 +1123,7 @@ get_cached_block(block_cache *cache, off_t blockNumber, bool *_allocated,
ssize_t bytesRead = read_pos(cache->fd, blockNumber * blockSize, ssize_t bytesRead = read_pos(cache->fd, blockNumber * blockSize,
block->current_data, blockSize); block->current_data, blockSize);
if (bytesRead < blockSize) { if (bytesRead < blockSize) {
hash_remove(cache->hash, block); cache->RemoveBlock(block);
cache->FreeBlock(block);
TB(Error(cache, blockNumber, "read failed", bytesRead)); TB(Error(cache, blockNumber, "read failed", bytesRead));
FATAL(("could not read block %Ld: bytesRead: %ld, error: %s\n", FATAL(("could not read block %Ld: bytesRead: %ld, error: %s\n",
@@ -1160,6 +1171,8 @@ get_writable_cached_block(block_cache *cache, off_t blockNumber, off_t base,
if (block == NULL) if (block == NULL)
return NULL; return NULL;
block->discard = false;
// if there is no transaction support, we just return the current block // if there is no transaction support, we just return the current block
if (transactionID == -1) { if (transactionID == -1) {
if (cleared) if (cleared)
@@ -1843,8 +1856,9 @@ cache_sync_transaction(void *_cache, int32 id)
T(Action("sync", cache, transaction)); T(Action("sync", cache, transaction));
while (transaction->num_blocks > 0) { while (transaction->num_blocks > 0) {
// sort blocks to speed up writing them back // sort blocks to speed up writing them back
// TODO: ideally, this should be handled by the I/O scheduler // TODO: this should be handled by the I/O scheduler
block_list::Iterator iterator = transaction->blocks.GetIterator(); block_list::Iterator iterator
= transaction->blocks.GetIterator();
uint32 maxCount = transaction->num_blocks; uint32 maxCount = transaction->num_blocks;
cached_block *buffer[16]; cached_block *buffer[16];
cached_block **blocks = (cached_block **)malloc(maxCount cached_block **blocks = (cached_block **)malloc(maxCount
@@ -1984,6 +1998,7 @@ cache_abort_transaction(void *_cache, int32 id)
block->transaction_next = NULL; block->transaction_next = NULL;
block->transaction = NULL; block->transaction = NULL;
block->discard = false;
} }
hash_remove(cache->transaction_hash, transaction); hash_remove(cache->transaction_hash, transaction);
@@ -2251,10 +2266,16 @@ cache_next_block_in_transaction(void *_cache, int32 id, bool mainOnly,
else else
block = block->transaction_next; block = block->transaction_next;
if (mainOnly && transaction->has_sub_transaction) { if (transaction->has_sub_transaction) {
// find next block that the parent changed if (mainOnly) {
while (block != NULL && block->parent_data == NULL) // find next block that the parent changed
block = block->transaction_next; while (block != NULL && block->parent_data == NULL)
block = block->transaction_next;
} else {
// find next non-discarded block
while (block != NULL && block->discard)
block = block->transaction_next;
}
} }
if (block == NULL) if (block == NULL)
@@ -2427,8 +2448,6 @@ block_cache_sync_etc(void *_cache, off_t blockNumber, size_t numBlocks)
if (block == NULL) if (block == NULL)
continue; continue;
// TODO: sort blocks!
if (block->previous_transaction != NULL if (block->previous_transaction != NULL
|| (block->transaction == NULL && block->is_dirty)) { || (block->transaction == NULL && block->is_dirty)) {
status_t status = write_cached_block(cache, block); status_t status = write_cached_block(cache, block);
@@ -2446,6 +2465,32 @@ block_cache_sync_etc(void *_cache, off_t blockNumber, size_t numBlocks)
} }
extern "C" void
block_cache_discard(void* _cache, off_t blockNumber, size_t numBlocks)
{
block_cache* cache = (block_cache*)_cache;
MutexLocker locker(&cache->lock);
for (; numBlocks > 0; numBlocks--, blockNumber++) {
cached_block* block = (cached_block*)hash_lookup(cache->hash,
&blockNumber);
if (block == NULL)
continue;
if (block->unused) {
cache->unused_blocks.Remove(block);
cache->RemoveBlock(block);
} else {
// mark them as discarded (in the current transaction only, if any)
if (block->previous_transaction != NULL)
write_cached_block(cache, block);
block->discard = true;
}
}
}
extern "C" status_t extern "C" status_t
block_cache_make_writable(void *_cache, off_t blockNumber, int32 transaction) block_cache_make_writable(void *_cache, off_t blockNumber, int32 transaction)
{ {
+7 -4
View File
@@ -1,11 +1,10 @@
SubDir HAIKU_TOP src tests system kernel cache ; SubDir HAIKU_TOP src tests system kernel cache ;
UsePrivateSystemHeaders ;
UsePrivateKernelHeaders ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src system kernel cache ] ; SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src system kernel cache ] ;
SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src system kernel util ] ; SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src system kernel util ] ;
UsePrivateHeaders kernel ;
UsePrivateHeaders [ FDirName kernel arch $(TARGET_ARCH) ] ;
UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ;
UseHeaders [ FDirName $(HAIKU_TOP) src system kernel cache ] ; UseHeaders [ FDirName $(HAIKU_TOP) src system kernel cache ] ;
StdBinCommands StdBinCommands
@@ -18,6 +17,10 @@ SimpleTest BlockMapTest :
khash.c khash.c
: libkernelland_emu.so ; : libkernelland_emu.so ;
SimpleTest block_cache_test :
block_cache_test.cpp
: libkernelland_emu.so ;
SimpleTest pages_io_test : SimpleTest pages_io_test :
pages_io_test.cpp pages_io_test.cpp
; ;
+13
View File
@@ -0,0 +1,13 @@
/*
* Copyright 2008, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License.
*/
#include "block_cache.cpp"
int
main(int argc, char** argv)
{
return 0;
}
+67 -18
View File
@@ -3,6 +3,7 @@
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
*/ */
#include <new> #include <new>
#include <stdlib.h> #include <stdlib.h>
@@ -73,7 +74,7 @@ struct cached_block {
bool is_writing : 1; bool is_writing : 1;
bool is_dirty : 1; bool is_dirty : 1;
bool unused : 1; bool unused : 1;
bool unmapped : 1; bool discard : 1;
cache_transaction *transaction; cache_transaction *transaction;
cache_transaction *previous_transaction; cache_transaction *previous_transaction;
@@ -106,6 +107,7 @@ struct block_cache {
fssh_status_t InitCheck(); fssh_status_t InitCheck();
void RemoveUnusedBlocks(int32_t maxAccessed = LONG_MAX, int32_t count = LONG_MAX); void RemoveUnusedBlocks(int32_t maxAccessed = LONG_MAX, int32_t count = LONG_MAX);
void RemoveBlock(cached_block* block);
void FreeBlock(cached_block *block); void FreeBlock(cached_block *block);
cached_block *NewBlock(fssh_off_t blockNumber); cached_block *NewBlock(fssh_off_t blockNumber);
void Free(void *address); void Free(void *address);
@@ -364,6 +366,7 @@ block_cache::NewBlock(fssh_off_t blockNumber)
block->parent_data = NULL; block->parent_data = NULL;
block->is_dirty = false; block->is_dirty = false;
block->unused = false; block->unused = false;
block->discard = false;
#ifdef DEBUG_CHANGED #ifdef DEBUG_CHANGED
block->compare = NULL; block->compare = NULL;
#endif #endif
@@ -374,14 +377,21 @@ block_cache::NewBlock(fssh_off_t blockNumber)
} }
void
block_cache::RemoveBlock(cached_block* block)
{
hash_remove(hash, block);
FreeBlock(block);
}
void void
block_cache::RemoveUnusedBlocks(int32_t maxAccessed, int32_t count) block_cache::RemoveUnusedBlocks(int32_t maxAccessed, int32_t count)
{ {
TRACE(("block_cache: remove up to %ld unused blocks\n", count)); TRACE(("block_cache: remove up to %ld unused blocks\n", count));
for (block_list::Iterator it = unused_blocks.GetIterator(); for (block_list::Iterator iterator = unused_blocks.GetIterator();
cached_block *block = it.Next();) { cached_block *block = iterator.Next();) {
if (maxAccessed < block->accessed) if (maxAccessed < block->accessed)
continue; continue;
@@ -393,10 +403,8 @@ block_cache::RemoveUnusedBlocks(int32_t maxAccessed, int32_t count)
write_cached_block(this, block, false); write_cached_block(this, block, false);
// remove block from lists // remove block from lists
it.Remove(); iterator.Remove();
hash_remove(hash, block); RemoveBlock(block);
FreeBlock(block);
if (--count <= 0) if (--count <= 0)
break; break;
@@ -426,11 +434,15 @@ put_cached_block(block_cache *cache, cached_block *block)
#endif #endif
if (--block->ref_count == 0 if (--block->ref_count == 0
&& block->transaction == NULL && block->transaction == NULL && block->previous_transaction == NULL) {
&& block->previous_transaction == NULL) { // This block is not used anymore, and not part of any transaction
// put this block in the list of unused blocks if (block->discard) {
block->unused = true; cache->RemoveBlock(block);
cache->unused_blocks.Add(block); } else {
// put this block in the list of unused blocks
block->unused = true;
cache->unused_blocks.Add(block);
}
} }
if (cache->allocated_block_count > kMaxBlockCount) { if (cache->allocated_block_count > kMaxBlockCount) {
@@ -539,6 +551,8 @@ get_writable_cached_block(block_cache *cache, fssh_off_t blockNumber, fssh_off_t
if (block == NULL) if (block == NULL)
return NULL; return NULL;
block->discard = false;
// if there is no transaction support, we just return the current block // if there is no transaction support, we just return the current block
if (transactionID == -1) { if (transactionID == -1) {
if (cleared) if (cleared)
@@ -1117,10 +1131,16 @@ fssh_cache_next_block_in_transaction(void *_cache, int32_t id, bool mainOnly,
else else
block = block->transaction_next; block = block->transaction_next;
if (mainOnly && transaction->has_sub_transaction) { if (transaction->has_sub_transaction) {
// find next block that the parent changed if (mainOnly) {
while (block != NULL && block->parent_data == NULL) // find next block that the parent changed
block = block->transaction_next; while (block != NULL && block->parent_data == NULL)
block = block->transaction_next;
} else {
// find next non-discarded block
while (block != NULL && block->discard)
block = block->transaction_next;
}
} }
if (block == NULL) if (block == NULL)
@@ -1282,6 +1302,7 @@ fssh_block_cache_sync_etc(void *_cache, fssh_off_t blockNumber,
&blockNumber); &blockNumber);
if (block == NULL) if (block == NULL)
continue; continue;
if (block->previous_transaction != NULL if (block->previous_transaction != NULL
|| (block->transaction == NULL && block->is_dirty)) { || (block->transaction == NULL && block->is_dirty)) {
fssh_status_t status = write_cached_block(cache, block); fssh_status_t status = write_cached_block(cache, block);
@@ -1294,8 +1315,36 @@ fssh_block_cache_sync_etc(void *_cache, fssh_off_t blockNumber,
} }
void
fssh_block_cache_discard(void* _cache, fssh_off_t blockNumber,
fssh_size_t numBlocks)
{
block_cache* cache = (block_cache*)_cache;
MutexLocker locker(&cache->lock);
for (; numBlocks > 0; numBlocks--, blockNumber++) {
cached_block* block = (cached_block*)hash_lookup(cache->hash,
&blockNumber);
if (block == NULL)
continue;
if (block->unused) {
cache->unused_blocks.Remove(block);
cache->RemoveBlock(block);
} else {
// mark them as discarded (in the current transaction only, if any)
if (block->previous_transaction != NULL)
write_cached_block(cache, block);
block->discard = true;
}
}
}
fssh_status_t fssh_status_t
fssh_block_cache_make_writable(void *_cache, fssh_off_t blockNumber, int32_t transaction) fssh_block_cache_make_writable(void *_cache, fssh_off_t blockNumber,
int32_t transaction)
{ {
block_cache *cache = (block_cache *)_cache; block_cache *cache = (block_cache *)_cache;
MutexLocker locker(&cache->lock); MutexLocker locker(&cache->lock);