Skip to content

Read caching implementation

Akira Hayakawa edited this page Sep 4, 2016 · 5 revisions

Writeboost implements read-caching using write-caching.

The algorithm is:

  1. Only caches 4KB (full-sized) read requests
  2. Hold read data into the read-cache cells in the endio callback (read_cache_cell_copy_data). There are 2048 cells preallocated by default. reserve_read_cache_cell is called when the read request result in cache miss, will be read from the backing store, and the function reserves a new cell. In endio, the read data payload is copied to the cell.
  3. Once all cells are occupied writeboost injects the read data in the cells into the write-caching routine. (inject_read_cache) This is something like read-requests turn into writers. But the code path is simpler than the real write path because the data is assured to be 4KB (not partial) and there is no chance of overwriting the existing cache block because the cell data should have been cancelled if other thread in write-caching wrote the same address. (might_cancel_read_cache_cell)
struct read_cache_cell {
    sector_t sector;
    void *data; /* 4KB data read */
    bool cancelled; /* Don't include this */
    struct rb_node rb_node;
};

With the tunable parameter read_cache_threshold set, read-caching detects sequentiality within the 2048 cells and cancels the cells included in the sequentiality. read_cache_cell is maintained in the rb tree because taking the cells out of the tree is sorted in ascending order which helps detect sequentiality.

The struct dirtiness indicates the dirtiness of a cache block. is_dirty is set false if it's read-caching, otherwise true, and no need to write back. data_bits is the bit mask of valid sectors in the 4KB cache block. Therefore all read-cached blocks are set is_dirty=false and data_bits=255. This way, we can mix write-caching and read-caching in unified manner.

struct dirtiness {
    bool is_dirty;
    u8 data_bits;
};
Clone this wiki locally