root/branches/Orange-Branch/src/common/misc/pint-cached-config.c @ 8869

Revision 8869, 52.3 KB (checked in by mtmoore, 2 years ago)

compiler warning cleanup

Line 
1/*
2 * (C) 2001 Clemson University and The University of Chicago
3 *
4 * See COPYING in top-level directory.
5 */
6
7#include <errno.h>
8#include <string.h>
9#include <assert.h>
10#include <stdlib.h>
11#include <sys/time.h>
12#include <time.h>
13#include <sys/types.h>
14#include <unistd.h>
15
16#include "pvfs2-types.h"
17#include "pvfs2-attr.h"
18#include "pint-sysint-utils.h"
19#include "bmi.h"
20#include "trove.h"
21#include "server-config.h"
22#include "quickhash.h"
23#include "extent-utils.h"
24#include "pint-cached-config.h"
25#include "pvfs2-internal.h"
26
27/* really old linux distributions (jazz's RHEL 3) don't have this(!?) */
28#ifndef HOST_NAME_MAX
29#define HOST_NAME_MAX 64
30#endif
31
32struct handle_lookup_entry
33{
34    PVFS_handle_extent extent;
35    char* server_name;
36    PVFS_BMI_addr_t server_addr;
37};
38
39struct config_fs_cache_s
40{
41    struct qlist_head hash_link;
42    struct filesystem_configuration_s *fs;
43
44    /* index into fs->meta_handle_ranges obj (see server-config.h) */
45    PINT_llist *meta_server_cursor;
46
47    /* index into fs->data_handle_ranges obj (see server-config.h) */
48    PINT_llist *data_server_cursor;
49
50    /*
51      the following fields are used to cache arrays of unique physical
52      server addresses, of particular use to the mgmt interface
53    */
54    phys_server_desc_s* io_server_array;
55    int io_server_count;
56    phys_server_desc_s* meta_server_array;
57    int meta_server_count;
58    phys_server_desc_s* server_array;
59    int server_count;
60
61    struct handle_lookup_entry* handle_lookup_table;
62    int handle_lookup_table_size;
63};
64
65struct qhash_table *PINT_fsid_config_cache_table = NULL;
66
67/* these are based on code from src/server/request-scheduler.c */
68static int hash_fsid(
69    void *fsid, int table_size);
70static int hash_fsid_compare(
71    void *key, struct qlist_head *link);
72
73static int cache_server_array(PVFS_fs_id fsid);
74static int handle_lookup_entry_compare(const void *p1, const void *p2);
75static const struct handle_lookup_entry* find_handle_lookup_entry(
76    PVFS_handle handle, PVFS_fs_id fsid);
77static int load_handle_lookup_table(
78    struct config_fs_cache_s *cur_config_fs_cache);
79
80static int meta_randomized = 0;
81static int io_randomized = 0;
82
83/* PINT_cached_config_initialize()
84 *
85 * initializes the cached_config interface
86 *
87 * returns 0 on success, -errno on failure
88 */
89int PINT_cached_config_initialize(void)
90{
91    struct timeval tv;
92    unsigned int seed = 0;
93    char hostname[HOST_NAME_MAX];
94    int ret;
95    int i;
96    int hostnamelen;
97
98    if (!PINT_fsid_config_cache_table)
99    {
100        PINT_fsid_config_cache_table =
101            qhash_init(hash_fsid_compare,hash_fsid,11);
102    }
103
104    /* include time, pid, and hostname in random seed in order to help avoid
105     * collisions on object placement when many clients are launched
106     * concurrently
107     */
108    gettimeofday(&tv, NULL);
109    seed += tv.tv_sec;
110    seed += tv.tv_usec;
111
112    seed += getpid();
113
114    ret = gethostname(hostname, HOST_NAME_MAX);
115    if(ret == 0)
116    {
117        hostnamelen = strlen(hostname);
118        for(i=0; i<hostnamelen; i++)
119        {
120            seed += (hostname[hostnamelen - i - 1] + i*256);
121        }
122    }
123   
124    srand(seed);
125
126    return (PINT_fsid_config_cache_table ? 0 : -PVFS_ENOMEM);
127}
128
129/* PINT_cached_config_finalize()
130 *
131 * shuts down the cached_config interface and releases any resources
132 * associated with it.
133 *
134 * returns 0 on success, -errno on failure
135 */
136int PINT_cached_config_finalize(void)
137{
138    int i = 0;
139    struct qlist_head *hash_link = NULL;
140    struct config_fs_cache_s *cur_config_cache = NULL;
141
142    /* if we haven't been initialized yet, just return success */
143    if (!PINT_fsid_config_cache_table)
144    {
145        return 0;
146    }
147
148    /*
149      this is an exhaustive and slow iterate.  speed this up if
150      'finalize' is something that will be done frequently.
151    */
152    for (i = 0; i < PINT_fsid_config_cache_table->table_size; i++)
153    {
154        do
155        {
156            hash_link = qhash_search_and_remove_at_index(
157                PINT_fsid_config_cache_table, i);
158            if (hash_link)
159            {
160                cur_config_cache = qlist_entry(
161                    hash_link, struct config_fs_cache_s, hash_link);
162
163                assert(cur_config_cache);
164                assert(cur_config_cache->fs);
165
166                /* fs object is freed by PINT_config_release */
167                cur_config_cache->fs = NULL;
168                /* if the 'cached server arrays' are used, free them */
169                if (cur_config_cache->io_server_count &&
170                    cur_config_cache->io_server_array)
171                {
172                    free(cur_config_cache->io_server_array);
173                    cur_config_cache->io_server_array = NULL;
174                }
175
176                if (cur_config_cache->meta_server_count &&
177                    cur_config_cache->meta_server_array)
178                {
179                    free(cur_config_cache->meta_server_array);
180                    cur_config_cache->meta_server_array = NULL;
181                }
182
183                if (cur_config_cache->server_count &&
184                    cur_config_cache->server_array)
185                {
186                    free(cur_config_cache->server_array);
187                    cur_config_cache->server_array = NULL;
188                }
189
190                free(cur_config_cache->handle_lookup_table);
191
192                free(cur_config_cache);
193            }
194        } while(hash_link);
195    }
196    qhash_finalize(PINT_fsid_config_cache_table);
197    PINT_fsid_config_cache_table = NULL;
198
199    return 0;
200}
201
202int PINT_cached_config_reinitialize(
203    struct server_configuration_s *config)
204{
205    int ret = -PVFS_EINVAL;
206    PINT_llist *cur = NULL;
207    struct filesystem_configuration_s *cur_fs = NULL;
208
209    PINT_cached_config_finalize();
210
211    ret = PINT_cached_config_initialize();
212    if (ret == 0)
213    {
214        cur = config->file_systems;
215        while(cur)
216        {
217            cur_fs = PINT_llist_head(cur);
218            if (!cur_fs)
219            {
220                break;
221            }
222
223            ret = PINT_cached_config_handle_load_mapping(cur_fs);
224            if (ret)
225            {
226                break;
227            }
228            cur = PINT_llist_next(cur);
229        }
230    }
231    return 0;
232}
233
234/* PINT_cached_config_handle_load_mapping()
235 *
236 * loads a new mapping of servers to handle into this interface.  This
237 * function may be called multiple times in order to add new file
238 * system information at run time.
239 *
240 * returns 0 on success, -errno on failure
241 */
242int PINT_cached_config_handle_load_mapping(
243    struct filesystem_configuration_s *fs)
244{
245    struct config_fs_cache_s *cur_config_fs_cache = NULL;
246    int ret;
247
248    if (fs)
249    {
250        cur_config_fs_cache = (struct config_fs_cache_s *)
251            malloc(sizeof(struct config_fs_cache_s));
252        assert(cur_config_fs_cache);
253        memset(cur_config_fs_cache, 0, sizeof(struct config_fs_cache_s));
254
255        cur_config_fs_cache->fs = (struct filesystem_configuration_s *)fs;
256
257        cur_config_fs_cache->meta_server_cursor =
258            cur_config_fs_cache->fs->meta_handle_ranges;
259        cur_config_fs_cache->data_server_cursor =
260            cur_config_fs_cache->fs->data_handle_ranges;
261
262        /* populate table used to speed up mapping of handle values
263         * to servers
264         */
265        ret = load_handle_lookup_table(cur_config_fs_cache);
266        if(ret < 0)
267        {
268            free(cur_config_fs_cache);
269            gossip_err("Error: failed to load handle lookup table.\n");
270            return(ret);
271        }
272
273        qhash_add(PINT_fsid_config_cache_table,
274                  &(cur_config_fs_cache->fs->coll_id),
275                  &(cur_config_fs_cache->hash_link));
276    }
277
278    return 0;
279}
280
281static struct host_handle_mapping_s *
282PINT_cached_config_find_server(PINT_llist *handle_ranges, const char *addr)
283{
284    host_handle_mapping_s *cur_mapping;
285    PINT_llist *server_cursor = handle_ranges;
286
287    cur_mapping = PINT_llist_head(server_cursor);
288    while(cur_mapping &&
289          strcmp(cur_mapping->alias_mapping->bmi_address, addr))
290    {
291        server_cursor = PINT_llist_next(server_cursor);
292        cur_mapping = PINT_llist_head(server_cursor);
293    }
294    return cur_mapping;
295}
296
297/* PINT_cached_config_get_server()
298 *
299 * Find the extent array for a specified server.
300 * This array MUST NOT be freed by the caller, nor cached for
301 * later use.
302 *
303 * returns 0 on success, -errno on failure
304 */
305int PINT_cached_config_get_server(
306    PVFS_fs_id fsid,
307    const char* host,
308    PVFS_ds_type type,
309    PVFS_handle_extent_array *ext_array)
310{
311    struct host_handle_mapping_s *cur_mapping = NULL;
312    struct qlist_head *hash_link = NULL;
313    struct config_fs_cache_s *cur_config_cache = NULL;
314    PINT_llist* server_cursor;
315
316    if (!ext_array)
317    {
318        return(-PVFS_EINVAL);
319    }
320
321    if(type != PINT_SERVER_TYPE_META && type != PINT_SERVER_TYPE_IO)
322    {
323        return(-PVFS_EINVAL);
324    }
325
326    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
327    if (!hash_link)
328    {
329        return(-PVFS_EINVAL);
330    }
331
332    cur_config_cache = qlist_entry(
333       hash_link, struct config_fs_cache_s, hash_link);
334
335    assert(cur_config_cache);
336    assert(cur_config_cache->fs);
337
338    if(type == PINT_SERVER_TYPE_META)
339    {
340        server_cursor =
341            cur_config_cache->fs->meta_handle_ranges;
342    }
343    else
344    {
345        server_cursor =
346            cur_config_cache->fs->data_handle_ranges;
347    }
348
349    cur_mapping = PINT_cached_config_find_server(server_cursor, host);
350    /* didn't find the server */
351    if(!cur_mapping)
352    {
353        return(-PVFS_ENOENT);
354    }
355
356    ext_array->extent_count =
357        cur_mapping->handle_extent_array.extent_count;
358    ext_array->extent_array =
359        cur_mapping->handle_extent_array.extent_array;
360
361    return(0);
362}
363
364
365/* PINT_cached_config_get_next_meta()
366 *
367 * returns the bmi address of a random server that should be used to
368 * store a new piece of metadata.  This function is responsible for
369 * fairly distributing the metadata storage responsibility to all
370 * servers.
371 *
372 * in addition, a handle range is returned as an array of extents that
373 * match the meta handle range configured for the returned meta
374 * server.  This array MUST NOT be freed by the caller, nor cached for
375 * later use.
376 * NOTE: address resolution is skipped if meta_addr is set to NULL
377 *
378 * returns 0 on success, -errno on failure
379 */
380int PINT_cached_config_get_next_meta(
381    PVFS_fs_id fsid,
382    PVFS_BMI_addr_t *meta_addr,
383    PVFS_handle_extent_array *ext_array)
384{
385    int ret = -PVFS_EINVAL, jitter = 0, num_meta_servers = 0;
386    char *meta_server_bmi_str = NULL;
387    struct host_handle_mapping_s *cur_mapping = NULL;
388    struct qlist_head *hash_link = NULL;
389    struct config_fs_cache_s *cur_config_cache = NULL;
390
391    if (ext_array)
392    {
393        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
394        if (hash_link)
395        {
396            cur_config_cache = qlist_entry(
397                hash_link, struct config_fs_cache_s, hash_link);
398
399            assert(cur_config_cache);
400            assert(cur_config_cache->fs);
401            assert(cur_config_cache->meta_server_cursor);
402
403            num_meta_servers = PINT_llist_count(
404                cur_config_cache->fs->meta_handle_ranges);
405
406            /* pick random starting point, then round robin */
407            if(!meta_randomized)
408            {
409                jitter = (rand() % num_meta_servers);
410                meta_randomized = 1;
411            }
412            else
413            {
414                /* we let the jitter loop below increment the cursor by one */
415                jitter = 0;
416            }
417            while(jitter-- > -1)
418            {
419                cur_mapping = PINT_llist_head(
420                    cur_config_cache->meta_server_cursor);
421                if (!cur_mapping)
422                {
423                    cur_config_cache->meta_server_cursor =
424                        cur_config_cache->fs->meta_handle_ranges;
425                    cur_mapping = PINT_llist_head(
426                        cur_config_cache->meta_server_cursor);
427                    assert(cur_mapping);
428                }
429                cur_config_cache->meta_server_cursor = PINT_llist_next(
430                    cur_config_cache->meta_server_cursor);
431            }
432            meta_server_bmi_str = cur_mapping->alias_mapping->bmi_address;
433
434            ext_array->extent_count =
435                cur_mapping->handle_extent_array.extent_count;
436            ext_array->extent_array =
437                cur_mapping->handle_extent_array.extent_array;
438
439            if (meta_addr != NULL)
440            {
441                ret = BMI_addr_lookup(meta_addr,meta_server_bmi_str);
442            }
443            else
444            {
445                ret = 0;
446            }
447        }
448    }
449    return ret;
450}
451
452static int PINT_cached_config_get_extents(
453    PVFS_fs_id fsid,
454    PVFS_BMI_addr_t *addr,
455    PVFS_handle_extent_array *handle_extents)
456{
457    struct qhash_head *hash_link;
458    struct PINT_llist *server_list;
459    PVFS_BMI_addr_t tmp_addr;
460    struct config_fs_cache_s *cur_config_cache = NULL;
461    struct host_handle_mapping_s *cur_mapping = NULL;
462    int ret;
463
464    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
465    if(!hash_link)
466    {
467        gossip_err("Failed to find a file system matching fsid: %d\n", fsid);
468        return -PVFS_EINVAL;
469    }
470
471    cur_config_cache = qlist_entry(
472        hash_link, struct config_fs_cache_s, hash_link);
473
474    assert(cur_config_cache);
475    assert(cur_config_cache->fs);
476
477    server_list = cur_config_cache->fs->data_handle_ranges;
478
479    while(!PINT_llist_empty(server_list))
480    {
481        cur_mapping = PINT_llist_head(server_list);
482        assert(cur_mapping);
483        server_list = PINT_llist_next(server_list);
484
485        ret = BMI_addr_lookup(
486            &tmp_addr, cur_mapping->alias_mapping->bmi_address);
487        if(ret < 0)
488        {
489            return ret;
490        }
491
492        if(tmp_addr == *addr)
493        {
494            handle_extents->extent_count =
495                cur_mapping->handle_extent_array.extent_count;
496            handle_extents->extent_array =
497                cur_mapping->handle_extent_array.extent_array;
498
499            return 0;
500        }
501    }
502    return -PVFS_ENOENT;
503}
504
505int PINT_cached_config_map_servers(
506    PVFS_fs_id fsid,
507    int *inout_num_datafiles,
508    PVFS_sys_layout *layout,
509    PVFS_BMI_addr_t *addr_array,
510    PVFS_handle_extent_array *handle_extent_array)
511{
512    struct qhash_head *hash_link;
513    struct PINT_llist *server_list;
514    struct host_handle_mapping_s *cur_mapping = NULL;
515    struct config_fs_cache_s *cur_config_cache = NULL;
516    int num_io_servers, i, ret;
517    int start_index = -1;
518    int index;
519    int random_attempts;
520
521    assert(inout_num_datafiles);
522
523    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
524    if(!hash_link)
525    {
526        gossip_err("Failed to find a file system matching fsid: %d\n", fsid);
527        return -PVFS_EINVAL;
528    }
529
530    cur_config_cache = qlist_entry(
531        hash_link, struct config_fs_cache_s, hash_link);
532
533    assert(cur_config_cache);
534    assert(cur_config_cache->fs);
535
536    server_list = cur_config_cache->fs->data_handle_ranges;
537    num_io_servers = PINT_llist_count(server_list);
538
539    switch(layout->algorithm)
540    {
541        case PVFS_SYS_LAYOUT_LIST:
542
543            if(*inout_num_datafiles < layout->server_list.count)
544            {
545                gossip_err("The specified datafile layout is larger"
546                           " than the number of requested datafiles\n");
547                return -PVFS_EINVAL;
548            }
549
550            *inout_num_datafiles = layout->server_list.count;
551            for(i = 0; i < layout->server_list.count; ++i)
552            {
553                if(handle_extent_array)
554                {
555                    ret = PINT_cached_config_get_extents(
556                        fsid,
557                        &layout->server_list.servers[i],
558                        &handle_extent_array[i]);
559                    if(ret < 0)
560                    {
561                        gossip_err("The address specified in the datafile "
562                                   "layout is invalid\n");
563                        return ret;
564                    }
565                }
566
567                addr_array[i] = layout->server_list.servers[i];
568            }
569            break;
570
571        case PVFS_SYS_LAYOUT_NONE:
572            start_index = 0;
573            /* fall through */
574
575        case PVFS_SYS_LAYOUT_ROUND_ROBIN:
576
577            if(num_io_servers < *inout_num_datafiles)
578            {
579                *inout_num_datafiles = num_io_servers;
580            }
581
582            if(start_index == -1)
583            {
584                start_index = rand() % *inout_num_datafiles;
585            }
586
587            for(i = 0; i < *inout_num_datafiles; ++i)
588            {
589                cur_mapping = PINT_llist_head(server_list);
590                assert(cur_mapping);
591                server_list = PINT_llist_next(server_list);
592
593                index = (i + start_index) % *inout_num_datafiles;
594                ret = BMI_addr_lookup(
595                    &addr_array[index],
596                    cur_mapping->alias_mapping->bmi_address);
597                if (ret)
598                {
599                    return ret;
600                }
601
602                if(handle_extent_array)
603                {
604                    handle_extent_array[index].extent_count =
605                        cur_mapping->handle_extent_array.extent_count;
606                    handle_extent_array[index].extent_array =
607                        cur_mapping->handle_extent_array.extent_array;
608                }
609            }
610            break;
611
612        case PVFS_SYS_LAYOUT_RANDOM:
613            /* this layout randomizes the order but still uses each server
614             * only once
615             */
616
617            /* limit this layout to a number of datafiles no greater than
618             * the number of servers
619             */
620            if(num_io_servers < *inout_num_datafiles)
621            {
622                *inout_num_datafiles = num_io_servers;
623            }
624
625            /* init all the addrs to 0, so we know whether we've set an
626             * address at a particular index or not
627             */
628            memset(addr_array, 0, (*inout_num_datafiles)*sizeof(*addr_array));
629
630            for(i = 0; i < *inout_num_datafiles; ++i)
631            {
632                /* go through server list in order */
633                cur_mapping = PINT_llist_head(server_list);
634                assert(cur_mapping);
635                server_list = PINT_llist_next(server_list);
636
637                /* select random index into caller's list */
638                index = rand() % *inout_num_datafiles;
639                random_attempts = 1;
640
641                /* if we have already filled that index, try another random
642                 * index
643                 */
644                while(addr_array[index] != 0 && random_attempts < 6)
645                {
646                    index = rand() % *inout_num_datafiles;
647                    random_attempts++;
648                }
649
650                /* if we exhausted a max number of randomization attempts,
651                 * then just go linearly through list
652                 */
653                while(addr_array[index] != 0)
654                {
655                    index = (index + 1) % *inout_num_datafiles;
656                }
657
658                /* found an unused index */
659                ret = BMI_addr_lookup(
660                    &addr_array[index],
661                    cur_mapping->alias_mapping->bmi_address);
662                if (ret)
663                {
664                    return ret;
665                }
666
667                if(handle_extent_array)
668                {
669                    handle_extent_array[index].extent_count =
670                        cur_mapping->handle_extent_array.extent_count;
671                    handle_extent_array[index].extent_array =
672                        cur_mapping->handle_extent_array.extent_array;
673                }
674            }
675            break;
676        default:
677            gossip_err("Unknown datafile mapping algorithm\n");
678            return -PVFS_EINVAL;
679    }
680    return 0;
681}
682
683/* PINT_cached_config_get_next_io()
684 *
685 * returns the address of a set of servers that should be used to
686 * store new pieces of file data.  This function is responsible for
687 * evenly distributing the file data storage load to all servers.
688 *
689 * NOTE: if io_addr_array is NULL, then don't resolve addresses
690 *
691 * returns 0 on success, -errno on failure
692 */
693int PINT_cached_config_get_next_io(
694    PVFS_fs_id fsid,
695    int num_servers,
696    PVFS_BMI_addr_t *io_addr_array,
697    PVFS_handle_extent_array *io_handle_extent_array)
698{
699    int ret = -PVFS_EINVAL, i = 0;
700    char *data_server_bmi_str = (char *)0;
701    struct host_handle_mapping_s *cur_mapping = NULL;
702    struct qlist_head *hash_link = NULL;
703    struct config_fs_cache_s *cur_config_cache = NULL;
704    int jitter = 0, num_io_servers = 0;
705    PINT_llist* old_data_server_cursor = NULL;
706
707    if (num_servers && io_handle_extent_array)
708    {
709        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
710        if (hash_link)
711        {
712            cur_config_cache = qlist_entry(
713                hash_link, struct config_fs_cache_s, hash_link);
714
715            assert(cur_config_cache);
716            assert(cur_config_cache->fs);
717
718            num_io_servers = PINT_llist_count(
719                cur_config_cache->fs->data_handle_ranges);
720
721
722            /* pick random starting point, then round robin */
723            if(!io_randomized)
724            {
725                jitter = (rand() % num_io_servers);
726                io_randomized = 1;
727            }
728            else
729            {
730                jitter = 0;
731            }
732            while(jitter-- > -1)
733            {
734                cur_mapping = PINT_llist_head(
735                    cur_config_cache->data_server_cursor);
736                if (!cur_mapping)
737                {
738                    cur_config_cache->data_server_cursor =
739                        cur_config_cache->fs->data_handle_ranges;
740                    cur_mapping = PINT_llist_head(
741                        cur_config_cache->data_server_cursor);
742                    assert(cur_mapping);
743                }
744                cur_config_cache->data_server_cursor = PINT_llist_next(
745                    cur_config_cache->data_server_cursor);
746            }
747            old_data_server_cursor = cur_config_cache->data_server_cursor;
748
749            while(num_servers)
750            {
751                assert(cur_config_cache->data_server_cursor);
752
753                cur_mapping = PINT_llist_head(
754                    cur_config_cache->data_server_cursor);
755                if (!cur_mapping)
756                {
757                    cur_config_cache->data_server_cursor =
758                        cur_config_cache->fs->data_handle_ranges;
759                    continue;
760                }
761                cur_config_cache->data_server_cursor = PINT_llist_next(
762                    cur_config_cache->data_server_cursor);
763
764                data_server_bmi_str = cur_mapping->alias_mapping->bmi_address;
765
766                if (io_addr_array != NULL)
767                {
768                    ret = BMI_addr_lookup(
769                        io_addr_array,data_server_bmi_str);
770                    if (ret)
771                    {
772                        break;
773                    }
774                }
775
776                io_handle_extent_array[i].extent_count =
777                    cur_mapping->handle_extent_array.extent_count;
778                io_handle_extent_array[i].extent_array =
779                    cur_mapping->handle_extent_array.extent_array;
780
781                i++;
782                num_servers--;
783                if(io_addr_array != NULL)
784                    io_addr_array++;
785            }
786            ret = ((num_servers == 0) ? 0 : ret);
787            /* reset data server cursor to point to the old cursor; the
788             * jitter on the next iteration will increment it by one
789             */
790            cur_config_cache->data_server_cursor = old_data_server_cursor;
791        }
792    }
793    return ret;
794}
795
796/* PINT_cached_config_map_addr()
797 *
798 * takes an opaque server address and returns the server type and
799 * address string for that server
800 *
801 * returns pointer to string on success, NULL on failure
802 */
803const char *PINT_cached_config_map_addr(
804    PVFS_fs_id fsid,
805    PVFS_BMI_addr_t addr,
806    int *server_type)
807{
808    int ret = -PVFS_EINVAL, i = 0;
809    struct qlist_head *hash_link = NULL;
810    struct config_fs_cache_s *cur_config_cache = NULL;
811
812    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
813    if (!hash_link)
814    {
815        return NULL;
816    }
817    cur_config_cache = qlist_entry(
818        hash_link, struct config_fs_cache_s, hash_link);
819    assert(cur_config_cache);
820    assert(cur_config_cache->fs);
821
822    ret = cache_server_array(fsid);
823    if (ret < 0)
824    {
825        return NULL;
826    }
827
828    /* run through general server list for a match */
829    for(i = 0; i < cur_config_cache->server_count; i++)
830    {
831        if (cur_config_cache->server_array[i].addr == addr)
832        {
833            if(server_type)
834            {
835                *server_type = cur_config_cache->server_array[i].server_type;
836            }
837            return (cur_config_cache->server_array[i].addr_string);
838        }
839    }
840    return NULL;
841}
842
843
844/* PINT_cached_config_check_type()
845 *
846 * Retrieves the server type flags for a specified BMI addr string
847 *
848 * returns 0 on success, -errno on failure
849 */
850int PINT_cached_config_check_type(
851    PVFS_fs_id fsid,
852    const char *server_addr_str,
853    int* server_type)
854{
855    int ret = -PVFS_EINVAL, i = 0;
856    struct qlist_head *hash_link = NULL;
857    struct config_fs_cache_s *cur_config_cache = NULL;
858
859    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
860    if (!hash_link)
861    {
862        return(-PVFS_EINVAL);
863    }
864    cur_config_cache = qlist_entry(
865        hash_link, struct config_fs_cache_s, hash_link);
866    assert(cur_config_cache);
867    assert(cur_config_cache->fs);
868
869    ret = cache_server_array(fsid);
870    if (ret < 0)
871    {
872        return(ret);
873    }
874
875    /* run through general server list for a match */
876    for(i = 0; i < cur_config_cache->server_count; i++)
877    {
878        if (!(strcmp(cur_config_cache->server_array[i].addr_string,
879           server_addr_str)))
880        {
881            *server_type = cur_config_cache->server_array[i].server_type;
882            return(0);
883        }
884    }
885    return(-PVFS_EINVAL);
886}
887
888
889/* PINT_cached_config_count_servers()
890 *
891 * counts the number of physical servers of the specified type
892 *
893 * returns 0 on success, -errno on failure
894 */
895int PINT_cached_config_count_servers(
896    PVFS_fs_id fsid,
897    int server_type,
898    int *count)
899{
900    int ret = -PVFS_EINVAL;
901    struct qlist_head *hash_link = NULL;
902    struct config_fs_cache_s *cur_config_cache = NULL;
903
904    if (!server_type)
905    {
906        return ret;
907    }
908
909    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
910    if (!hash_link)
911    {
912        return ret;
913    }
914    cur_config_cache = qlist_entry(
915        hash_link, struct config_fs_cache_s, hash_link);
916
917    assert(cur_config_cache);
918    assert(cur_config_cache->fs);
919
920    ret = cache_server_array(fsid);
921    if (ret == 0)
922    {
923        if (server_type == PINT_SERVER_TYPE_META)
924        {
925            *count = cur_config_cache->meta_server_count;
926            ret = 0;
927        }
928        else if (server_type == PINT_SERVER_TYPE_IO)
929        {
930            *count = cur_config_cache->io_server_count;
931            ret = 0;
932        }
933        else if (server_type == PINT_SERVER_TYPE_ALL)
934        {
935            *count = cur_config_cache->server_count;
936            ret = 0;
937        }
938    }
939    return ret;
940}
941
942/* PINT_cached_config_get_server_array()
943 *
944 * fills in an array of addresses corresponding to each server of the
945 * type specified by "server_type" (meta,io,or both).  If
946 * inout_count_p is not large enough to accomodate array, then an
947 * error is returned.
948 *
949 * returns 0 on success, -errno on failure
950 */
951int PINT_cached_config_get_server_array(
952    PVFS_fs_id fsid,
953    int server_type,
954    PVFS_BMI_addr_t *addr_array,
955    int *inout_count_p)
956{
957    int ret = -PVFS_EINVAL, i = 0;
958    struct qlist_head *hash_link = NULL;
959    struct config_fs_cache_s *cur_config_cache = NULL;
960
961    if (!inout_count_p || !*inout_count_p ||
962        !addr_array || !server_type)
963    {
964        return ret;
965    }
966
967    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
968    if (!hash_link)
969    {
970        return ret;
971    }
972    cur_config_cache = qlist_entry(
973        hash_link, struct config_fs_cache_s, hash_link);
974
975    assert(cur_config_cache);
976    assert(cur_config_cache->fs);
977
978    ret = cache_server_array(fsid);
979    if (ret < 0)
980    {
981        return ret;
982    }
983
984    /* at this point, we should have the data that we need cached up,
985     * just copy out
986     */
987    if (server_type == PINT_SERVER_TYPE_META)
988    {
989        if (*inout_count_p < cur_config_cache->meta_server_count)
990        {
991            return -PVFS_EMSGSIZE;
992        }
993
994        for(i = 0; i < cur_config_cache->meta_server_count; i++)
995        {
996            addr_array[i] = cur_config_cache->meta_server_array[i].addr;
997        }
998
999        *inout_count_p = cur_config_cache->meta_server_count;
1000        return 0;
1001    }
1002    else if (server_type == PINT_SERVER_TYPE_IO)
1003    {
1004        if (*inout_count_p < cur_config_cache->io_server_count)
1005        {
1006            return -PVFS_EMSGSIZE;
1007        }
1008
1009        for(i = 0; i < cur_config_cache->io_server_count; i++)
1010        {
1011            addr_array[i] = cur_config_cache->io_server_array[i].addr;
1012        }
1013
1014        *inout_count_p = cur_config_cache->io_server_count;
1015        return 0;
1016    }
1017    else if (server_type == PINT_SERVER_TYPE_ALL)
1018    {
1019        if (*inout_count_p < cur_config_cache->server_count)
1020        {
1021            return -PVFS_EMSGSIZE;
1022        }
1023
1024        for(i = 0; i < cur_config_cache->server_count; i++)
1025        {
1026            addr_array[i] =
1027                cur_config_cache->server_array[i].addr;
1028        }
1029
1030        *inout_count_p = cur_config_cache->server_count;
1031        return 0;
1032    }
1033    return ret;
1034}
1035
1036/* PINT_cached_config_map_to_server()
1037 *
1038 * maps from a handle and fsid to a server address
1039 *
1040 * returns 0 on success to -errno on failure
1041 */
1042int PINT_cached_config_map_to_server(
1043    PVFS_BMI_addr_t *server_addr,
1044    PVFS_handle handle,
1045    PVFS_fs_id fs_id)
1046{
1047    const struct handle_lookup_entry* tmp_entry;
1048
1049    tmp_entry = find_handle_lookup_entry(handle, fs_id);
1050
1051    if(!tmp_entry)
1052    {
1053        gossip_err("Error: failed to find handle %llu in fs configuration.\n",
1054            llu(handle));
1055        return(-PVFS_EINVAL);
1056    }
1057
1058    *server_addr = tmp_entry->server_addr;
1059    return(0);
1060}
1061
1062/* PINT_cached_config_get_num_dfiles()
1063 *
1064 * Returns 0 if the number of dfiles has been successfully set
1065 *
1066 * Sets the number of dfiles to a distribution approved the value.  Clients
1067 * may pass in num_dfiles_requested as a hint, if no hint is given, the server
1068 * configuration is checked to find a hint there.  The distribution will
1069 * choose a correct number of dfiles even if no hint is set.
1070 */
1071int PINT_cached_config_get_num_dfiles(
1072    PVFS_fs_id fsid,
1073    PINT_dist *dist,
1074    int num_dfiles_requested,
1075    int *num_dfiles)
1076{
1077    int rc;
1078    int num_io_servers;
1079   
1080    /* If the dfile request is zero, check to see if the config has that
1081       setting */
1082    if (0 == num_dfiles_requested)
1083    {
1084        struct qlist_head *hash_link = NULL;
1085        struct config_fs_cache_s *cur_config_cache = NULL;
1086       
1087        /* Locate the filesystem configuration for this fs id */
1088        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1089        if (hash_link)
1090        {
1091            cur_config_cache = qlist_entry(
1092                hash_link, struct config_fs_cache_s, hash_link);
1093            assert(cur_config_cache);
1094            assert(cur_config_cache->fs);
1095            num_dfiles_requested = cur_config_cache->fs->default_num_dfiles;
1096        }
1097    }
1098
1099    /* Determine the number of I/O servers available */
1100    rc = PINT_cached_config_get_num_io(fsid, &num_io_servers);
1101    if(rc < 0)
1102    {
1103        return(rc);
1104    }
1105   
1106    /* Allow the distribution to apply its hint to the number of
1107       dfiles requested and the number of I/O servers available */
1108    *num_dfiles = dist->methods->get_num_dfiles(dist->params,
1109                                                num_io_servers,
1110                                                num_dfiles_requested);
1111    if(*num_dfiles < 1)
1112    {
1113        gossip_err("Error: distribution failure for %d servers and %d requested datafiles.\n", num_io_servers, num_dfiles_requested);
1114        return(-PVFS_EINVAL);
1115    }
1116
1117    return 0;
1118}
1119
1120/* PINT_cached_config_get_num_meta()
1121 *
1122 * discovers the number of metadata servers available for a given file
1123 * system
1124 *
1125 * returns 0 on success, -errno on failure
1126 */
1127int PINT_cached_config_get_num_meta(
1128    PVFS_fs_id fsid,
1129    int *num_meta)
1130{
1131    int ret = -PVFS_EINVAL;
1132    struct qlist_head *hash_link = NULL;
1133    struct config_fs_cache_s *cur_config_cache = NULL;
1134
1135    if (num_meta)
1136    {
1137        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1138        if (hash_link)
1139        {
1140            cur_config_cache = qlist_entry(
1141                hash_link, struct config_fs_cache_s, hash_link);
1142
1143            assert(cur_config_cache);
1144            assert(cur_config_cache->fs);
1145            assert(cur_config_cache->fs->meta_handle_ranges);
1146
1147            *num_meta = PINT_llist_count(
1148                cur_config_cache->fs->meta_handle_ranges);
1149            ret = 0;
1150        }
1151    }
1152    return ret;
1153}
1154
1155/* PINT_cached_config_get_num_io()
1156 *
1157 * discovers the number of io servers available for a given file
1158 * system
1159 *
1160 * returns 0 on success, -errno on failure
1161 */
1162int PINT_cached_config_get_num_io(PVFS_fs_id fsid, int *num_io)
1163{
1164    int ret = -PVFS_EINVAL;
1165    struct qlist_head *hash_link = NULL;
1166    struct config_fs_cache_s *cur_config_cache = NULL;
1167
1168    if (num_io)
1169    {
1170        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1171        if (hash_link)
1172        {
1173            cur_config_cache = qlist_entry(
1174                hash_link, struct config_fs_cache_s, hash_link);
1175
1176            assert(cur_config_cache);
1177            assert(cur_config_cache->fs);
1178            assert(cur_config_cache->fs->data_handle_ranges);
1179
1180            *num_io = PINT_llist_count(
1181                cur_config_cache->fs->data_handle_ranges);
1182            ret = 0;
1183        }
1184    }
1185    return ret;
1186}
1187
1188/* PINT_cached_config_get_server_handle_count()
1189 *
1190 * counts the number of handles associated with a given server
1191 *
1192 * returns 0 on success, -PVFS_error on failure
1193 */
1194int PINT_cached_config_get_server_handle_count(
1195    const char *server_addr_str,
1196    PVFS_fs_id fs_id,
1197    uint64_t *handle_count)
1198{
1199    struct qlist_head *hash_link = NULL;
1200    struct config_fs_cache_s *cur_config_cache = NULL;
1201    struct host_handle_mapping_s *server_mapping = NULL;
1202
1203    *handle_count = 0;
1204
1205    assert(PINT_fsid_config_cache_table);
1206
1207    /* for each fs find the right server */
1208    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fs_id));
1209    if (hash_link)
1210    {
1211        cur_config_cache = qlist_entry(
1212            hash_link, struct config_fs_cache_s, hash_link);
1213
1214        assert(cur_config_cache);
1215        assert(cur_config_cache->fs);
1216
1217        server_mapping = PINT_cached_config_find_server(
1218            cur_config_cache->fs->meta_handle_ranges, server_addr_str);
1219        if(server_mapping)
1220        {
1221            *handle_count += PINT_extent_array_count_total(
1222                &server_mapping->handle_extent_array);
1223        }
1224
1225        server_mapping = PINT_cached_config_find_server(
1226            cur_config_cache->fs->data_handle_ranges, server_addr_str);
1227        if(server_mapping)
1228        {
1229            *handle_count += PINT_extent_array_count_total(
1230                &server_mapping->handle_extent_array);
1231        }
1232    }
1233    return 0;
1234}
1235
1236/* PINT_cached_config_get_server_name()
1237 *
1238 * discovers the string (BMI url) name of a server that controls the
1239 * specified cached_config.
1240 *
1241 * returns 0 on success, -errno on failure
1242 */
1243int PINT_cached_config_get_server_name(
1244    char *server_name,
1245    int max_server_name_len,
1246    PVFS_handle handle,
1247    PVFS_fs_id fsid)
1248{
1249    const struct handle_lookup_entry* tmp_entry;
1250
1251    tmp_entry = find_handle_lookup_entry(handle, fsid);
1252
1253    if(!tmp_entry)
1254    {
1255        gossip_err("Error: failed to find handle %llu in fs configuration.\n",
1256            llu(handle));
1257        return(-PVFS_EINVAL);
1258    }
1259
1260    strncpy(server_name, tmp_entry->server_name, max_server_name_len);
1261    return(0);
1262}
1263
1264/* PINT_cached_config_get_root_handle()
1265 *
1266 * return the root handle of any valid filesystem
1267 *
1268 * returns 0 on success -errno on failure
1269 *
1270 */
1271int PINT_cached_config_get_root_handle(
1272    PVFS_fs_id fsid,
1273    PVFS_handle *fh_root)
1274{
1275    int ret = -PVFS_EINVAL;
1276    struct qlist_head *hash_link = NULL;
1277    struct config_fs_cache_s *cur_config_cache = NULL;
1278
1279    if (fh_root)
1280    {
1281        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1282        if (hash_link)
1283        {
1284            cur_config_cache = qlist_entry(
1285                hash_link, struct config_fs_cache_s, hash_link);
1286
1287            assert(cur_config_cache);
1288            assert(cur_config_cache->fs);
1289
1290            *fh_root = (PVFS_handle)cur_config_cache->fs->root_handle;
1291            ret = 0;
1292        }
1293    }
1294    return ret;
1295}
1296
1297int PINT_cached_config_get_handle_timeout(
1298    PVFS_fs_id fsid,
1299    struct timeval *timeout)
1300{
1301    int ret = -PVFS_EINVAL;
1302    struct qlist_head *hash_link = NULL;
1303    struct config_fs_cache_s *cur_config_cache = NULL;
1304
1305    hash_link = qhash_search(PINT_fsid_config_cache_table, &(fsid));
1306    if(hash_link)
1307    {
1308        cur_config_cache = qlist_entry(
1309            hash_link, struct config_fs_cache_s, hash_link);
1310
1311        assert(cur_config_cache);
1312        assert(cur_config_cache->fs);
1313
1314        timeout->tv_sec =
1315            cur_config_cache->fs->handle_recycle_timeout_sec.tv_sec;
1316        timeout->tv_usec =
1317            cur_config_cache->fs->handle_recycle_timeout_sec.tv_usec;
1318        ret = 0;
1319    }
1320    return ret;
1321}
1322
1323int PINT_cached_config_get_server_list(
1324    PVFS_fs_id fs_id,
1325    PINT_dist *dist,
1326    int num_dfiles_req,
1327    PVFS_sys_layout *layout,
1328    const char ***server_names,
1329    int *server_count)
1330{
1331    int num_io_servers, ret, i;
1332    PVFS_BMI_addr_t *server_addrs;
1333    const char **servers;
1334
1335    /* find the server list from the layout */
1336    ret = PINT_cached_config_get_num_dfiles(
1337        fs_id,
1338        dist,
1339        num_dfiles_req,
1340        &num_io_servers);
1341    if (ret < 0)
1342    {
1343        gossip_err("Failed to get number of data servers\n");
1344        return ret;
1345    }
1346
1347    if(num_io_servers > PVFS_REQ_LIMIT_DFILE_COUNT)
1348    {
1349        num_io_servers = PVFS_REQ_LIMIT_DFILE_COUNT;
1350        gossip_err("Warning: reducing number of data "
1351                     "files to PVFS_REQ_LIMIT_DFILE_COUNT\n");
1352    }
1353
1354    server_addrs = malloc(sizeof(*server_addrs) * num_io_servers);
1355    if(!server_addrs)
1356    {
1357        gossip_err("Failed to allocate server address list\n");
1358        return -PVFS_ENOMEM;
1359    }
1360
1361    ret = PINT_cached_config_map_servers(
1362        fs_id,
1363        &num_io_servers,
1364        layout,
1365        server_addrs,
1366        NULL);
1367    if(ret != 0)
1368    {
1369        gossip_err("Failed to get IO server addrs from layout\n");
1370        return ret;
1371    }
1372
1373    servers = malloc(sizeof(*servers) * num_io_servers);
1374    if(!servers)
1375    {
1376        gossip_err("Failed to allocate server address list\n");
1377        free(server_addrs);
1378        return -PVFS_ENOMEM;
1379    }
1380
1381    for(i = 0; i < num_io_servers; ++i)
1382    {
1383        servers[i] = BMI_addr_rev_lookup(server_addrs[i]);
1384    }
1385    free(server_addrs);
1386
1387    *server_count = num_io_servers;
1388    *server_names = servers;
1389
1390    return 0;
1391}
1392
1393/* cache_server_array()
1394 *
1395 * verifies that the arrays of physical server addresses have been
1396 * cached in the configuration structs
1397 *
1398 * returns 0 on success, -errno on failure
1399 */
1400static int cache_server_array(
1401    PVFS_fs_id fsid)
1402{
1403    int ret = -PVFS_EINVAL, i = 0, j = 0;
1404    char *server_bmi_str = NULL;
1405    struct host_handle_mapping_s *cur_mapping = NULL;
1406    struct qlist_head *hash_link = NULL;
1407    struct config_fs_cache_s *cur_config_cache = NULL;
1408    PINT_llist *tmp_server = NULL;
1409    PVFS_BMI_addr_t tmp_bmi_addr;
1410    int dup_flag = 0;
1411    int current = 0;
1412    int array_index = 0, array_index2 = 0;
1413
1414    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1415    if (!hash_link)
1416    {
1417        return ret;
1418    }
1419    cur_config_cache = qlist_entry(
1420        hash_link, struct config_fs_cache_s, hash_link);
1421
1422    assert(cur_config_cache);
1423    assert(cur_config_cache->fs);
1424
1425    /* first check to see if we have the array information cached */
1426    if (cur_config_cache->server_count < 1)
1427    {
1428        /* we need to fill in this stuff in our config cache */
1429        cur_config_cache->server_count = 0;
1430        cur_config_cache->meta_server_count = 0;
1431        cur_config_cache->io_server_count = 0;
1432
1433        /* iterate through lists to come up with an upper bound for
1434         * the size of the arrays that we need
1435         */
1436        tmp_server = cur_config_cache->fs->meta_handle_ranges;
1437        while ((cur_mapping = PINT_llist_head(tmp_server)))
1438        {
1439            tmp_server = PINT_llist_next(tmp_server);
1440            cur_config_cache->meta_server_count++;
1441            cur_config_cache->server_count++;
1442        }
1443        tmp_server = cur_config_cache->fs->data_handle_ranges;
1444        while ((cur_mapping = PINT_llist_head(tmp_server)))
1445        {
1446            tmp_server = PINT_llist_next(tmp_server);
1447            cur_config_cache->io_server_count++;
1448            cur_config_cache->server_count++;
1449        }
1450
1451        cur_config_cache->meta_server_array = (phys_server_desc_s*)malloc(
1452            (cur_config_cache->meta_server_count *
1453             sizeof(phys_server_desc_s)));
1454        cur_config_cache->io_server_array = (phys_server_desc_s*)malloc(
1455            (cur_config_cache->io_server_count*
1456             sizeof(phys_server_desc_s)));
1457        cur_config_cache->server_array = (phys_server_desc_s*)malloc(
1458            (cur_config_cache->server_count*
1459             sizeof(phys_server_desc_s)));
1460
1461        if ((cur_config_cache->meta_server_array == NULL) ||
1462            (cur_config_cache->io_server_array == NULL) ||
1463            (cur_config_cache->server_array == NULL))
1464        {
1465            ret = -PVFS_ENOMEM;
1466            goto cleanup_allocations;
1467        }
1468        memset(cur_config_cache->server_array, 0,
1469               (cur_config_cache->server_count *
1470                sizeof(phys_server_desc_s)));
1471
1472        /* reset counts until we find out how many physical servers
1473         * are actually present
1474         */
1475        cur_config_cache->server_count = 0;
1476        cur_config_cache->meta_server_count = 0;
1477        cur_config_cache->io_server_count = 0;
1478
1479        for(i = 0; i < 2; i++)
1480        {
1481            if (i == 0)
1482            {
1483                tmp_server = cur_config_cache->fs->meta_handle_ranges;
1484                current = PINT_SERVER_TYPE_META;
1485            }
1486            else
1487            {
1488                tmp_server = cur_config_cache->fs->data_handle_ranges;
1489                current = PINT_SERVER_TYPE_IO;
1490            }
1491            while ((cur_mapping = PINT_llist_head(tmp_server)))
1492            {
1493                tmp_server = PINT_llist_next(tmp_server);
1494                server_bmi_str = cur_mapping->alias_mapping->bmi_address;
1495
1496                ret = BMI_addr_lookup(&tmp_bmi_addr,server_bmi_str);
1497                if (ret < 0)
1498                {
1499                    return(ret);
1500                }
1501
1502                /* see if we have already listed this BMI address */
1503                dup_flag = 0;
1504                for (j=0; j < array_index; j++)
1505                {
1506                    if (cur_config_cache->server_array[j].addr ==
1507                        tmp_bmi_addr)
1508                    {
1509                        cur_config_cache->server_array[j].server_type
1510                            |= current;
1511                        dup_flag = 1;
1512                        break;
1513                    }
1514                }
1515               
1516                if (!dup_flag)
1517                {
1518                    cur_config_cache->server_array[array_index].addr =
1519                        tmp_bmi_addr;
1520                    cur_config_cache->server_array[
1521                        array_index].addr_string = server_bmi_str;
1522                    cur_config_cache->server_array[
1523                        array_index].server_type = current;
1524                    array_index++;
1525                    cur_config_cache->server_count = array_index;
1526                }
1527            }
1528        }
1529
1530        /* now build meta and I/O arrays based on generic server list */
1531        array_index = 0;
1532        array_index2 = 0;
1533        for(i = 0; i < cur_config_cache->server_count; i++)
1534        {
1535            if (cur_config_cache->server_array[i].server_type &
1536                PINT_SERVER_TYPE_META)
1537            {
1538                cur_config_cache->meta_server_array[array_index] =
1539                    cur_config_cache->server_array[i];
1540                array_index++;
1541            }
1542            if (cur_config_cache->server_array[i].server_type &
1543                PINT_SERVER_TYPE_IO)
1544            {
1545                cur_config_cache->io_server_array[array_index2] =
1546                    cur_config_cache->server_array[i];
1547                array_index2++;
1548            }
1549        }
1550        cur_config_cache->meta_server_count = array_index;
1551        cur_config_cache->io_server_count = array_index2;
1552    }
1553    return 0;
1554
1555  cleanup_allocations:
1556    if (cur_config_cache->meta_server_array)
1557    {
1558        free(cur_config_cache->meta_server_array);
1559    }
1560    if (cur_config_cache->io_server_array)
1561    {
1562        free(cur_config_cache->io_server_array);
1563    }
1564    if (cur_config_cache->server_array)
1565    {
1566        free(cur_config_cache->server_array);
1567    }
1568    return ret;
1569}
1570
1571/* hash_fsid()
1572 *
1573 * hash function for fsids added to table
1574 *
1575 * returns integer offset into table
1576 */
1577static int hash_fsid(void *fsid, int table_size)
1578{
1579    unsigned long tmp = 0;
1580    PVFS_fs_id *real_fsid = (PVFS_fs_id *)fsid;
1581
1582    assert(PINT_fsid_config_cache_table);
1583
1584    tmp += (*(real_fsid));
1585    tmp = tmp%table_size;
1586
1587    return ((int) tmp);
1588}
1589
1590/* hash_fsid_compare()
1591 *
1592 * performs a comparison of a hash table entro to a given key (used
1593 * for searching)
1594 *
1595 * returns 1 if match found, 0 otherwise
1596 */
1597static int hash_fsid_compare(void *key, struct qlist_head *link)
1598{
1599    struct config_fs_cache_s *fs_info = NULL;
1600    PVFS_fs_id *real_fsid = (PVFS_fs_id *)key;
1601
1602    assert(PINT_fsid_config_cache_table);
1603
1604    fs_info = qlist_entry(link, struct config_fs_cache_s, hash_link);
1605    if ((PVFS_fs_id)fs_info->fs->coll_id == *real_fsid)
1606    {
1607        return 1;
1608    }
1609    return 0;
1610}
1611
1612/* handle_lookup_entry_compare()
1613 *  *
1614 *   * comparison function used by qsort()
1615 *    */
1616static int handle_lookup_entry_compare(const void *p1, const void *p2)
1617{
1618    const struct handle_lookup_entry* e1  = p1;
1619    const struct handle_lookup_entry* e2  = p2;
1620
1621    if(e1->extent.first < e2->extent.first)
1622        return(-1);
1623    if(e1->extent.first > e2->extent.first)
1624        return(1);
1625
1626    return(0);
1627}
1628
1629/* find_handle_lookup_entry()
1630 *
1631 * searches sorted table for extent that contains the specified handle
1632 *
1633 * returns pointer to table entry on success, NULL on failure
1634 */
1635static const struct handle_lookup_entry* find_handle_lookup_entry(
1636    PVFS_handle handle, PVFS_fs_id fsid)
1637{
1638    struct qlist_head *hash_link = NULL;
1639    struct config_fs_cache_s *cur_config_cache = NULL;
1640    int high, low, mid;
1641    int table_index;
1642
1643    assert(PINT_fsid_config_cache_table);
1644
1645    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1646    if(!hash_link)
1647    {
1648        return(NULL);
1649    }
1650
1651    cur_config_cache = qlist_entry(
1652        hash_link, struct config_fs_cache_s, hash_link);
1653
1654    assert(cur_config_cache);
1655    assert(cur_config_cache->fs);
1656
1657    /* iterative binary search through handle lookup table to find the
1658     * extent that this handle falls into
1659     */
1660    low = 0;
1661    high = cur_config_cache->handle_lookup_table_size;
1662    while (low < high)
1663    {
1664        mid = (low + high)/2;
1665        if (cur_config_cache->handle_lookup_table[mid].extent.first < handle)
1666            low = mid + 1;
1667        else
1668            high = mid;
1669    }
1670    if ((low < cur_config_cache->handle_lookup_table_size) &&
1671        (cur_config_cache->handle_lookup_table[low].extent.first == handle))
1672    {
1673        /* we happened to locate the first handle in a range */
1674        table_index = low;
1675    }
1676    else
1677    {
1678        /* this handle must fall into the previous range if any */
1679        table_index = low-1;
1680    }
1681
1682    /* confirm match */
1683    if(PINT_handle_in_extent(
1684        &cur_config_cache->handle_lookup_table[table_index].extent,
1685        handle))
1686    {
1687        return(&cur_config_cache->handle_lookup_table[table_index]);
1688    }
1689
1690    /* no match */
1691    return(NULL);
1692}
1693
1694/* load_handle_lookup_table()
1695 *
1696 * iterates through extents for all servers and constructs a table sorted by
1697 * the first handle in each extent.  This table can then be searched with a
1698 * binary algorithm to map handles to servers.  Table includes extent,
1699 * server name, and server's resolved bmi address.
1700 *
1701 * returns 0 on success, -PVFS_error on failure
1702 */
1703static int load_handle_lookup_table(
1704    struct config_fs_cache_s *cur_config_fs_cache)
1705{
1706    int ret = -PVFS_EINVAL;
1707    host_handle_mapping_s *cur_mapping = NULL;
1708    int count = 0;
1709    int table_offset = 0;
1710    PINT_llist* server_cursor;
1711    int i;
1712    int j;
1713    PINT_llist* range_list[2] =
1714    {
1715        cur_config_fs_cache->fs->meta_handle_ranges,
1716        cur_config_fs_cache->fs->data_handle_ranges
1717    };
1718
1719    /* count total number of extents */
1720    /* loop through both meta and data ranges */
1721    for(j=0; j<2; j++)
1722    {
1723        server_cursor = range_list[j];
1724        cur_mapping = PINT_llist_head(server_cursor);
1725        while(cur_mapping)
1726        {
1727            /* each server may have multiple extents */
1728            for(i=0; i<cur_mapping->handle_extent_array.extent_count; i++)
1729            {
1730                count += 1;
1731            }
1732            server_cursor = PINT_llist_next(server_cursor);
1733            cur_mapping = PINT_llist_head(server_cursor);
1734        }
1735    }
1736
1737    /* allocate a table to hold all extents for faster searching */
1738    if(cur_config_fs_cache->handle_lookup_table)
1739    {
1740        free(cur_config_fs_cache->handle_lookup_table);
1741    }
1742    cur_config_fs_cache->handle_lookup_table =
1743        malloc(sizeof(*cur_config_fs_cache->handle_lookup_table) * count);
1744    if(!cur_config_fs_cache->handle_lookup_table)
1745    {
1746        return(-PVFS_ENOMEM);
1747    }
1748    cur_config_fs_cache->handle_lookup_table_size = count;
1749
1750    /* populate table */
1751    /* loop through both meta and data ranges */
1752    for(j=0; j<2; j++)
1753    {
1754        server_cursor = range_list[j];
1755        cur_mapping = PINT_llist_head(server_cursor);
1756        while(cur_mapping)
1757        {
1758            for(i=0; i<cur_mapping->handle_extent_array.extent_count; i++)
1759            {
1760                cur_config_fs_cache->handle_lookup_table[table_offset].extent
1761                    = cur_mapping->handle_extent_array.extent_array[i];
1762                cur_config_fs_cache->handle_lookup_table[table_offset].server_name
1763                    = cur_mapping->alias_mapping->bmi_address;
1764                ret = BMI_addr_lookup(
1765                    &cur_config_fs_cache->handle_lookup_table[table_offset].server_addr,                 
1766                    cur_config_fs_cache->handle_lookup_table[table_offset].server_name);
1767                if(ret < 0)
1768                {
1769                    free(cur_config_fs_cache->handle_lookup_table);
1770                    gossip_err("Error: failed to resolve address of server: %s\n",
1771                        cur_config_fs_cache->handle_lookup_table[table_offset].server_name);
1772                    return(ret);
1773                }
1774                table_offset++;
1775            }
1776            server_cursor = PINT_llist_next(server_cursor);
1777            cur_mapping = PINT_llist_head(server_cursor);
1778        }
1779    }
1780
1781    /* sort table */
1782    qsort(cur_config_fs_cache->handle_lookup_table, table_offset,
1783        sizeof(*cur_config_fs_cache->handle_lookup_table),
1784        handle_lookup_entry_compare);
1785
1786    return(0);
1787}
1788
1789/* PINT_cached_config_server_names()
1790 *
1791 * Returns a list of pointers to the IO server names currently running in this   
1792 * file system.
1793 *
1794 * returns 0 on success, -PVFS_error on failure
1795 */
1796int PINT_cached_config_io_server_names( char ***list
1797                                      , int *size
1798                                      , PVFS_fs_id fsid)
1799{
1800    int i;
1801    struct qlist_head *hash_link = NULL;
1802    struct config_fs_cache_s *cur_config_cache = NULL;
1803
1804    assert(PINT_fsid_config_cache_table);
1805
1806    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1807    if(!hash_link)
1808    {
1809        return(-PVFS_ENOENT);
1810    }
1811
1812    cur_config_cache = qlist_entry(
1813        hash_link, struct config_fs_cache_s, hash_link);
1814
1815    assert(cur_config_cache);
1816
1817    *size = cur_config_cache->io_server_count;
1818
1819    *list = malloc(sizeof(char *) * (*size));
1820
1821    if (! (*list) )
1822       return(-PVFS_ENOMEM);
1823
1824    memset(*list,0,sizeof(char *) * (*size));
1825
1826    for (i=0; i<(*size); i++)
1827    {
1828        /*addr_string originates from the alias mapping->bmi_address*/
1829        (*list)[i] = cur_config_cache->io_server_array[i].addr_string;
1830    }
1831
1832   return(0);
1833}
1834
1835/*
1836 * Local variables:
1837 *  c-indent-level: 4
1838 *  c-basic-offset: 4
1839 * End:
1840 *
1841 * vim: ts=8 sts=4 sw=4 expandtab
1842 */
Note: See TracBrowser for help on using the browser.