ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

6.S081-2021 locks

2022-06-04 23:01:19  阅读:162  来源: 互联网

标签:index struct buf lock bucket locks 2021 bcache S081


buffer cache

原来的实现是一个双向链表,每次进行文件的读写操作都要锁住整个表,显然大大降低了系统的并发度。

所以可以仿照Java中currentHashMap的思路,使用分段锁,每个hash桶上一个锁。

但是在进行缓存驱逐的时候需要注意死锁的情况。

比如我们哈希值为2的缓存块不存在并且哈希值为5的缓冲块不存在。这时候CPU1会先获取桶2的锁然后遍历所有的桶,遍历到5的时候,因为桶5的锁被另外一个CPU2持有。而CPU2获取桶5的锁之后,同样需要遍历所有的桶查找,这时候桶2又被CPU1持有。形成循环等待,从而造成死锁。

#include "types.h"
#include "param.h"
#include "spinlock.h"
#include "sleeplock.h"
#include "riscv.h"
#include "defs.h"
#include "fs.h"
#include "buf.h"

#define NBUCKET 13

int hash(int no){
  return no%NBUCKET;
}

struct hashbuf{
  struct spinlock lock;
  struct buf head;
};

struct {
  struct spinlock lock;
  struct buf buf[NBUF];
  struct hashbuf bucket[NBUCKET];
  // Linked list of all buffers, through prev/next.
  // Sorted by how recently the buffer was used.
  // head.next is most recent, head.prev is least.
  //struct buf head;
} bcache;

void
binit(void)
{
  struct buf *b;

  initlock(&bcache.lock, "bcache");

  // 初始化散列桶的锁和头节点
  for(int i = 0; i<NBUCKET; i++){
    initlock(&bcache.bucket[i].lock,"bache");
    bcache.bucket[i].head.prev = &bcache.bucket[i].head;
    bcache.bucket[i].head.next = &bcache.bucket[i].head;
  }

  // 将所有的buf都先添加到0号桶
  for(b = bcache.buf; b < bcache.buf+NBUF; b++){
    b->next = bcache.bucket[0].head.next;
    b->prev = &bcache.bucket[0].head;
    initsleeplock(&b->lock, "buffer");
    bcache.bucket[0].head.next->prev = b;
    bcache.bucket[0].head.next = b;
  }
}

// Look through buffer cache for block on device dev.
// If not found, allocate a buffer.
// In either case, return locked buffer.
static struct buf*
bget(uint dev, uint blockno)
{
  struct buf *b;

  // acquire(&bcache.lock);
  int index = hash(blockno);
  acquire(&bcache.bucket[index].lock);
  
  // Is the block already cached?
  for(b = bcache.bucket[index].head.next; b != &bcache.bucket[index].head; b = b->next){
    if(b->dev == dev && b->blockno == blockno){
      b->refcnt++;
      b->timestamp = ticks;
      release(&bcache.bucket[index].lock);
      // release(&bcache.lock);
      acquiresleep(&b->lock);
      return b;
    }
  }
  
  release(&bcache.bucket[index].lock);
  
  uint oldestTime = __UINT32_MAX__;
  struct buf *item;
  int bucketId = -1;
  for(int i=index,loop=0;loop<NBUCKET;loop++){
    i=(index+loop)%NBUCKET;
    acquire(&bcache.bucket[i].lock);
    
    for(item = bcache.bucket[i].head.next; item != &bcache.bucket[i].head; item = item->next){
      if(item->refcnt == 0 && item->timestamp < oldestTime){
        oldestTime = item->timestamp;
        b = item;
        bucketId = i;
      }
    }

    release(&bcache.bucket[i].lock);
  }

  if(oldestTime!=__UINT32_MAX__){
  
    // 驱逐
    acquire(&bcache.bucket[bucketId].lock);
    b->next->prev = b->prev;
    b->prev->next = b->next;
    release(&bcache.bucket[bucketId].lock);

      

    acquire(&bcache.bucket[index].lock);
    b->next = bcache.bucket[index].head.next;
    b->prev = &bcache.bucket[index].head;
    bcache.bucket[index].head.next->prev = b;
    bcache.bucket[index].head.next = b;
    
    b->dev = dev;
    b->blockno = blockno;
    b->valid = 0;
    b->refcnt = 1;
    b->timestamp = ticks;
    release(&bcache.bucket[index].lock);
    acquiresleep(&b->lock);
    return b; 
  } 
  panic("bget: no buffers");
}

// Return a locked buf with the contents of the indicated block.
struct buf*
bread(uint dev, uint blockno)
{
  struct buf *b;

  b = bget(dev, blockno);
  if(!b->valid) {
    virtio_disk_rw(b, 0);
    b->valid = 1;
  }
  return b;
}

// Write b's contents to disk.  Must be locked.
void
bwrite(struct buf *b)
{
  if(!holdingsleep(&b->lock))
    panic("bwrite");
  virtio_disk_rw(b, 1);
}

// Release a locked buffer.
// Move to the head of the most-recently-used list.
void
brelse(struct buf *b)
{
  if(!holdingsleep(&b->lock))
    panic("brelse");

  releasesleep(&b->lock);

  int index = hash(b->blockno);
  acquire(&bcache.bucket[index].lock);
  b->refcnt--;
  b->timestamp = ticks;
  
  release(&bcache.bucket[index].lock);
}

void
bpin(struct buf *b) {
  int index = hash(b->blockno);
  acquire(&bcache.bucket[index].lock);
  b->refcnt++;
  release(&bcache.bucket[index].lock);
}

void
bunpin(struct buf *b) {
  int index = hash(b->blockno);
  acquire(&bcache.bucket[index].lock);
  b->refcnt--;
  release(&bcache.bucket[index].lock);
}

标签:index,struct,buf,lock,bucket,locks,2021,bcache,S081
来源: https://www.cnblogs.com/AD-milk/p/16336238.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有