| 1 | /* |
|---|
| 2 | * (C) 2001 Clemson University and The University of Chicago |
|---|
| 3 | * |
|---|
| 4 | * See COPYING in top-level directory. |
|---|
| 5 | */ |
|---|
| 6 | |
|---|
| 7 | #include <stdio.h> |
|---|
| 8 | #include <stdlib.h> |
|---|
| 9 | #include <string.h> |
|---|
| 10 | #include <math.h> |
|---|
| 11 | #include <assert.h> |
|---|
| 12 | |
|---|
| 13 | #include "dist-dir-utils.h" |
|---|
| 14 | #include "md5.h" |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | /**************************** |
|---|
| 18 | * helper functions |
|---|
| 19 | * **************************/ |
|---|
| 20 | |
|---|
| 21 | /* calculate log2 of number */ |
|---|
| 22 | static double my_log2(const double n) |
|---|
| 23 | { |
|---|
| 24 | return log(n) / log(2.0); |
|---|
| 25 | } |
|---|
| 26 | |
|---|
| 27 | /* calculate branch_level for a server from a bitmap */ |
|---|
| 28 | static int dist_dir_calc_branch_level( |
|---|
| 29 | const PVFS_dist_dir_attr *dist_dir_attr, |
|---|
| 30 | const PVFS_dist_dir_bitmap bitmap) |
|---|
| 31 | { |
|---|
| 32 | int level = 0; |
|---|
| 33 | int server_no, num_servers; |
|---|
| 34 | |
|---|
| 35 | server_no = dist_dir_attr->server_no; |
|---|
| 36 | num_servers = dist_dir_attr->num_servers; |
|---|
| 37 | |
|---|
| 38 | /* meta handle copy (server_no = -1) shall not reach here */ |
|---|
| 39 | assert(server_no >= 0 && server_no < num_servers); |
|---|
| 40 | assert(bitmap != NULL); |
|---|
| 41 | |
|---|
| 42 | if(!(TST_BIT(bitmap, server_no))) |
|---|
| 43 | { |
|---|
| 44 | return -1; /* not an active server */ |
|---|
| 45 | } |
|---|
| 46 | |
|---|
| 47 | /* get the number of bits above which all bits are zero */ |
|---|
| 48 | while( server_no >> level ) |
|---|
| 49 | { |
|---|
| 50 | level++; |
|---|
| 51 | } |
|---|
| 52 | |
|---|
| 53 | /* until no splitting node is set */ |
|---|
| 54 | while( TST_BIT(bitmap, server_no + (1l << level)) ) |
|---|
| 55 | { |
|---|
| 56 | level++; |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | return level; |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | /***************************** |
|---|
| 63 | * main operation functions |
|---|
| 64 | * ***************************/ |
|---|
| 65 | |
|---|
| 66 | /* init dir state function, set all parameters |
|---|
| 67 | * server_no <- -1..(num_servers-1) |
|---|
| 68 | * pre_dsg_num_server: pre-set a number of servers, used for known large directory. default value can be 1. |
|---|
| 69 | */ |
|---|
| 70 | |
|---|
| 71 | int PINT_init_dist_dir_state( |
|---|
| 72 | PVFS_dist_dir_attr *dist_dir_attr, |
|---|
| 73 | PVFS_dist_dir_bitmap *bitmap_ptr, |
|---|
| 74 | const int num_servers, |
|---|
| 75 | const int server_no, |
|---|
| 76 | int pre_dsg_num_server) |
|---|
| 77 | { |
|---|
| 78 | int i; |
|---|
| 79 | |
|---|
| 80 | assert(dist_dir_attr != NULL); |
|---|
| 81 | |
|---|
| 82 | /* -1 <= server_no < num_servers && 0 < pre_dsg_num_server <= num_servers */ |
|---|
| 83 | assert( (num_servers > 0) && |
|---|
| 84 | (server_no >= -1) && /* metadata handle has server_no = -1 */ |
|---|
| 85 | (server_no < num_servers)); |
|---|
| 86 | |
|---|
| 87 | if ((pre_dsg_num_server <= 0) || |
|---|
| 88 | (pre_dsg_num_server > num_servers)) |
|---|
| 89 | { |
|---|
| 90 | pre_dsg_num_server = num_servers; |
|---|
| 91 | } |
|---|
| 92 | |
|---|
| 93 | dist_dir_attr->num_servers = num_servers; |
|---|
| 94 | dist_dir_attr->server_no = server_no; |
|---|
| 95 | /* tree_height start from 0 */ |
|---|
| 96 | dist_dir_attr->tree_height = (int)ceil(my_log2((double)num_servers)); |
|---|
| 97 | |
|---|
| 98 | /* increase bitmap_size if 2^tree_height > 32 |
|---|
| 99 | * bitmap has at least 2^tree_height bits, that is, the number of leaves of a full tree. */ |
|---|
| 100 | if( (1l << dist_dir_attr->tree_height) > |
|---|
| 101 | (sizeof(PVFS_dist_dir_bitmap_basetype) * 8)) |
|---|
| 102 | { |
|---|
| 103 | dist_dir_attr->bitmap_size = ((1l << dist_dir_attr->tree_height) >> 5); |
|---|
| 104 | } |
|---|
| 105 | else |
|---|
| 106 | { |
|---|
| 107 | dist_dir_attr->bitmap_size = 1; |
|---|
| 108 | } |
|---|
| 109 | |
|---|
| 110 | *bitmap_ptr = (PVFS_dist_dir_bitmap) malloc( |
|---|
| 111 | dist_dir_attr->bitmap_size * sizeof(PVFS_dist_dir_bitmap_basetype)); |
|---|
| 112 | if ((*bitmap_ptr) == NULL) |
|---|
| 113 | { |
|---|
| 114 | return -1; |
|---|
| 115 | } |
|---|
| 116 | |
|---|
| 117 | memset((*bitmap_ptr), 0, |
|---|
| 118 | dist_dir_attr->bitmap_size * sizeof(PVFS_dist_dir_bitmap_basetype)); |
|---|
| 119 | |
|---|
| 120 | for(i = pre_dsg_num_server-1; i >= 0; i--) |
|---|
| 121 | { |
|---|
| 122 | SET_BIT((*bitmap_ptr), i); |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | if(server_no > -1) /* an dirdata server */ |
|---|
| 126 | { |
|---|
| 127 | dist_dir_attr->branch_level = dist_dir_calc_branch_level(dist_dir_attr, *bitmap_ptr); |
|---|
| 128 | } |
|---|
| 129 | else /* a meta server */ |
|---|
| 130 | { |
|---|
| 131 | dist_dir_attr->branch_level = -1; |
|---|
| 132 | } |
|---|
| 133 | |
|---|
| 134 | /* set split size */ |
|---|
| 135 | dist_dir_attr->split_size = PVFS_DIST_DIR_MAX_ENTRIES; |
|---|
| 136 | return 0; |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | /* functions to test whether a dirdata server is active or not. |
|---|
| 140 | * will return 0 if server_no is out of bound or server is inactive. |
|---|
| 141 | */ |
|---|
| 142 | int PINT_is_dist_dir_bucket_active( |
|---|
| 143 | const PVFS_dist_dir_attr *dist_dir_attr_p, |
|---|
| 144 | const PVFS_dist_dir_bitmap bitmap, |
|---|
| 145 | const int server_no) |
|---|
| 146 | { |
|---|
| 147 | if((server_no < 0) || |
|---|
| 148 | (server_no >= dist_dir_attr_p->num_servers)) |
|---|
| 149 | { |
|---|
| 150 | return 0; |
|---|
| 151 | } |
|---|
| 152 | |
|---|
| 153 | if(TST_BIT(bitmap, server_no)) |
|---|
| 154 | { |
|---|
| 155 | return 1; |
|---|
| 156 | } |
|---|
| 157 | else |
|---|
| 158 | { |
|---|
| 159 | return 0; |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | } |
|---|
| 163 | |
|---|
| 164 | /* |
|---|
| 165 | * client uses this function to find the server that should hold |
|---|
| 166 | * a new dir entry, based on the current tree |
|---|
| 167 | * hash can be any value, whose rightmost several bits will be examined. |
|---|
| 168 | */ |
|---|
| 169 | int PINT_find_dist_dir_bucket( |
|---|
| 170 | const PVFS_dist_dir_hash_type hash, |
|---|
| 171 | const PVFS_dist_dir_attr *const dist_dir_attr, |
|---|
| 172 | const PVFS_dist_dir_bitmap bitmap) |
|---|
| 173 | { |
|---|
| 174 | PVFS_dist_dir_hash_type node_val; |
|---|
| 175 | int level; |
|---|
| 176 | |
|---|
| 177 | assert(dist_dir_attr != NULL); |
|---|
| 178 | assert(bitmap != NULL); |
|---|
| 179 | |
|---|
| 180 | level = dist_dir_attr->tree_height; |
|---|
| 181 | |
|---|
| 182 | if(level < 0) |
|---|
| 183 | { |
|---|
| 184 | return -1; |
|---|
| 185 | } |
|---|
| 186 | |
|---|
| 187 | for( node_val = hash & ((1l << level) - 1); /* use the rightmost 'tree_height' bits */ |
|---|
| 188 | (level >= 0) && !(TST_BIT(bitmap, node_val)); /* test if node_val bit is set */ |
|---|
| 189 | node_val &= ((1l << (--level)) - 1) ); /* if it's not, use less bits of the hash value */ |
|---|
| 190 | |
|---|
| 191 | return (int)node_val; /* assume tree_height < 32 */ |
|---|
| 192 | } |
|---|
| 193 | |
|---|
| 194 | |
|---|
| 195 | /* |
|---|
| 196 | * this code return the index of the new node when a bucket is to be split |
|---|
| 197 | */ |
|---|
| 198 | int PINT_find_dist_dir_split_node( |
|---|
| 199 | const PVFS_dist_dir_attr *const dist_dir_attr, |
|---|
| 200 | const PVFS_dist_dir_bitmap bitmap) |
|---|
| 201 | { |
|---|
| 202 | int new_node_val; |
|---|
| 203 | int branch_level; |
|---|
| 204 | |
|---|
| 205 | assert((dist_dir_attr != NULL) && |
|---|
| 206 | (dist_dir_attr->server_no > -1) && |
|---|
| 207 | (bitmap != NULL)); |
|---|
| 208 | |
|---|
| 209 | branch_level = dist_dir_attr->branch_level; |
|---|
| 210 | |
|---|
| 211 | /* meta server or inactive dirdata server should not come here */ |
|---|
| 212 | assert(branch_level > -1); |
|---|
| 213 | |
|---|
| 214 | /* if it reaches the maximum tree height */ |
|---|
| 215 | if (branch_level >= dist_dir_attr->tree_height) |
|---|
| 216 | { |
|---|
| 217 | return -1; |
|---|
| 218 | } |
|---|
| 219 | |
|---|
| 220 | /* calculate new node value */ |
|---|
| 221 | new_node_val = dist_dir_attr->server_no |
|---|
| 222 | + (1l << branch_level); |
|---|
| 223 | if(new_node_val >= dist_dir_attr->num_servers) |
|---|
| 224 | { |
|---|
| 225 | return -1; |
|---|
| 226 | } |
|---|
| 227 | |
|---|
| 228 | /* new node must be unset, otherwise branch_level is messed up */ |
|---|
| 229 | assert(!TST_BIT(bitmap, new_node_val)); |
|---|
| 230 | |
|---|
| 231 | return new_node_val; |
|---|
| 232 | } |
|---|
| 233 | |
|---|
| 234 | /* |
|---|
| 235 | * update current bitmap tree and re-calculate branch_level |
|---|
| 236 | */ |
|---|
| 237 | int PINT_update_dist_dir_bitmap_from_bitmap( |
|---|
| 238 | PVFS_dist_dir_attr *to_dir_attr, |
|---|
| 239 | PVFS_dist_dir_bitmap to_dir_bitmap, |
|---|
| 240 | const PVFS_dist_dir_attr *from_dir_attr, |
|---|
| 241 | const PVFS_dist_dir_bitmap from_dir_bitmap) |
|---|
| 242 | { |
|---|
| 243 | int i; |
|---|
| 244 | |
|---|
| 245 | assert((to_dir_attr != NULL) && (from_dir_attr != NULL)); |
|---|
| 246 | assert((to_dir_bitmap != NULL) && (from_dir_bitmap != NULL)); |
|---|
| 247 | |
|---|
| 248 | if( (to_dir_attr->num_servers != from_dir_attr->num_servers) || |
|---|
| 249 | (to_dir_attr->server_no == from_dir_attr->server_no)) |
|---|
| 250 | { |
|---|
| 251 | return -1; /* not in the same tree or update itself */ |
|---|
| 252 | } |
|---|
| 253 | |
|---|
| 254 | /* bitmap is with a type of (uint32_t *) |
|---|
| 255 | */ |
|---|
| 256 | for(i = to_dir_attr->bitmap_size - 1; |
|---|
| 257 | i >= 0; i--) |
|---|
| 258 | { |
|---|
| 259 | to_dir_bitmap[i] |= from_dir_bitmap[i]; |
|---|
| 260 | } |
|---|
| 261 | |
|---|
| 262 | /* update branch level */ |
|---|
| 263 | if(to_dir_attr->server_no > -1) /* dirdata server */ |
|---|
| 264 | { |
|---|
| 265 | to_dir_attr->branch_level = dist_dir_calc_branch_level(to_dir_attr, to_dir_bitmap); |
|---|
| 266 | } |
|---|
| 267 | |
|---|
| 268 | /* anything else to update? */ |
|---|
| 269 | |
|---|
| 270 | return 0; |
|---|
| 271 | } |
|---|
| 272 | |
|---|
| 273 | |
|---|
| 274 | /** a md5 encrypt function |
|---|
| 275 | * MD5 encryption returns a 128bit value, the hash value takes the last 64bit |
|---|
| 276 | * and save as an uint64_t |
|---|
| 277 | * |
|---|
| 278 | * ?? later, may add an option to be able to use other hash algorithm? |
|---|
| 279 | */ |
|---|
| 280 | PVFS_dist_dir_hash_type PINT_encrypt_dirdata(const char *const name) |
|---|
| 281 | { |
|---|
| 282 | PVFS_dist_dir_hash_type *hash_val; |
|---|
| 283 | md5_state_t state; |
|---|
| 284 | md5_byte_t digest[16]; |
|---|
| 285 | |
|---|
| 286 | md5_init(&state); |
|---|
| 287 | md5_append(&state, (const md5_byte_t *)name, strlen(name)); |
|---|
| 288 | md5_finish(&state, digest); |
|---|
| 289 | |
|---|
| 290 | hash_val = (PVFS_dist_dir_hash_type *)(digest + 8); |
|---|
| 291 | return *hash_val; |
|---|
| 292 | } |
|---|
| 293 | |
|---|
| 294 | |
|---|
| 295 | |
|---|
| 296 | /* set server_no field and update branch_level if necessary */ |
|---|
| 297 | int PINT_dist_dir_set_serverno(const int server_no, |
|---|
| 298 | PVFS_dist_dir_attr *ddattr, |
|---|
| 299 | PVFS_dist_dir_bitmap ddbitmap) |
|---|
| 300 | { |
|---|
| 301 | assert(ddattr != NULL && |
|---|
| 302 | ddbitmap != NULL && |
|---|
| 303 | server_no >= -1 && |
|---|
| 304 | server_no < ddattr->num_servers); |
|---|
| 305 | |
|---|
| 306 | ddattr->server_no = server_no; |
|---|
| 307 | |
|---|
| 308 | ddattr->branch_level = dist_dir_calc_branch_level(ddattr, ddbitmap); |
|---|
| 309 | |
|---|
| 310 | return 0; |
|---|
| 311 | } |
|---|
| 312 | |
|---|
| 313 | /* |
|---|
| 314 | * Local variables: |
|---|
| 315 | * c-indent-level: 4 |
|---|
| 316 | * c-basic-offset: 4 |
|---|
| 317 | * End: |
|---|
| 318 | * |
|---|
| 319 | * vim: ts=8 sts=4 sw=4 expandtab |
|---|
| 320 | */ |
|---|