Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/srv/fs/cdfs/cdfs_ops.c

    rbc216a0 rf73b291  
    3737 */
    3838
    39 #include "cdfs_ops.h"
    4039#include <bool.h>
    4140#include <adt/hash_table.h>
    42 #include <adt/hash.h>
    4341#include <malloc.h>
    4442#include <mem.h>
     
    4644#include <libfs.h>
    4745#include <errno.h>
    48 #include <libblock.h>
     46#include <block.h>
    4947#include <str.h>
    5048#include <byteorder.h>
     
    5250#include "cdfs.h"
    5351#include "cdfs_endian.h"
     52#include "cdfs_ops.h"
    5453
    5554/** Standard CD-ROM block size */
    5655#define BLOCK_SIZE  2048
    5756
    58 #define NODE_CACHE_SIZE 200
     57/** Implicit node cache size
     58 *
     59 * More nodes can be actually cached if the files remain
     60 * opended.
     61 *
     62 */
     63#define NODE_CACHE_SIZE  200
     64
     65#define NODES_BUCKETS  256
     66
     67#define NODES_KEY_SRVC   0
     68#define NODES_KEY_INDEX  1
    5969
    6070/** All root nodes have index 0 */
     
    195205        service_id_t service_id;  /**< Service ID of block device */
    196206       
    197         ht_link_t nh_link;        /**< Nodes hash table link */
     207        link_t nh_link;           /**< Nodes hash table link */
    198208        cdfs_dentry_type_t type;  /**< Dentry type */
    199209       
     
    216226static hash_table_t nodes;
    217227
    218 /*
    219  * Hash table support functions.
    220  */
    221 
    222 typedef struct {
    223         service_id_t service_id;
    224     fs_index_t index;
    225 } ht_key_t;
    226 
    227 static size_t nodes_key_hash(void *k)
    228 {
    229         ht_key_t *key = (ht_key_t*)k;
    230         return hash_combine(key->service_id, key->index);
    231 }
    232 
    233 static size_t nodes_hash(const ht_link_t *item)
    234 {
    235         cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link);
    236         return hash_combine(node->service_id, node->index);
    237 }
    238 
    239 static bool nodes_key_equal(void *k, const ht_link_t *item)
    240 {
    241         cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link);
    242         ht_key_t *key = (ht_key_t*)k;
    243        
    244         return key->service_id == node->service_id && key->index == node->index;
    245 }
    246 
    247 static void nodes_remove_callback(ht_link_t *item)
    248 {
    249         cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link);
     228static hash_index_t nodes_hash(unsigned long key[])
     229{
     230        return key[NODES_KEY_INDEX] % NODES_BUCKETS;
     231}
     232
     233static int nodes_compare(unsigned long key[], hash_count_t keys, link_t *item)
     234{
     235        cdfs_node_t *node =
     236            hash_table_get_instance(item, cdfs_node_t, nh_link);
     237       
     238        switch (keys) {
     239        case 1:
     240                return (node->service_id == key[NODES_KEY_SRVC]);
     241        case 2:
     242                return ((node->service_id == key[NODES_KEY_SRVC]) &&
     243                    (node->index == key[NODES_KEY_INDEX]));
     244        default:
     245                assert((keys == 1) || (keys == 2));
     246        }
     247       
     248        return 0;
     249}
     250
     251static void nodes_remove_callback(link_t *item)
     252{
     253        cdfs_node_t *node =
     254            hash_table_get_instance(item, cdfs_node_t, nh_link);
    250255       
    251256        assert(node->type == CDFS_DIRECTORY);
     
    263268
    264269/** Nodes hash table operations */
    265 static hash_table_ops_t nodes_ops = {
     270static hash_table_operations_t nodes_ops = {
    266271        .hash = nodes_hash,
    267         .key_hash = nodes_key_hash,
    268         .key_equal = nodes_key_equal,
    269         .equal = 0,
     272        .compare = nodes_compare,
    270273        .remove_callback = nodes_remove_callback
    271274};
     
    274277    fs_index_t index)
    275278{
    276         ht_key_t key = {
    277                 .index = index,
    278                 .service_id = service_id
     279        unsigned long key[] = {
     280                [NODES_KEY_SRVC] = service_id,
     281                [NODES_KEY_INDEX] = index
    279282        };
    280283       
    281         ht_link_t *link = hash_table_find(&nodes, &key);
     284        link_t *link = hash_table_find(&nodes, key);
    282285        if (link) {
    283286                cdfs_node_t *node =
    284                     hash_table_get_inst(link, cdfs_node_t, nh_link);
     287                    hash_table_get_instance(link, cdfs_node_t, nh_link);
    285288               
    286289                *rfn = FS_NODE(node);
     
    308311        node->opened = 0;
    309312       
     313        link_initialize(&node->nh_link);
    310314        list_initialize(&node->cs_list);
    311315}
     
    349353       
    350354        /* Insert the new node into the nodes hash table. */
    351         hash_table_insert(&nodes, &node->nh_link);
     355        unsigned long key[] = {
     356                [NODES_KEY_SRVC] = node->service_id,
     357                [NODES_KEY_INDEX] = node->index
     358        };
     359       
     360        hash_table_insert(&nodes, key, &node->nh_link);
    352361       
    353362        *rfn = FS_NODE(node);
     
    499508static fs_node_t *get_cached_node(service_id_t service_id, fs_index_t index)
    500509{
    501         ht_key_t key = {
    502                 .index = index,
    503                 .service_id = service_id
     510        unsigned long key[] = {
     511                [NODES_KEY_SRVC] = service_id,
     512                [NODES_KEY_INDEX] = index
    504513        };
    505514       
    506         ht_link_t *link = hash_table_find(&nodes, &key);
     515        link_t *link = hash_table_find(&nodes, key);
    507516        if (link) {
    508517                cdfs_node_t *node =
    509                     hash_table_get_inst(link, cdfs_node_t, nh_link);
     518                    hash_table_get_instance(link, cdfs_node_t, nh_link);
    510519                return FS_NODE(node);
    511520        }
     
    793802}
    794803
    795 static bool rm_service_id_nodes(ht_link_t *item, void *arg)
    796 {
    797         service_id_t service_id = *(service_id_t*)arg;
    798         cdfs_node_t *node = hash_table_get_inst(item, cdfs_node_t, nh_link);
    799        
    800         if (node->service_id == service_id) {
    801                 hash_table_remove_item(&nodes, &node->nh_link);
    802         }
    803        
    804         return true;
    805 }
    806 
    807804static void cdfs_instance_done(service_id_t service_id)
    808805{
    809         hash_table_apply(&nodes, rm_service_id_nodes, &service_id);
     806        unsigned long key[] = {
     807                [NODES_KEY_SRVC] = service_id
     808        };
     809       
     810        hash_table_remove(&nodes, key, 1);
    810811        block_cache_fini(service_id);
    811812        block_fini(service_id);
     
    821822    size_t *rbytes)
    822823{
    823         ht_key_t key = {
    824                 .index = index,
    825                 .service_id = service_id
     824        unsigned long key[] = {
     825                [NODES_KEY_SRVC] = service_id,
     826                [NODES_KEY_INDEX] = index
    826827        };
    827828       
    828         ht_link_t *link = hash_table_find(&nodes, &key);
     829        link_t *link = hash_table_find(&nodes, key);
    829830        if (link == NULL)
    830831                return ENOENT;
    831832       
    832833        cdfs_node_t *node =
    833             hash_table_get_inst(link, cdfs_node_t, nh_link);
     834            hash_table_get_instance(link, cdfs_node_t, nh_link);
    834835       
    835836        if (!node->processed) {
     
    911912}
    912913
    913 static bool cache_remove_closed(ht_link_t *item, void *arg)
    914 {
    915         size_t *premove_cnt = (size_t*)arg;
    916        
    917         /* Some nodes were requested to be removed from the cache. */
    918         if (0 < *premove_cnt) {
    919                 cdfs_node_t *node =     hash_table_get_inst(item, cdfs_node_t, nh_link);
    920 
    921                 if (!node->opened) {
    922                         hash_table_remove_item(&nodes, item);
    923                        
    924                         --nodes_cached;
    925                         --*premove_cnt;
     914static void cleanup_cache(service_id_t service_id)
     915{
     916        if (nodes_cached > NODE_CACHE_SIZE) {
     917                size_t remove = nodes_cached - NODE_CACHE_SIZE;
     918               
     919                // FIXME: this accesses the internals of the hash table
     920                //        and should be rewritten in a clean way
     921               
     922                for (hash_index_t chain = 0; chain < nodes.entries; chain++) {
     923                        for (link_t *link = nodes.entry[chain].head.next;
     924                            link != &nodes.entry[chain].head;
     925                            link = link->next) {
     926                                if (remove == 0)
     927                                        return;
     928                               
     929                                cdfs_node_t *node =
     930                                    hash_table_get_instance(link, cdfs_node_t, nh_link);
     931                                if (node->opened == 0) {
     932                                        link_t *tmp = link;
     933                                        link = link->prev;
     934                                       
     935                                        list_remove(tmp);
     936                                        nodes.op->remove_callback(tmp);
     937                                        nodes_cached--;
     938                                        remove--;
     939                                       
     940                                        continue;
     941                                }
     942                        }
    926943                }
    927         }
    928        
    929         /* Only continue if more nodes were requested to be removed. */
    930         return 0 < *premove_cnt;
    931 }
    932 
    933 static void cleanup_cache(service_id_t service_id)
    934 {
    935         if (nodes_cached > NODE_CACHE_SIZE) {
    936                 size_t remove_cnt = nodes_cached - NODE_CACHE_SIZE;
    937                
    938                 if (0 < remove_cnt)
    939                         hash_table_apply(&nodes, cache_remove_closed, &remove_cnt);
    940944        }
    941945}
     
    947951                return EOK;
    948952       
    949         ht_key_t key = {
    950                 .index = index,
    951                 .service_id = service_id
     953        unsigned long key[] = {
     954                [NODES_KEY_SRVC] = service_id,
     955                [NODES_KEY_INDEX] = index
    952956        };
    953957       
    954         ht_link_t *link = hash_table_find(&nodes, &key);
     958        link_t *link = hash_table_find(&nodes, key);
    955959        if (link == 0)
    956960                return ENOENT;
    957961       
    958962        cdfs_node_t *node =
    959             hash_table_get_inst(link, cdfs_node_t, nh_link);
     963            hash_table_get_instance(link, cdfs_node_t, nh_link);
    960964       
    961965        assert(node->opened > 0);
     
    10031007bool cdfs_init(void)
    10041008{
    1005         if (!hash_table_create(&nodes, 0, 0, &nodes_ops))
     1009        if (!hash_table_create(&nodes, NODES_BUCKETS, 2, &nodes_ops))
    10061010                return false;
    10071011       
Note: See TracChangeset for help on using the changeset viewer.