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 + -
显示快捷键?