Exemple #1
0
/*---------------------------------------------------------------------------*/
static coffee_page_t
next_file(coffee_page_t page, struct file_header *hdr)
{
  if(HDR_FREE(*hdr)) {
    return (page + COFFEE_PAGES_PER_SECTOR) & ~(COFFEE_PAGES_PER_SECTOR - 1);
  } else if(HDR_ISOLATED(*hdr)) {
    return page + 1;
  }
  return page + hdr->max_pages;    
}
Exemple #2
0
/*---------------------------------------------------------------------------*/
static coffee_page_t
next_file(coffee_page_t page, struct file_header *hdr)
{
  /*
   * The quick-skip algorithm for finding file extents is the most 
   * essential part of Coffee. The file allocation rules enables this 
   * algorithm to quickly jump over free areas and allocated extents 
   * after reading single headers and determining their status.
   *
   * The worst-case performance occurs when we encounter multiple long 
   * sequences of isolated pages, but such sequences are uncommon and 
   * always shorter than a sector.
   */
  if(HDR_FREE(*hdr)) {
    return (page + COFFEE_PAGES_PER_SECTOR) & ~(COFFEE_PAGES_PER_SECTOR - 1);
  } else if(HDR_ISOLATED(*hdr)) {
    return page + 1;
  }
  return page + hdr->max_pages;    
}
Exemple #3
0
/*---------------------------------------------------------------------------*/
static coffee_page_t
get_sector_status(uint16_t sector, struct sector_status *stats)
{
  static coffee_page_t skip_pages;
  static char last_pages_are_active;
  struct file_header hdr;
  coffee_page_t active, obsolete, free;
  coffee_page_t sector_start, sector_end;
  coffee_page_t page;

  memset(stats, 0, sizeof(*stats));
  active = obsolete = free = 0;

  /*
   * get_sector_status() is an iterative function using local static 
   * state. It therefore requires that the caller starts iterating from 
   * sector 0 in order to reset the internal state.
   */
  if(sector == 0) {
    skip_pages = 0;
    last_pages_are_active = 0;
  }

  sector_start = sector * COFFEE_PAGES_PER_SECTOR;
  sector_end = sector_start + COFFEE_PAGES_PER_SECTOR;

  /*
   * Account for pages belonging to a file starting in a previous 
   * segment that extends into this segment. If the whole segment is 
   * covered, we do not need to continue counting pages in this iteration.
   */
  if(last_pages_are_active) {
    if(skip_pages >= COFFEE_PAGES_PER_SECTOR) {
      stats->active = COFFEE_PAGES_PER_SECTOR;
      skip_pages -= COFFEE_PAGES_PER_SECTOR;
      return 0;
    }
    active = skip_pages;
  } else {
    if(skip_pages >= COFFEE_PAGES_PER_SECTOR) {
      stats->obsolete = COFFEE_PAGES_PER_SECTOR;
      skip_pages -= COFFEE_PAGES_PER_SECTOR;
      return skip_pages >= COFFEE_PAGES_PER_SECTOR ? 0 : skip_pages;
    }
    obsolete = skip_pages;
  }

  /* Determine the amount of pages of each type that have not been 
     accounted for yet in the current sector. */
  for(page = sector_start + skip_pages; page < sector_end;) {
    read_header(&hdr, page);
    last_pages_are_active = 0;
    if(HDR_ACTIVE(hdr)) {
      last_pages_are_active = 1;
      page += hdr.max_pages;
      active += hdr.max_pages;
    } else if(HDR_ISOLATED(hdr)) {
      page++;
      obsolete++;
    } else if(HDR_OBSOLETE(hdr)) {
      page += hdr.max_pages;
      obsolete += hdr.max_pages;
    } else {
      free = sector_end - page;
      break;
    }
  }

  /*
   * Determine the amount of pages in the following sectors that
   * should be remembered for the next iteration. This is necessary 
   * because no page except the first of a file contains information 
   * about what type of page it is. A side effect of remembering this
   * amount is that there is no need to read in the headers of each 
   * of these pages from the storage.
   */
  skip_pages = active + obsolete + free - COFFEE_PAGES_PER_SECTOR;
  if(skip_pages > 0) {
    if(last_pages_are_active) {
      active = COFFEE_PAGES_PER_SECTOR - obsolete;
    } else {
      obsolete = COFFEE_PAGES_PER_SECTOR - active;
    }
  }

  stats->active = active;
  stats->obsolete = obsolete;
  stats->free = free;

  /*
   * To avoid unnecessary page isolation, we notify the caller that 
   * "skip_pages" pages should be isolated only if the current file extent 
   * ends in the next sector. If the file extent ends in a more distant 
   * sector, however, the garbage collection can free the next sector 
   * immediately without requiring page isolation. 
   */
  return (last_pages_are_active || (skip_pages >= COFFEE_PAGES_PER_SECTOR)) ?
	0 : skip_pages;
}
Exemple #4
0
/*---------------------------------------------------------------------------*/
static coffee_page_t
get_sector_status(uint16_t sector, struct sector_status *stats)
{
  static coffee_page_t skip_pages;
  static char last_pages_are_active;
  struct file_header hdr;
  coffee_page_t active, obsolete, free;
  coffee_page_t sector_start, sector_end;
  coffee_page_t page;

  memset(stats, 0, sizeof(*stats));
  active = obsolete = free = 0;

  if(sector == 0) {
    skip_pages = 0;
    last_pages_are_active = 0;
  }

  sector_start = sector * COFFEE_PAGES_PER_SECTOR;
  sector_end = sector_start + COFFEE_PAGES_PER_SECTOR;

  if(last_pages_are_active) {
    if(skip_pages >= COFFEE_PAGES_PER_SECTOR) {
      stats->active = COFFEE_PAGES_PER_SECTOR;
      skip_pages -= COFFEE_PAGES_PER_SECTOR;
      return 0;
    }
    active = skip_pages;
  } else {
    if(skip_pages >= COFFEE_PAGES_PER_SECTOR) {
      stats->obsolete = COFFEE_PAGES_PER_SECTOR;
      skip_pages -= COFFEE_PAGES_PER_SECTOR;
      return skip_pages >= COFFEE_PAGES_PER_SECTOR ? 0 : skip_pages;
    }
    obsolete = skip_pages;
  }

  for(page = sector_start + skip_pages; page < sector_end;) {
    read_header(&hdr, page);
    last_pages_are_active = 0;
    if(HDR_ACTIVE(hdr)) {
      last_pages_are_active = 1;
      page += hdr.max_pages;
      active += hdr.max_pages;
    } else if(HDR_ISOLATED(hdr)) {
      page++;
      obsolete++;
    } else if(HDR_OBSOLETE(hdr)) {
      page += hdr.max_pages;
      obsolete += hdr.max_pages;
    } else {
      free = sector_end - page;
      break;
    }
  }

  skip_pages = active + obsolete + free - COFFEE_PAGES_PER_SECTOR;
  if(skip_pages > 0) {
    if(last_pages_are_active) {
      active = COFFEE_PAGES_PER_SECTOR - obsolete;
    } else {
      obsolete = COFFEE_PAGES_PER_SECTOR - active;
    }
  }

  stats->active = active;
  stats->obsolete = obsolete;
  stats->free = free;

  return (last_pages_are_active || (skip_pages >= COFFEE_PAGES_PER_SECTOR)) ?
	0 : skip_pages;
}