* 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:
parent
5ae0bbaad0
commit
5b812019b4
@ -33,70 +33,72 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
/* transactions */
|
||||
extern int32 cache_start_transaction(void *_cache);
|
||||
extern status_t cache_sync_transaction(void *_cache, int32 id);
|
||||
extern status_t cache_end_transaction(void *_cache, int32 id,
|
||||
extern int32 cache_start_transaction(void *cache);
|
||||
extern status_t cache_sync_transaction(void *cache, int32 id);
|
||||
extern status_t cache_end_transaction(void *cache, int32 id,
|
||||
transaction_notification_hook hook, void *data);
|
||||
extern status_t cache_abort_transaction(void *_cache, int32 id);
|
||||
extern int32 cache_detach_sub_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,
|
||||
transaction_notification_hook hook, void *data);
|
||||
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_add_transaction_listener(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_add_transaction_listener(void *cache, int32 id,
|
||||
int32 events, transaction_notification_hook hook,
|
||||
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);
|
||||
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,
|
||||
void **_data, void **_unchangedData);
|
||||
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_sub_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_sub_transaction(void *cache, int32 id);
|
||||
|
||||
/* 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,
|
||||
bool readOnly);
|
||||
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(void *cache);
|
||||
extern status_t block_cache_sync_etc(void *cache, off_t blockNumber,
|
||||
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);
|
||||
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);
|
||||
extern void *block_cache_get_writable(void *_cache, off_t blockNumber,
|
||||
extern void *block_cache_get_writable(void *cache, off_t blockNumber,
|
||||
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);
|
||||
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);
|
||||
extern const void *block_cache_get(void *_cache, off_t blockNumber);
|
||||
extern status_t block_cache_set_dirty(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,
|
||||
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 */
|
||||
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_enable(void *_cacheRef);
|
||||
extern bool file_cache_is_enabled(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_sync(void *_cache);
|
||||
extern void file_cache_delete(void *cacheRef);
|
||||
extern void file_cache_enable(void *cacheRef);
|
||||
extern bool file_cache_is_enabled(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_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);
|
||||
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);
|
||||
|
||||
/* file map */
|
||||
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_set_size(void *_map, 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_translate(void *_map, off_t offset, size_t size,
|
||||
extern void file_map_delete(void *map);
|
||||
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 status_t file_map_set_mode(void *map, uint32 mode);
|
||||
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);
|
||||
|
||||
/* entry cache */
|
||||
|
@ -820,6 +820,7 @@
|
||||
#define block_cache_create fssh_block_cache_create
|
||||
#define block_cache_sync fssh_block_cache_sync
|
||||
#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_get_writable_etc fssh_block_cache_get_writable_etc
|
||||
#define block_cache_get_writable fssh_block_cache_get_writable
|
||||
|
@ -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_etc(void *_cache,
|
||||
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,
|
||||
fssh_off_t blockNumber, int32_t transaction);
|
||||
extern void * fssh_block_cache_get_writable_etc(void *_cache,
|
||||
|
101
src/system/kernel/cache/block_cache.cpp
vendored
101
src/system/kernel/cache/block_cache.cpp
vendored
@ -74,6 +74,7 @@ struct cached_block {
|
||||
bool is_writing : 1;
|
||||
bool is_dirty : 1;
|
||||
bool unused : 1;
|
||||
bool discard : 1;
|
||||
cache_transaction *transaction;
|
||||
cache_transaction *previous_transaction;
|
||||
|
||||
@ -122,12 +123,13 @@ struct block_cache : DoublyLinkedListLinkImpl<block_cache> {
|
||||
|
||||
void RemoveUnusedBlocks(int32 maxAccessed = LONG_MAX,
|
||||
int32 count = LONG_MAX);
|
||||
void FreeBlock(cached_block *block);
|
||||
cached_block *NewBlock(off_t blockNumber);
|
||||
void Free(void *buffer);
|
||||
void *Allocate();
|
||||
void RemoveBlock(cached_block* block);
|
||||
void FreeBlock(cached_block* block);
|
||||
cached_block* NewBlock(off_t blockNumber);
|
||||
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:
|
||||
cached_block *_GetUnusedBlock();
|
||||
@ -909,6 +911,7 @@ block_cache::NewBlock(off_t blockNumber)
|
||||
block->parent_data = NULL;
|
||||
block->is_dirty = false;
|
||||
block->unused = false;
|
||||
block->discard = false;
|
||||
#if BLOCK_CACHE_DEBUG_CHANGED
|
||||
block->compare = NULL;
|
||||
#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
|
||||
block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
|
||||
{
|
||||
@ -932,14 +943,12 @@ block_cache::RemoveUnusedBlocks(int32 maxAccessed, int32 count)
|
||||
block->block_number, block->accessed));
|
||||
|
||||
// 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);
|
||||
|
||||
// remove block from lists
|
||||
iterator.Remove();
|
||||
hash_remove(hash, block);
|
||||
|
||||
FreeBlock(block);
|
||||
RemoveBlock(block);
|
||||
|
||||
if (--count <= 0)
|
||||
break;
|
||||
@ -1022,17 +1031,20 @@ put_cached_block(block_cache *cache, cached_block *block)
|
||||
}
|
||||
|
||||
if (--block->ref_count == 0
|
||||
&& block->transaction == NULL
|
||||
&& block->previous_transaction == NULL) {
|
||||
// put this block in the list of unused blocks
|
||||
block->unused = true;
|
||||
if (block->original_data != NULL || block->parent_data != NULL)
|
||||
panic("put_cached_block(): %p (%Ld): %p, %p\n", block, block->block_number, block->original_data, block->parent_data);
|
||||
cache->unused_blocks.Add(block);
|
||||
// block->current_data = cache->allocator->Release(block->current_data);
|
||||
&& block->transaction == NULL && block->previous_transaction == NULL) {
|
||||
// This block is not used anymore, and not part of any transaction
|
||||
if (block->discard) {
|
||||
cache->RemoveBlock(block);
|
||||
} else {
|
||||
// put this block in the list of unused blocks
|
||||
block->unused = true;
|
||||
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)
|
||||
|
||||
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,
|
||||
block->current_data, blockSize);
|
||||
if (bytesRead < blockSize) {
|
||||
hash_remove(cache->hash, block);
|
||||
cache->FreeBlock(block);
|
||||
cache->RemoveBlock(block);
|
||||
TB(Error(cache, blockNumber, "read failed", bytesRead));
|
||||
|
||||
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)
|
||||
return NULL;
|
||||
|
||||
block->discard = false;
|
||||
|
||||
// if there is no transaction support, we just return the current block
|
||||
if (transactionID == -1) {
|
||||
if (cleared)
|
||||
@ -1843,8 +1856,9 @@ cache_sync_transaction(void *_cache, int32 id)
|
||||
T(Action("sync", cache, transaction));
|
||||
while (transaction->num_blocks > 0) {
|
||||
// sort blocks to speed up writing them back
|
||||
// TODO: ideally, this should be handled by the I/O scheduler
|
||||
block_list::Iterator iterator = transaction->blocks.GetIterator();
|
||||
// TODO: this should be handled by the I/O scheduler
|
||||
block_list::Iterator iterator
|
||||
= transaction->blocks.GetIterator();
|
||||
uint32 maxCount = transaction->num_blocks;
|
||||
cached_block *buffer[16];
|
||||
cached_block **blocks = (cached_block **)malloc(maxCount
|
||||
@ -1984,6 +1998,7 @@ cache_abort_transaction(void *_cache, int32 id)
|
||||
|
||||
block->transaction_next = NULL;
|
||||
block->transaction = NULL;
|
||||
block->discard = false;
|
||||
}
|
||||
|
||||
hash_remove(cache->transaction_hash, transaction);
|
||||
@ -2251,10 +2266,16 @@ cache_next_block_in_transaction(void *_cache, int32 id, bool mainOnly,
|
||||
else
|
||||
block = block->transaction_next;
|
||||
|
||||
if (mainOnly && transaction->has_sub_transaction) {
|
||||
// find next block that the parent changed
|
||||
while (block != NULL && block->parent_data == NULL)
|
||||
block = block->transaction_next;
|
||||
if (transaction->has_sub_transaction) {
|
||||
if (mainOnly) {
|
||||
// find next block that the parent changed
|
||||
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)
|
||||
@ -2427,8 +2448,6 @@ block_cache_sync_etc(void *_cache, off_t blockNumber, size_t numBlocks)
|
||||
if (block == NULL)
|
||||
continue;
|
||||
|
||||
// TODO: sort blocks!
|
||||
|
||||
if (block->previous_transaction != NULL
|
||||
|| (block->transaction == NULL && block->is_dirty)) {
|
||||
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
|
||||
block_cache_make_writable(void *_cache, off_t blockNumber, int32 transaction)
|
||||
{
|
||||
|
11
src/tests/system/kernel/cache/Jamfile
vendored
11
src/tests/system/kernel/cache/Jamfile
vendored
@ -1,11 +1,10 @@
|
||||
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 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 ] ;
|
||||
|
||||
StdBinCommands
|
||||
@ -18,6 +17,10 @@ SimpleTest BlockMapTest :
|
||||
khash.c
|
||||
: libkernelland_emu.so ;
|
||||
|
||||
SimpleTest block_cache_test :
|
||||
block_cache_test.cpp
|
||||
: libkernelland_emu.so ;
|
||||
|
||||
SimpleTest pages_io_test :
|
||||
pages_io_test.cpp
|
||||
;
|
||||
|
13
src/tests/system/kernel/cache/block_cache_test.cpp
vendored
Normal file
13
src/tests/system/kernel/cache/block_cache_test.cpp
vendored
Normal 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;
|
||||
}
|
@ -3,6 +3,7 @@
|
||||
* Distributed under the terms of the MIT License.
|
||||
*/
|
||||
|
||||
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
|
||||
@ -73,7 +74,7 @@ struct cached_block {
|
||||
bool is_writing : 1;
|
||||
bool is_dirty : 1;
|
||||
bool unused : 1;
|
||||
bool unmapped : 1;
|
||||
bool discard : 1;
|
||||
cache_transaction *transaction;
|
||||
cache_transaction *previous_transaction;
|
||||
|
||||
@ -106,6 +107,7 @@ struct block_cache {
|
||||
fssh_status_t InitCheck();
|
||||
|
||||
void RemoveUnusedBlocks(int32_t maxAccessed = LONG_MAX, int32_t count = LONG_MAX);
|
||||
void RemoveBlock(cached_block* block);
|
||||
void FreeBlock(cached_block *block);
|
||||
cached_block *NewBlock(fssh_off_t blockNumber);
|
||||
void Free(void *address);
|
||||
@ -364,6 +366,7 @@ block_cache::NewBlock(fssh_off_t blockNumber)
|
||||
block->parent_data = NULL;
|
||||
block->is_dirty = false;
|
||||
block->unused = false;
|
||||
block->discard = false;
|
||||
#ifdef DEBUG_CHANGED
|
||||
block->compare = NULL;
|
||||
#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
|
||||
block_cache::RemoveUnusedBlocks(int32_t maxAccessed, int32_t count)
|
||||
{
|
||||
TRACE(("block_cache: remove up to %ld unused blocks\n", count));
|
||||
|
||||
for (block_list::Iterator it = unused_blocks.GetIterator();
|
||||
cached_block *block = it.Next();) {
|
||||
|
||||
for (block_list::Iterator iterator = unused_blocks.GetIterator();
|
||||
cached_block *block = iterator.Next();) {
|
||||
if (maxAccessed < block->accessed)
|
||||
continue;
|
||||
|
||||
@ -393,10 +403,8 @@ block_cache::RemoveUnusedBlocks(int32_t maxAccessed, int32_t count)
|
||||
write_cached_block(this, block, false);
|
||||
|
||||
// remove block from lists
|
||||
it.Remove();
|
||||
hash_remove(hash, block);
|
||||
|
||||
FreeBlock(block);
|
||||
iterator.Remove();
|
||||
RemoveBlock(block);
|
||||
|
||||
if (--count <= 0)
|
||||
break;
|
||||
@ -426,11 +434,15 @@ put_cached_block(block_cache *cache, cached_block *block)
|
||||
#endif
|
||||
|
||||
if (--block->ref_count == 0
|
||||
&& block->transaction == NULL
|
||||
&& block->previous_transaction == NULL) {
|
||||
// put this block in the list of unused blocks
|
||||
block->unused = true;
|
||||
cache->unused_blocks.Add(block);
|
||||
&& block->transaction == NULL && block->previous_transaction == NULL) {
|
||||
// This block is not used anymore, and not part of any transaction
|
||||
if (block->discard) {
|
||||
cache->RemoveBlock(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) {
|
||||
@ -539,6 +551,8 @@ get_writable_cached_block(block_cache *cache, fssh_off_t blockNumber, fssh_off_t
|
||||
if (block == NULL)
|
||||
return NULL;
|
||||
|
||||
block->discard = false;
|
||||
|
||||
// if there is no transaction support, we just return the current block
|
||||
if (transactionID == -1) {
|
||||
if (cleared)
|
||||
@ -1117,10 +1131,16 @@ fssh_cache_next_block_in_transaction(void *_cache, int32_t id, bool mainOnly,
|
||||
else
|
||||
block = block->transaction_next;
|
||||
|
||||
if (mainOnly && transaction->has_sub_transaction) {
|
||||
// find next block that the parent changed
|
||||
while (block != NULL && block->parent_data == NULL)
|
||||
block = block->transaction_next;
|
||||
if (transaction->has_sub_transaction) {
|
||||
if (mainOnly) {
|
||||
// find next block that the parent changed
|
||||
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)
|
||||
@ -1282,6 +1302,7 @@ fssh_block_cache_sync_etc(void *_cache, fssh_off_t blockNumber,
|
||||
&blockNumber);
|
||||
if (block == NULL)
|
||||
continue;
|
||||
|
||||
if (block->previous_transaction != NULL
|
||||
|| (block->transaction == NULL && block->is_dirty)) {
|
||||
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_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;
|
||||
MutexLocker locker(&cache->lock);
|
||||
|
Loading…
Reference in New Issue
Block a user