void
ssd_flush_current_swb(drv_ssd *ssd, uint64_t *p_prev_n_writes,
uint32_t *p_prev_size)
{
uint64_t n_writes = cf_atomic64_get(ssd->n_wblock_writes);
//ssd->n_wblock_writes表示ssd->swb_write_q队列中有多少个swb,该swb已写满脏数据
// 如果swb_write_q队列中有脏数据的swb,则需要将该swb先刷写完成,这里不能先刷写current_swb
if (n_writes != *p_prev_n_writes) {
*p_prev_n_writes = n_writes;
*p_prev_size = 0;
return;
}
//因为current_swb刷写时,其他线程可能正在向里面写入,所以需要加锁;
//swb_write_q中的swb不需要,因为已写满,其他的线程不能向里写了
pthread_mutex_lock(&ssd->write_lock);
n_writes = cf_atomic64_get(ssd->n_wblock_writes);
// 还需要在锁里面再检查一次。因为可能正好有一个swb放到了swb_write_q里了
if (n_writes != *p_prev_n_writes) {
pthread_mutex_unlock(&ssd->write_lock);
*p_prev_n_writes = n_writes;
*p_prev_size = 0;
return;
}
//如果current_swb不为空,那么可以刷。刷前需要将剩下的部分全部置成0清空
ssd_write_buf *swb = ssd->current_swb;
if (swb && swb->pos != *p_prev_size) {
*p_prev_size = swb->pos;
// Clean the end of the buffer before flushing.
if (ssd->write_block_size != swb->pos) {
memset(&swb->buf[swb->pos], 0, ssd->write_block_size - swb->pos);
}
//刷写到磁盘:swb->wblock_id*ssd->write_block_size为lseek的偏移,
//写入大小是ssd->write_block_size
ssd_flush_swb(ssd, swb);
}
pthread_mutex_unlock(&ssd->write_lock);
}
int
ssd_write_bins(as_storage_rd *rd)
{
...
//在ssd->write_lock锁内进行操作,向里写入脏数据
//如果current_swb为NULL,则从ssd->swb_free_q拿一个
pthread_mutex_lock(&ssd->write_lock);
ssd_write_buf *swb = ssd->current_swb;
if (! swb) {
swb = swb_get(ssd);
ssd->current_swb = swb;
}
//如果current_swb空间不够了:(将剩下的清0),将swb放到swb_write_q队列
//ssd->n_wblock_writes加一,表示队列里多了一个成员
//从swb_free_q中拿一个当做current_swb
if (write_size > ssd->write_block_size - swb->pos) {
if (ssd->write_block_size != swb->pos) {
// Clean the end of the buffer before pushing to write queue.
memset(&swb->buf[swb->pos], 0, ssd->write_block_size - swb->pos);
}
cf_queue_push(ssd->swb_write_q, &swb);
cf_atomic64_incr(&ssd->n_wblock_writes);
swb = swb_get(ssd);
ssd->current_swb = swb;
...
}
uint32_t swb_pos = swb->pos;
swb->pos += write_size;
cf_atomic32_incr(&swb->n_writers);
pthread_mutex_unlock(&ssd->write_lock);
...
//向swb写入
}
void *
run_ssd_maintenance(void *udata)
{
...
uint64_t prev_n_writes_flush = 0;
uint32_t prev_size_flush = 0;
while (true) {
...
ssd_flush_current_swb(ssd, &prev_n_writes_flush, &prev_size_flush);
...
}
}
结论:
该函数是刷写current_swb的后台线程。prev_n_writes_flush的入参是0,结合上面2个函数的介绍如果ssd_write_bins函数在写入时,current_swb满了,将他放到swb_write_q队列,那么这里current_swb就不能刷写了,需要等待ssd_write_worker后台线程将swb_write_q队列的脏数据刷写后再刷。从而保证数据一致性。