class_hash.c

来自「lustre 1.6.5 source code」· C语言 代码 · 共 757 行 · 第 1/2 页

C
757
字号
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * *  Copyright (C) 2005 Cluster File Systems, Inc. *   Author: YuZhangyong <yzy@clusterfs.com> * *   This file is part of Lustre, http://www.lustre.org/ * *   No redistribution or use is permitted outside of Cluster File Systems, Inc. * *   Implement a hash class for hash process in lustre system. */#ifndef __KERNEL__#include <liblustre.h>#include <obd.h>#endif#include <obd_class.h>#include <class_hash.h>#include <lustre_export.h>#include <obd_support.h>#include <lustre_net.h>#include <lustre_quota.h>int lustre_hash_init(struct lustre_class_hash_body **hash_body_new,                     char *hashname, __u32 hashsize,                     struct lustre_hash_operations *hash_operations){        int i, n = 0;        struct lustre_class_hash_body *hash_body = NULL;        LASSERT(hashsize > 0);        LASSERT(hash_operations != NULL);        ENTRY;        i = hashsize;        while (i != 0) {                if (i & 0x1)                        n++;                i >>= 1;        }        LASSERTF(n == 1, "hashsize %u isn't 2^n\n", hashsize);        /* alloc space for hash_body */        OBD_ALLOC(hash_body, sizeof(*hash_body));        if (hash_body == NULL) {                CERROR("Cannot alloc space for hash body, hashname = %s \n",                        hashname);                RETURN(-ENOMEM);        }        LASSERT(hashname != NULL &&                strlen(hashname) <= sizeof(hash_body->hashname));        strcpy(hash_body->hashname, hashname);        hash_body->lchb_hash_max_size = hashsize;        hash_body->lchb_hash_operations = hash_operations;        /* alloc space for the hash tables */        OBD_ALLOC(hash_body->lchb_hash_tables,                  sizeof(*hash_body->lchb_hash_tables) * hash_body->lchb_hash_max_size);        if (hash_body->lchb_hash_tables == NULL) {                OBD_FREE(hash_body, sizeof(*hash_body));                CERROR("Cannot alloc space for hashtables, hashname = %s \n",                        hash_body->hashname);                RETURN(-ENOMEM);        }        spin_lock_init(&hash_body->lchb_lock); /* initialize the body lock */        for(i = 0 ; i < hash_body->lchb_hash_max_size; i++) {                /* initial the bucket lock and list_head */                INIT_HLIST_HEAD(&hash_body->lchb_hash_tables[i].lhb_head);                spin_lock_init(&hash_body->lchb_hash_tables[i].lhb_lock);        }        *hash_body_new = hash_body;        RETURN(0);}EXPORT_SYMBOL(lustre_hash_init);void lustre_hash_exit(struct lustre_class_hash_body **new_hash_body){        int i;        struct lustre_class_hash_body *hash_body = NULL;        ENTRY;        hash_body = *new_hash_body;        if (hash_body == NULL) {                CWARN("hash body has been deleted\n");                goto out_hash;        }        spin_lock(&hash_body->lchb_lock); /* lock the hash tables */        if (hash_body->lchb_hash_tables == NULL ) {                spin_unlock(&hash_body->lchb_lock);                CWARN("hash tables has been deleted\n");                goto out_hash;        }        for( i = 0; i < hash_body->lchb_hash_max_size; i++ ) {                struct lustre_hash_bucket * bucket;                struct hlist_node * actual_hnode, *pos;                bucket = &hash_body->lchb_hash_tables[i];                spin_lock(&bucket->lhb_lock); /* lock the bucket */                hlist_for_each_safe(actual_hnode, pos, &(bucket->lhb_head)) {                        lustre_hash_delitem_nolock(hash_body, i, actual_hnode);                }                spin_unlock(&bucket->lhb_lock);        }        /* free the hash_tables's memory space */        OBD_FREE(hash_body->lchb_hash_tables,                 sizeof(*hash_body->lchb_hash_tables) *                 hash_body->lchb_hash_max_size);        hash_body->lchb_hash_tables = NULL;        spin_unlock(&hash_body->lchb_lock);out_hash :         /* free the hash_body's memory space */        if (hash_body != NULL) {                OBD_FREE(hash_body, sizeof(*hash_body));                *new_hash_body = NULL;        }        EXIT;}EXPORT_SYMBOL(lustre_hash_exit);/* * only allow unique @key in hashtables, if the same @key has existed  * in hashtables, it will return with fails. */int lustre_hash_additem_unique(struct lustre_class_hash_body *hash_body,                                void *key, struct hlist_node *actual_hnode){        int hashent;        struct lustre_hash_bucket *bucket = NULL;        struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;        ENTRY;        LASSERT(hlist_unhashed(actual_hnode));        hashent = hop->lustre_hashfn(hash_body, key);        /* get the hash-bucket and lock it */        bucket = &hash_body->lchb_hash_tables[hashent];        spin_lock(&bucket->lhb_lock);        if ( (lustre_hash_getitem_in_bucket_nolock(hash_body, hashent, key)) != NULL) {                /* the added-item exist in hashtables, so cannot add it again */                spin_unlock(&bucket->lhb_lock);                CWARN("Already found the key in hash [%s]\n",                       hash_body->hashname);                RETURN(-EALREADY);        }        hlist_add_head(actual_hnode, &(bucket->lhb_head));#ifdef LUSTRE_HASH_DEBUG        /* hash distribute debug */        hash_body->lchb_hash_tables[hashent].lhb_item_count++;         CDEBUG(D_INFO, "hashname[%s] bucket[%d] has [%d] hashitem\n",                         hash_body->hashname, hashent,                         hash_body->lchb_hash_tables[hashent].lhb_item_count);#endif          hop->lustre_hash_object_refcount_get(actual_hnode);         spin_unlock(&bucket->lhb_lock);        RETURN(0);}EXPORT_SYMBOL(lustre_hash_additem_unique);/* * only allow unique @key in hashtables, if the same @key has existed  * in hashtables, it will return with fails. */void* lustre_hash_findadd_unique(struct lustre_class_hash_body *hash_body,                                      void *key, struct hlist_node *actual_hnode){        int hashent;        struct lustre_hash_bucket *bucket = NULL;        struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;        struct hlist_node * hash_item_hnode = NULL;        void *obj;        ENTRY;        LASSERT(hlist_unhashed(actual_hnode));        hashent = hop->lustre_hashfn(hash_body, key);        /* get the hash-bucket and lock it */        bucket = &hash_body->lchb_hash_tables[hashent];        spin_lock(&bucket->lhb_lock);        hash_item_hnode = lustre_hash_getitem_in_bucket_nolock(hash_body,                                                               hashent, key);        if ( hash_item_hnode != NULL) {                /* the added-item exist in hashtables, so cannot add it again */                obj = hop->lustre_hash_object_refcount_get(hash_item_hnode);                spin_unlock(&bucket->lhb_lock);                RETURN(obj);        }        hlist_add_head(actual_hnode, &(bucket->lhb_head));#ifdef LUSTRE_HASH_DEBUG        /* hash distribute debug */        hash_body->lchb_hash_tables[hashent].lhb_item_count++;         CDEBUG(D_INFO, "hashname[%s] bucket[%d] has [%d] hashitem\n",                         hash_body->hashname, hashent,                         hash_body->lchb_hash_tables[hashent].lhb_item_count);#endif        obj = hop->lustre_hash_object_refcount_get(actual_hnode);        spin_unlock(&bucket->lhb_lock);        RETURN(obj);}EXPORT_SYMBOL(lustre_hash_findadd_unique);/* * this version of additem, it allow multi same @key <key, value> in hashtables.  * in this additem version, we don't need to check if exist same @key in hash  * tables, we only add it to related hashbucket. * example: maybe same nid will be related to multi difference export */int lustre_hash_additem(struct lustre_class_hash_body *hash_body, void *key,                          struct hlist_node *actual_hnode){        int hashent;        struct lustre_hash_bucket *bucket = NULL;        struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;        ENTRY;        LASSERT(hlist_unhashed(actual_hnode));        hashent = hop->lustre_hashfn(hash_body, key);        /* get the hashbucket and lock it */        bucket = &hash_body->lchb_hash_tables[hashent];        spin_lock(&bucket->lhb_lock);        hlist_add_head(actual_hnode, &(bucket->lhb_head));#ifdef LUSTRE_HASH_DEBUG        /* hash distribute debug */        hash_body->lchb_hash_tables[hashent].lhb_item_count++;         CDEBUG(D_INFO, "hashname[%s] bucket[%d] has [%d] hashitem\n",                         hash_body->hashname, hashent,                         hash_body->lchb_hash_tables[hashent].lhb_item_count);#endif          hop->lustre_hash_object_refcount_get(actual_hnode);         spin_unlock(&bucket->lhb_lock);        RETURN(0);}EXPORT_SYMBOL(lustre_hash_additem);/* * this version of delitem will delete a hashitem with given @key,  * we need to search the <@key, @value> in hashbucket with @key,  * if match, the hashitem will be delete.  * we have a no-search version of delitem, it will directly delete a hashitem,  * doesn't need to search it in hashtables, so it is a O(1) delete. */int lustre_hash_delitem_by_key(struct lustre_class_hash_body *hash_body,                                void *key){        int hashent ;        struct hlist_node * hash_item;        struct lustre_hash_bucket *bucket = NULL;        struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;        int retval = 0;        ENTRY;        hashent = hop->lustre_hashfn(hash_body, key);        /* first, lock the hashbucket */        bucket = &hash_body->lchb_hash_tables[hashent];        spin_lock(&bucket->lhb_lock);        /* get the hash_item from hash_bucket */        hash_item = lustre_hash_getitem_in_bucket_nolock(hash_body, hashent,                                                          key);        if (hash_item == NULL) {                spin_unlock(&bucket->lhb_lock);                RETURN(-ENOENT);        }        /* call delitem_nolock() to delete the hash_item */        retval = lustre_hash_delitem_nolock(hash_body, hashent, hash_item);        spin_unlock(&bucket->lhb_lock);        RETURN(retval);}EXPORT_SYMBOL(lustre_hash_delitem_by_key);/* * the O(1) version of delete hash item,  * it will directly delete the hashitem with given @hash_item, * the parameter @key used to get the relation hash bucket and lock it. */int lustre_hash_delitem(struct lustre_class_hash_body *hash_body,                         void *key, struct hlist_node * hash_item){          int hashent = 0;        int retval = 0;        struct lustre_hash_bucket *bucket = NULL;        struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;        ENTRY;        hashent = hop->lustre_hashfn(hash_body, key);        bucket = &hash_body->lchb_hash_tables[hashent];        spin_lock(&bucket->lhb_lock);        /* call delitem_nolock() to delete the hash_item */        retval = lustre_hash_delitem_nolock(hash_body, hashent, hash_item);        spin_unlock(&bucket->lhb_lock);        RETURN(retval);}EXPORT_SYMBOL(lustre_hash_delitem);void lustre_hash_bucket_iterate(struct lustre_class_hash_body *hash_body,                                void *key, hash_item_iterate_cb func, void *data){        int hashent, find = 0;        struct lustre_hash_bucket *bucket = NULL;        struct hlist_node *hash_item_node = NULL;        struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;        struct obd_export *tmp = NULL;        ENTRY;        hashent = hop->lustre_hashfn(hash_body, key);        bucket = &hash_body->lchb_hash_tables[hashent];        spin_lock(&bucket->lhb_lock);        hlist_for_each(hash_item_node, &(bucket->lhb_head)) {                find = hop->lustre_hash_key_compare(key, hash_item_node);                if (find) {                        tmp = hop->lustre_hash_object_refcount_get(hash_item_node);                        func(tmp, data);                        hop->lustre_hash_object_refcount_put(hash_item_node);                }        }        spin_unlock(&bucket->lhb_lock);}EXPORT_SYMBOL(lustre_hash_bucket_iterate);void lustre_hash_iterate_all(struct lustre_class_hash_body *hash_body,                            hash_item_iterate_cb func, void *data){        int i;        struct lustre_hash_operations *hop = hash_body->lchb_hash_operations;        ENTRY;        for( i = 0; i < hash_body->lchb_hash_max_size; i++ ) {                struct lustre_hash_bucket * bucket;                struct hlist_node * actual_hnode, *pos;                void *obj;                bucket = &hash_body->lchb_hash_tables[i];#ifdef LUSTRE_HASH_DEBUG                CDEBUG(D_INFO, "idx %d - bucket %p\n", i, bucket);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?