make sure that page isolation is called after erasing a sector in reluctant GC.

simplified the GC logic a bit.
This commit is contained in:
nvt-se 2009-04-29 13:15:59 +00:00
parent 3c68862599
commit 17fa2f1618

View file

@ -183,8 +183,9 @@ absolute_offset(coffee_page_t page, cfs_offset_t offset)
return page * COFFEE_PAGE_SIZE + sizeof(struct file_header) + offset; return page * COFFEE_PAGE_SIZE + sizeof(struct file_header) + offset;
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static coffee_page_t
get_sector_status(uint16_t sector, struct sector_stats *stats) { get_sector_status(uint16_t sector, struct sector_stats *stats)
{
static coffee_page_t skip_pages; static coffee_page_t skip_pages;
static char last_pages_are_active; static char last_pages_are_active;
struct file_header hdr; struct file_header hdr;
@ -197,36 +198,15 @@ get_sector_status(uint16_t sector, struct sector_stats *stats) {
if(sector == 0) { if(sector == 0) {
skip_pages = 0; skip_pages = 0;
last_pages_are_active = 0; last_pages_are_active = 0;
} else if(skip_pages > COFFEE_PAGES_PER_SECTOR) {
skip_pages -= COFFEE_PAGES_PER_SECTOR;
if(last_pages_are_active) {
stats->active = COFFEE_PAGES_PER_SECTOR;
stats->obsolete = 0;
} else {
stats->active = 0;
stats->obsolete = COFFEE_PAGES_PER_SECTOR;
}
stats->free = 0;
return;
} }
sector_start = sector * COFFEE_SECTOR_SIZE / COFFEE_PAGE_SIZE; sector_start = sector * COFFEE_PAGES_PER_SECTOR;
sector_end = sector_start + COFFEE_SECTOR_SIZE / COFFEE_PAGE_SIZE; sector_end = sector_start + COFFEE_PAGES_PER_SECTOR;
if(last_pages_are_active) { if(last_pages_are_active) {
active = skip_pages; active = skip_pages & (COFFEE_PAGES_PER_SECTOR - 1);
} else { } else {
obsolete = skip_pages; obsolete = skip_pages & (COFFEE_PAGES_PER_SECTOR - 1);
/* Split an obsolete file starting in the previous sector and mark
the following pages as isolated. */
memset(&hdr, 0, sizeof(hdr));
hdr.flags = HDR_FLAG_ALLOCATED | HDR_FLAG_ISOLATED;
for(page = 0; page < skip_pages; page++) {
write_header(&hdr, sector_start + page);
}
PRINTF("Coffee: Isolated %u pages starting in sector %d\n",
(unsigned)skip_pages, (int)sector);
} }
for(page = sector_start + skip_pages; page < sector_end;) { for(page = sector_start + skip_pages; page < sector_end;) {
@ -243,7 +223,7 @@ get_sector_status(uint16_t sector, struct sector_stats *stats) {
page += hdr.max_pages; page += hdr.max_pages;
obsolete += hdr.max_pages; obsolete += hdr.max_pages;
} else { } else {
free = COFFEE_PAGES_PER_SECTOR - active - obsolete; free = sector_end - page;
break; break;
} }
} }
@ -260,6 +240,28 @@ get_sector_status(uint16_t sector, struct sector_stats *stats) {
stats->active = active; stats->active = active;
stats->obsolete = obsolete; stats->obsolete = obsolete;
stats->free = free; stats->free = free;
return last_pages_are_active ? 0 : skip_pages;
}
/*---------------------------------------------------------------------------*/
static void
isolate_pages(coffee_page_t start, coffee_page_t skip_pages)
{
struct file_header hdr;
coffee_page_t page;
/* Split an obsolete file starting in the previous sector and mark
the following pages as isolated. */
memset(&hdr, 0, sizeof(hdr));
hdr.flags = HDR_FLAG_ALLOCATED | HDR_FLAG_ISOLATED;
/* Isolation starts from the next sector. */
for(page = 0; page < skip_pages; page++) {
write_header(&hdr, start + page);
}
PRINTF("Coffee: Isolated %u pages starting in sector %d\n",
(unsigned)skip_pages, (int)start / COFFEE_PAGES_PER_SECTOR);
} }
/*---------------------------------------------------------------------------*/ /*---------------------------------------------------------------------------*/
static void static void
@ -267,7 +269,7 @@ collect_garbage(int mode)
{ {
uint16_t sector; uint16_t sector;
struct sector_stats stats; struct sector_stats stats;
coffee_page_t first_page; coffee_page_t first_page, skip_pages;
watchdog_stop(); watchdog_stop();
@ -278,20 +280,28 @@ collect_garbage(int mode)
* erasable if there are only free or obsolete pages in it. * erasable if there are only free or obsolete pages in it.
*/ */
for(sector = 0; sector < COFFEE_SECTOR_COUNT; sector++) { for(sector = 0; sector < COFFEE_SECTOR_COUNT; sector++) {
get_sector_status(sector, &stats); skip_pages = get_sector_status(sector, &stats);
PRINTF("Coffee: Sector %u has %u active, %u free, and %u obsolete pages.\n", PRINTF("Coffee: Sector %u has %u active, %u free, and %u obsolete pages.\n",
sector, (unsigned)stats.active, (unsigned)stats.free, (unsigned)stats.obsolete); sector, (unsigned)stats.active, (unsigned)stats.free, (unsigned)stats.obsolete);
if(stats.active > 0) { if(stats.active > 0) {
continue; continue;
} }
if((mode == GC_RELUCTANT && stats.free == 0) || if((mode == GC_RELUCTANT && stats.free == 0) ||
(mode == GC_GREEDY && stats.obsolete > 0)) { (mode == GC_GREEDY && stats.obsolete > 0)) {
COFFEE_ERASE(sector);
PRINTF("Coffee: Erased sector %d!\n", sector);
first_page = sector * COFFEE_PAGES_PER_SECTOR; first_page = sector * COFFEE_PAGES_PER_SECTOR;
if(first_page < *next_free) { if(first_page < *next_free) {
*next_free = first_page; *next_free = first_page;
} }
if(skip_pages > 0) {
isolate_pages(first_page + COFFEE_PAGES_PER_SECTOR, skip_pages);
}
COFFEE_ERASE(sector);
PRINTF("Coffee: Erased sector %d!\n", sector);
if(mode == GC_RELUCTANT) { if(mode == GC_RELUCTANT) {
break; break;
} }