| 895 | } |
| 896 | |
| 897 | int bcache_read(struct filemgr *file, bid_t bid, void *buf) |
| 898 | { |
| 899 | struct hash_elem *h; |
| 900 | struct bcache_item *item; |
| 901 | struct bcache_item query; |
| 902 | struct fnamedic_item *fname; |
| 903 | |
| 904 | // Note that we don't need to grab bcache_lock here as the block cache |
| 905 | // is already created and binded when the file is created or opened for |
| 906 | // the first time. |
| 907 | fname = file->bcache; |
| 908 | |
| 909 | if (fname) { |
| 910 | // file exists |
| 911 | // set query |
| 912 | query.bid = bid; |
| 913 | // Update the access timestamp. |
| 914 | struct timeval tp; |
| 915 | gettimeofday(&tp, NULL); // TODO: Need to implement a better way of |
| 916 | // getting the timestamp to avoid the overhead of |
| 917 | // gettimeofday() |
| 918 | atomic_store_uint64_t(&fname->access_timestamp, |
| 919 | (uint64_t) (tp.tv_sec * 1000000 + tp.tv_usec)); |
| 920 | |
| 921 | size_t shard_num = bid % fname->num_shards; |
| 922 | spin_lock(&fname->shards[shard_num].lock); |
| 923 | |
| 924 | // search shard hash table |
| 925 | h = hash_find(&fname->shards[shard_num].hashtable, &query.hash_elem); |
| 926 | if (h) { |
| 927 | // cache hit |
| 928 | item = _get_entry(h, struct bcache_item, hash_elem); |
| 929 | if (item->flag & BCACHE_FREE) { |
| 930 | spin_unlock(&fname->shards[shard_num].lock); |
| 931 | DBG("Warning: failed to read the buffer cache entry for a file '%s' " |
| 932 | "because the entry belongs to the free list!\n", |
| 933 | file->filename); |
| 934 | return 0; |
| 935 | } |
| 936 | |
| 937 | // move the item to the head of list if the block is clean |
| 938 | // (don't care if the block is dirty) |
| 939 | if (!(item->flag & BCACHE_DIRTY)) { |
| 940 | // TODO: Scanning the list would cause some overhead. We need to devise |
| 941 | // the better data structure to provide a fast lookup for the clean list. |
| 942 | list_remove(&fname->shards[shard_num].cleanlist, &item->list_elem); |
| 943 | list_push_front(&fname->shards[shard_num].cleanlist, &item->list_elem); |
| 944 | } |
| 945 | |
| 946 | memcpy(buf, item->addr, bcache_blocksize); |
| 947 | _bcache_set_score(item); |
| 948 | |
| 949 | spin_unlock(&fname->shards[shard_num].lock); |
| 950 | |
| 951 | return bcache_blocksize; |
| 952 | } else { |
| 953 | // cache miss |
| 954 | spin_unlock(&fname->shards[shard_num].lock); |