root/branches/cu-security-branch/src/common/misc/pint-cached-config.c @ 8397

Revision 8397, 52.4 KB (checked in by nlmills, 3 years ago)

initial merge with Orange-Branch. much will be broken

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 num_io_servers, 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    num_io_servers = PINT_llist_count(server_list);
479
480    while(!PINT_llist_empty(server_list))
481    {
482        cur_mapping = PINT_llist_head(server_list);
483        assert(cur_mapping);
484        server_list = PINT_llist_next(server_list);
485
486        ret = BMI_addr_lookup(
487            &tmp_addr, cur_mapping->alias_mapping->bmi_address);
488        if(ret < 0)
489        {
490            return ret;
491        }
492
493        if(tmp_addr == *addr)
494        {
495            handle_extents->extent_count =
496                cur_mapping->handle_extent_array.extent_count;
497            handle_extents->extent_array =
498                cur_mapping->handle_extent_array.extent_array;
499
500            return 0;
501        }
502    }
503    return -PVFS_ENOENT;
504}
505
506int PINT_cached_config_map_servers(
507    PVFS_fs_id fsid,
508    int *inout_num_datafiles,
509    PVFS_sys_layout *layout,
510    PVFS_BMI_addr_t *addr_array,
511    PVFS_handle_extent_array *handle_extent_array)
512{
513    struct qhash_head *hash_link;
514    struct PINT_llist *server_list;
515    struct host_handle_mapping_s *cur_mapping = NULL;
516    struct config_fs_cache_s *cur_config_cache = NULL;
517    int num_io_servers, i, ret;
518    int start_index = -1;
519    int index;
520    int random_attempts;
521
522    assert(inout_num_datafiles);
523
524    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
525    if(!hash_link)
526    {
527        gossip_err("Failed to find a file system matching fsid: %d\n", fsid);
528        return -PVFS_EINVAL;
529    }
530
531    cur_config_cache = qlist_entry(
532        hash_link, struct config_fs_cache_s, hash_link);
533
534    assert(cur_config_cache);
535    assert(cur_config_cache->fs);
536
537    server_list = cur_config_cache->fs->data_handle_ranges;
538    num_io_servers = PINT_llist_count(server_list);
539
540    switch(layout->algorithm)
541    {
542        case PVFS_SYS_LAYOUT_LIST:
543
544            if(*inout_num_datafiles < layout->server_list.count)
545            {
546                gossip_err("The specified datafile layout is larger"
547                           " than the number of requested datafiles\n");
548                return -PVFS_EINVAL;
549            }
550
551            *inout_num_datafiles = layout->server_list.count;
552            for(i = 0; i < layout->server_list.count; ++i)
553            {
554                if(handle_extent_array)
555                {
556                    ret = PINT_cached_config_get_extents(
557                        fsid,
558                        &layout->server_list.servers[i],
559                        &handle_extent_array[i]);
560                    if(ret < 0)
561                    {
562                        gossip_err("The address specified in the datafile "
563                                   "layout is invalid\n");
564                        return ret;
565                    }
566                }
567
568                addr_array[i] = layout->server_list.servers[i];
569            }
570            break;
571
572        case PVFS_SYS_LAYOUT_NONE:
573            start_index = 0;
574            /* fall through */
575
576        case PVFS_SYS_LAYOUT_ROUND_ROBIN:
577
578            if(num_io_servers < *inout_num_datafiles)
579            {
580                *inout_num_datafiles = num_io_servers;
581            }
582
583            if(start_index == -1)
584            {
585                start_index = rand() % *inout_num_datafiles;
586            }
587
588            for(i = 0; i < *inout_num_datafiles; ++i)
589            {
590                cur_mapping = PINT_llist_head(server_list);
591                assert(cur_mapping);
592                server_list = PINT_llist_next(server_list);
593
594                index = (i + start_index) % *inout_num_datafiles;
595                ret = BMI_addr_lookup(
596                    &addr_array[index],
597                    cur_mapping->alias_mapping->bmi_address);
598                if (ret)
599                {
600                    return ret;
601                }
602
603                if(handle_extent_array)
604                {
605                    handle_extent_array[index].extent_count =
606                        cur_mapping->handle_extent_array.extent_count;
607                    handle_extent_array[index].extent_array =
608                        cur_mapping->handle_extent_array.extent_array;
609                }
610            }
611            break;
612
613        case PVFS_SYS_LAYOUT_RANDOM:
614            /* this layout randomizes the order but still uses each server
615             * only once
616             */
617
618            /* limit this layout to a number of datafiles no greater than
619             * the number of servers
620             */
621            if(num_io_servers < *inout_num_datafiles)
622            {
623                *inout_num_datafiles = num_io_servers;
624            }
625
626            /* init all the addrs to 0, so we know whether we've set an
627             * address at a particular index or not
628             */
629            memset(addr_array, 0, (*inout_num_datafiles)*sizeof(*addr_array));
630
631            for(i = 0; i < *inout_num_datafiles; ++i)
632            {
633                /* go through server list in order */
634                cur_mapping = PINT_llist_head(server_list);
635                assert(cur_mapping);
636                server_list = PINT_llist_next(server_list);
637
638                /* select random index into caller's list */
639                index = rand() % *inout_num_datafiles;
640                random_attempts = 1;
641
642                /* if we have already filled that index, try another random
643                 * index
644                 */
645                while(addr_array[index] != 0 && random_attempts < 6)
646                {
647                    index = rand() % *inout_num_datafiles;
648                    random_attempts++;
649                }
650
651                /* if we exhausted a max number of randomization attempts,
652                 * then just go linearly through list
653                 */
654                while(addr_array[index] != 0)
655                {
656                    index = (index + 1) % *inout_num_datafiles;
657                }
658
659                /* found an unused index */
660                ret = BMI_addr_lookup(
661                    &addr_array[index],
662                    cur_mapping->alias_mapping->bmi_address);
663                if (ret)
664                {
665                    return ret;
666                }
667
668                if(handle_extent_array)
669                {
670                    handle_extent_array[index].extent_count =
671                        cur_mapping->handle_extent_array.extent_count;
672                    handle_extent_array[index].extent_array =
673                        cur_mapping->handle_extent_array.extent_array;
674                }
675            }
676            break;
677        default:
678            gossip_err("Unknown datafile mapping algorithm\n");
679            return -PVFS_EINVAL;
680    }
681    return 0;
682}
683
684/* PINT_cached_config_get_next_io()
685 *
686 * returns the address of a set of servers that should be used to
687 * store new pieces of file data.  This function is responsible for
688 * evenly distributing the file data storage load to all servers.
689 *
690 * NOTE: if io_addr_array is NULL, then don't resolve addresses
691 *
692 * returns 0 on success, -errno on failure
693 */
694int PINT_cached_config_get_next_io(
695    PVFS_fs_id fsid,
696    int num_servers,
697    PVFS_BMI_addr_t *io_addr_array,
698    PVFS_handle_extent_array *io_handle_extent_array)
699{
700    int ret = -PVFS_EINVAL, i = 0;
701    char *data_server_bmi_str = (char *)0;
702    struct host_handle_mapping_s *cur_mapping = NULL;
703    struct qlist_head *hash_link = NULL;
704    struct config_fs_cache_s *cur_config_cache = NULL;
705    int jitter = 0, num_io_servers = 0;
706    PINT_llist* old_data_server_cursor = NULL;
707
708    if (num_servers && io_handle_extent_array)
709    {
710        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
711        if (hash_link)
712        {
713            cur_config_cache = qlist_entry(
714                hash_link, struct config_fs_cache_s, hash_link);
715
716            assert(cur_config_cache);
717            assert(cur_config_cache->fs);
718
719            num_io_servers = PINT_llist_count(
720                cur_config_cache->fs->data_handle_ranges);
721
722
723            /* pick random starting point, then round robin */
724            if(!io_randomized)
725            {
726                jitter = (rand() % num_io_servers);
727                io_randomized = 1;
728            }
729            else
730            {
731                jitter = 0;
732            }
733            while(jitter-- > -1)
734            {
735                cur_mapping = PINT_llist_head(
736                    cur_config_cache->data_server_cursor);
737                if (!cur_mapping)
738                {
739                    cur_config_cache->data_server_cursor =
740                        cur_config_cache->fs->data_handle_ranges;
741                    cur_mapping = PINT_llist_head(
742                        cur_config_cache->data_server_cursor);
743                    assert(cur_mapping);
744                }
745                cur_config_cache->data_server_cursor = PINT_llist_next(
746                    cur_config_cache->data_server_cursor);
747            }
748            old_data_server_cursor = cur_config_cache->data_server_cursor;
749
750            while(num_servers)
751            {
752                assert(cur_config_cache->data_server_cursor);
753
754                cur_mapping = PINT_llist_head(
755                    cur_config_cache->data_server_cursor);
756                if (!cur_mapping)
757                {
758                    cur_config_cache->data_server_cursor =
759                        cur_config_cache->fs->data_handle_ranges;
760                    continue;
761                }
762                cur_config_cache->data_server_cursor = PINT_llist_next(
763                    cur_config_cache->data_server_cursor);
764
765                data_server_bmi_str = cur_mapping->alias_mapping->bmi_address;
766
767                if (io_addr_array != NULL)
768                {
769                    ret = BMI_addr_lookup(
770                        io_addr_array,data_server_bmi_str);
771                    if (ret)
772                    {
773                        break;
774                    }
775                }
776
777                io_handle_extent_array[i].extent_count =
778                    cur_mapping->handle_extent_array.extent_count;
779                io_handle_extent_array[i].extent_array =
780                    cur_mapping->handle_extent_array.extent_array;
781
782                i++;
783                num_servers--;
784                if(io_addr_array != NULL)
785                    io_addr_array++;
786            }
787            ret = ((num_servers == 0) ? 0 : ret);
788            /* reset data server cursor to point to the old cursor; the
789             * jitter on the next iteration will increment it by one
790             */
791            cur_config_cache->data_server_cursor = old_data_server_cursor;
792        }
793    }
794    return ret;
795}
796
797/* PINT_cached_config_map_addr()
798 *
799 * takes an opaque server address and returns the server type and
800 * address string for that server
801 *
802 * returns pointer to string on success, NULL on failure
803 */
804const char *PINT_cached_config_map_addr(
805    PVFS_fs_id fsid,
806    PVFS_BMI_addr_t addr,
807    int *server_type)
808{
809    int ret = -PVFS_EINVAL, i = 0;
810    struct qlist_head *hash_link = NULL;
811    struct config_fs_cache_s *cur_config_cache = NULL;
812
813    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
814    if (!hash_link)
815    {
816        return NULL;
817    }
818    cur_config_cache = qlist_entry(
819        hash_link, struct config_fs_cache_s, hash_link);
820    assert(cur_config_cache);
821    assert(cur_config_cache->fs);
822
823    ret = cache_server_array(fsid);
824    if (ret < 0)
825    {
826        return NULL;
827    }
828
829    /* run through general server list for a match */
830    for(i = 0; i < cur_config_cache->server_count; i++)
831    {
832        if (cur_config_cache->server_array[i].addr == addr)
833        {
834            if(server_type)
835            {
836                *server_type = cur_config_cache->server_array[i].server_type;
837            }
838            return (cur_config_cache->server_array[i].addr_string);
839        }
840    }
841    return NULL;
842}
843
844
845/* PINT_cached_config_check_type()
846 *
847 * Retrieves the server type flags for a specified BMI addr string
848 *
849 * returns 0 on success, -errno on failure
850 */
851int PINT_cached_config_check_type(
852    PVFS_fs_id fsid,
853    const char *server_addr_str,
854    int* server_type)
855{
856    int ret = -PVFS_EINVAL, i = 0;
857    struct qlist_head *hash_link = NULL;
858    struct config_fs_cache_s *cur_config_cache = NULL;
859
860    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
861    if (!hash_link)
862    {
863        return(-PVFS_EINVAL);
864    }
865    cur_config_cache = qlist_entry(
866        hash_link, struct config_fs_cache_s, hash_link);
867    assert(cur_config_cache);
868    assert(cur_config_cache->fs);
869
870    ret = cache_server_array(fsid);
871    if (ret < 0)
872    {
873        return(ret);
874    }
875
876    /* run through general server list for a match */
877    for(i = 0; i < cur_config_cache->server_count; i++)
878    {
879        if (!(strcmp(cur_config_cache->server_array[i].addr_string,
880           server_addr_str)))
881        {
882            *server_type = cur_config_cache->server_array[i].server_type;
883            return(0);
884        }
885    }
886    return(-PVFS_EINVAL);
887}
888
889
890/* PINT_cached_config_count_servers()
891 *
892 * counts the number of physical servers of the specified type
893 *
894 * returns 0 on success, -errno on failure
895 */
896int PINT_cached_config_count_servers(
897    PVFS_fs_id fsid,
898    int server_type,
899    int *count)
900{
901    int ret = -PVFS_EINVAL;
902    struct qlist_head *hash_link = NULL;
903    struct config_fs_cache_s *cur_config_cache = NULL;
904
905    if (!server_type)
906    {
907        return ret;
908    }
909
910    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
911    if (!hash_link)
912    {
913        return ret;
914    }
915    cur_config_cache = qlist_entry(
916        hash_link, struct config_fs_cache_s, hash_link);
917
918    assert(cur_config_cache);
919    assert(cur_config_cache->fs);
920
921    ret = cache_server_array(fsid);
922    if (ret == 0)
923    {
924        if (server_type == PINT_SERVER_TYPE_META)
925        {
926            *count = cur_config_cache->meta_server_count;
927            ret = 0;
928        }
929        else if (server_type == PINT_SERVER_TYPE_IO)
930        {
931            *count = cur_config_cache->io_server_count;
932            ret = 0;
933        }
934        else if (server_type == PINT_SERVER_TYPE_ALL)
935        {
936            *count = cur_config_cache->server_count;
937            ret = 0;
938        }
939    }
940    return ret;
941}
942
943/* PINT_cached_config_get_server_array()
944 *
945 * fills in an array of addresses corresponding to each server of the
946 * type specified by "server_type" (meta,io,or both).  If
947 * inout_count_p is not large enough to accomodate array, then an
948 * error is returned.
949 *
950 * returns 0 on success, -errno on failure
951 */
952int PINT_cached_config_get_server_array(
953    PVFS_fs_id fsid,
954    int server_type,
955    PVFS_BMI_addr_t *addr_array,
956    int *inout_count_p)
957{
958    int ret = -PVFS_EINVAL, i = 0;
959    struct qlist_head *hash_link = NULL;
960    struct config_fs_cache_s *cur_config_cache = NULL;
961
962    if (!inout_count_p || !*inout_count_p ||
963        !addr_array || !server_type)
964    {
965        return ret;
966    }
967
968    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
969    if (!hash_link)
970    {
971        return ret;
972    }
973    cur_config_cache = qlist_entry(
974        hash_link, struct config_fs_cache_s, hash_link);
975
976    assert(cur_config_cache);
977    assert(cur_config_cache->fs);
978
979    ret = cache_server_array(fsid);
980    if (ret < 0)
981    {
982        return ret;
983    }
984
985    /* at this point, we should have the data that we need cached up,
986     * just copy out
987     */
988    if (server_type == PINT_SERVER_TYPE_META)
989    {
990        if (*inout_count_p < cur_config_cache->meta_server_count)
991        {
992            return -PVFS_EMSGSIZE;
993        }
994
995        for(i = 0; i < cur_config_cache->meta_server_count; i++)
996        {
997            addr_array[i] = cur_config_cache->meta_server_array[i].addr;
998        }
999
1000        *inout_count_p = cur_config_cache->meta_server_count;
1001        return 0;
1002    }
1003    else if (server_type == PINT_SERVER_TYPE_IO)
1004    {
1005        if (*inout_count_p < cur_config_cache->io_server_count)
1006        {
1007            return -PVFS_EMSGSIZE;
1008        }
1009
1010        for(i = 0; i < cur_config_cache->io_server_count; i++)
1011        {
1012            addr_array[i] = cur_config_cache->io_server_array[i].addr;
1013        }
1014
1015        *inout_count_p = cur_config_cache->io_server_count;
1016        return 0;
1017    }
1018    else if (server_type == PINT_SERVER_TYPE_ALL)
1019    {
1020        if (*inout_count_p < cur_config_cache->server_count)
1021        {
1022            return -PVFS_EMSGSIZE;
1023        }
1024
1025        for(i = 0; i < cur_config_cache->server_count; i++)
1026        {
1027            addr_array[i] =
1028                cur_config_cache->server_array[i].addr;
1029        }
1030
1031        *inout_count_p = cur_config_cache->server_count;
1032        return 0;
1033    }
1034    return ret;
1035}
1036
1037/* PINT_cached_config_map_to_server()
1038 *
1039 * maps from a handle and fsid to a server address
1040 *
1041 * returns 0 on success to -errno on failure
1042 */
1043int PINT_cached_config_map_to_server(
1044    PVFS_BMI_addr_t *server_addr,
1045    PVFS_handle handle,
1046    PVFS_fs_id fs_id)
1047{
1048    const struct handle_lookup_entry* tmp_entry;
1049
1050    tmp_entry = find_handle_lookup_entry(handle, fs_id);
1051
1052    if(!tmp_entry)
1053    {
1054        gossip_err("Error: failed to find handle %llu in fs configuration.\n",
1055            llu(handle));
1056        return(-PVFS_EINVAL);
1057    }
1058
1059    *server_addr = tmp_entry->server_addr;
1060    return(0);
1061}
1062
1063/* PINT_cached_config_get_num_dfiles()
1064 *
1065 * Returns 0 if the number of dfiles has been successfully set
1066 *
1067 * Sets the number of dfiles to a distribution approved the value.  Clients
1068 * may pass in num_dfiles_requested as a hint, if no hint is given, the server
1069 * configuration is checked to find a hint there.  The distribution will
1070 * choose a correct number of dfiles even if no hint is set.
1071 */
1072int PINT_cached_config_get_num_dfiles(
1073    PVFS_fs_id fsid,
1074    PINT_dist *dist,
1075    int num_dfiles_requested,
1076    int *num_dfiles)
1077{
1078    int rc;
1079    int num_io_servers;
1080   
1081    /* If the dfile request is zero, check to see if the config has that
1082       setting */
1083    if (0 == num_dfiles_requested)
1084    {
1085        struct qlist_head *hash_link = NULL;
1086        struct config_fs_cache_s *cur_config_cache = NULL;
1087       
1088        /* Locate the filesystem configuration for this fs id */
1089        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1090        if (hash_link)
1091        {
1092            cur_config_cache = qlist_entry(
1093                hash_link, struct config_fs_cache_s, hash_link);
1094            assert(cur_config_cache);
1095            assert(cur_config_cache->fs);
1096            num_dfiles_requested = cur_config_cache->fs->default_num_dfiles;
1097        }
1098    }
1099
1100    /* Determine the number of I/O servers available */
1101    rc = PINT_cached_config_get_num_io(fsid, &num_io_servers);
1102    if(rc < 0)
1103    {
1104        return(rc);
1105    }
1106   
1107    /* Allow the distribution to apply its hint to the number of
1108       dfiles requested and the number of I/O servers available */
1109    *num_dfiles = dist->methods->get_num_dfiles(dist->params,
1110                                                num_io_servers,
1111                                                num_dfiles_requested);
1112    if(*num_dfiles < 1)
1113    {
1114        gossip_err("Error: distribution failure for %d servers and %d requested datafiles.\n", num_io_servers, num_dfiles_requested);
1115        return(-PVFS_EINVAL);
1116    }
1117
1118    return 0;
1119}
1120
1121/* PINT_cached_config_get_num_meta()
1122 *
1123 * discovers the number of metadata servers available for a given file
1124 * system
1125 *
1126 * returns 0 on success, -errno on failure
1127 */
1128int PINT_cached_config_get_num_meta(
1129    PVFS_fs_id fsid,
1130    int *num_meta)
1131{
1132    int ret = -PVFS_EINVAL;
1133    struct qlist_head *hash_link = NULL;
1134    struct config_fs_cache_s *cur_config_cache = NULL;
1135
1136    if (num_meta)
1137    {
1138        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1139        if (hash_link)
1140        {
1141            cur_config_cache = qlist_entry(
1142                hash_link, struct config_fs_cache_s, hash_link);
1143
1144            assert(cur_config_cache);
1145            assert(cur_config_cache->fs);
1146            assert(cur_config_cache->fs->meta_handle_ranges);
1147
1148            *num_meta = PINT_llist_count(
1149                cur_config_cache->fs->meta_handle_ranges);
1150            ret = 0;
1151        }
1152    }
1153    return ret;
1154}
1155
1156/* PINT_cached_config_get_num_io()
1157 *
1158 * discovers the number of io servers available for a given file
1159 * system
1160 *
1161 * returns 0 on success, -errno on failure
1162 */
1163int PINT_cached_config_get_num_io(PVFS_fs_id fsid, int *num_io)
1164{
1165    int ret = -PVFS_EINVAL;
1166    struct qlist_head *hash_link = NULL;
1167    struct config_fs_cache_s *cur_config_cache = NULL;
1168
1169    if (num_io)
1170    {
1171        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1172        if (hash_link)
1173        {
1174            cur_config_cache = qlist_entry(
1175                hash_link, struct config_fs_cache_s, hash_link);
1176
1177            assert(cur_config_cache);
1178            assert(cur_config_cache->fs);
1179            assert(cur_config_cache->fs->data_handle_ranges);
1180
1181            *num_io = PINT_llist_count(
1182                cur_config_cache->fs->data_handle_ranges);
1183            ret = 0;
1184        }
1185    }
1186    return ret;
1187}
1188
1189/* PINT_cached_config_get_server_handle_count()
1190 *
1191 * counts the number of handles associated with a given server
1192 *
1193 * returns 0 on success, -PVFS_error on failure
1194 */
1195int PINT_cached_config_get_server_handle_count(
1196    const char *server_addr_str,
1197    PVFS_fs_id fs_id,
1198    uint64_t *handle_count)
1199{
1200    struct qlist_head *hash_link = NULL;
1201    struct config_fs_cache_s *cur_config_cache = NULL;
1202    struct host_handle_mapping_s *server_mapping = NULL;
1203
1204    *handle_count = 0;
1205
1206    assert(PINT_fsid_config_cache_table);
1207
1208    /* for each fs find the right server */
1209    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fs_id));
1210    if (hash_link)
1211    {
1212        cur_config_cache = qlist_entry(
1213            hash_link, struct config_fs_cache_s, hash_link);
1214
1215        assert(cur_config_cache);
1216        assert(cur_config_cache->fs);
1217
1218        server_mapping = PINT_cached_config_find_server(
1219            cur_config_cache->fs->meta_handle_ranges, server_addr_str);
1220        if(server_mapping)
1221        {
1222            *handle_count += PINT_extent_array_count_total(
1223                &server_mapping->handle_extent_array);
1224        }
1225
1226        server_mapping = PINT_cached_config_find_server(
1227            cur_config_cache->fs->data_handle_ranges, server_addr_str);
1228        if(server_mapping)
1229        {
1230            *handle_count += PINT_extent_array_count_total(
1231                &server_mapping->handle_extent_array);
1232        }
1233    }
1234    return 0;
1235}
1236
1237/* PINT_cached_config_get_server_name()
1238 *
1239 * discovers the string (BMI url) name of a server that controls the
1240 * specified cached_config.
1241 *
1242 * returns 0 on success, -errno on failure
1243 */
1244int PINT_cached_config_get_server_name(
1245    char *server_name,
1246    int max_server_name_len,
1247    PVFS_handle handle,
1248    PVFS_fs_id fsid)
1249{
1250    const struct handle_lookup_entry* tmp_entry;
1251
1252    tmp_entry = find_handle_lookup_entry(handle, fsid);
1253
1254    if(!tmp_entry)
1255    {
1256        gossip_err("Error: failed to find handle %llu in fs configuration.\n",
1257            llu(handle));
1258        return(-PVFS_EINVAL);
1259    }
1260
1261    strncpy(server_name, tmp_entry->server_name, max_server_name_len);
1262    return(0);
1263}
1264
1265/* PINT_cached_config_get_root_handle()
1266 *
1267 * return the root handle of any valid filesystem
1268 *
1269 * returns 0 on success -errno on failure
1270 *
1271 */
1272int PINT_cached_config_get_root_handle(
1273    PVFS_fs_id fsid,
1274    PVFS_handle *fh_root)
1275{
1276    int ret = -PVFS_EINVAL;
1277    struct qlist_head *hash_link = NULL;
1278    struct config_fs_cache_s *cur_config_cache = NULL;
1279
1280    if (fh_root)
1281    {
1282        hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1283        if (hash_link)
1284        {
1285            cur_config_cache = qlist_entry(
1286                hash_link, struct config_fs_cache_s, hash_link);
1287
1288            assert(cur_config_cache);
1289            assert(cur_config_cache->fs);
1290
1291            *fh_root = (PVFS_handle)cur_config_cache->fs->root_handle;
1292            ret = 0;
1293        }
1294    }
1295    return ret;
1296}
1297
1298int PINT_cached_config_get_handle_timeout(
1299    PVFS_fs_id fsid,
1300    struct timeval *timeout)
1301{
1302    int ret = -PVFS_EINVAL;
1303    struct qlist_head *hash_link = NULL;
1304    struct config_fs_cache_s *cur_config_cache = NULL;
1305
1306    hash_link = qhash_search(PINT_fsid_config_cache_table, &(fsid));
1307    if(hash_link)
1308    {
1309        cur_config_cache = qlist_entry(
1310            hash_link, struct config_fs_cache_s, hash_link);
1311
1312        assert(cur_config_cache);
1313        assert(cur_config_cache->fs);
1314
1315        timeout->tv_sec =
1316            cur_config_cache->fs->handle_recycle_timeout_sec.tv_sec;
1317        timeout->tv_usec =
1318            cur_config_cache->fs->handle_recycle_timeout_sec.tv_usec;
1319        ret = 0;
1320    }
1321    return ret;
1322}
1323
1324int PINT_cached_config_get_server_list(
1325    PVFS_fs_id fs_id,
1326    PINT_dist *dist,
1327    int num_dfiles_req,
1328    PVFS_sys_layout *layout,
1329    const char ***server_names,
1330    int *server_count)
1331{
1332    int num_io_servers, ret, i;
1333    PVFS_BMI_addr_t *server_addrs;
1334    const char **servers;
1335
1336    /* find the server list from the layout */
1337    ret = PINT_cached_config_get_num_dfiles(
1338        fs_id,
1339        dist,
1340        num_dfiles_req,
1341        &num_io_servers);
1342    if (ret < 0)
1343    {
1344        gossip_err("Failed to get number of data servers\n");
1345        return ret;
1346    }
1347
1348    if(num_io_servers > PVFS_REQ_LIMIT_DFILE_COUNT)
1349    {
1350        num_io_servers = PVFS_REQ_LIMIT_DFILE_COUNT;
1351        gossip_err("Warning: reducing number of data "
1352                     "files to PVFS_REQ_LIMIT_DFILE_COUNT\n");
1353    }
1354
1355    server_addrs = malloc(sizeof(*server_addrs) * num_io_servers);
1356    if(!server_addrs)
1357    {
1358        gossip_err("Failed to allocate server address list\n");
1359        return -PVFS_ENOMEM;
1360    }
1361
1362    ret = PINT_cached_config_map_servers(
1363        fs_id,
1364        &num_io_servers,
1365        layout,
1366        server_addrs,
1367        NULL);
1368    if(ret != 0)
1369    {
1370        gossip_err("Failed to get IO server addrs from layout\n");
1371        return ret;
1372    }
1373
1374    servers = malloc(sizeof(*servers) * num_io_servers);
1375    if(!servers)
1376    {
1377        gossip_err("Failed to allocate server address list\n");
1378        free(server_addrs);
1379        return -PVFS_ENOMEM;
1380    }
1381
1382    for(i = 0; i < num_io_servers; ++i)
1383    {
1384        servers[i] = BMI_addr_rev_lookup(server_addrs[i]);
1385    }
1386    free(server_addrs);
1387
1388    *server_count = num_io_servers;
1389    *server_names = servers;
1390
1391    return 0;
1392}
1393
1394/* cache_server_array()
1395 *
1396 * verifies that the arrays of physical server addresses have been
1397 * cached in the configuration structs
1398 *
1399 * returns 0 on success, -errno on failure
1400 */
1401static int cache_server_array(
1402    PVFS_fs_id fsid)
1403{
1404    int ret = -PVFS_EINVAL, i = 0, j = 0;
1405    char *server_bmi_str = NULL;
1406    struct host_handle_mapping_s *cur_mapping = NULL;
1407    struct qlist_head *hash_link = NULL;
1408    struct config_fs_cache_s *cur_config_cache = NULL;
1409    PINT_llist *tmp_server = NULL;
1410    PVFS_BMI_addr_t tmp_bmi_addr;
1411    int dup_flag = 0;
1412    int current = 0;
1413    int array_index = 0, array_index2 = 0;
1414
1415    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1416    if (!hash_link)
1417    {
1418        return ret;
1419    }
1420    cur_config_cache = qlist_entry(
1421        hash_link, struct config_fs_cache_s, hash_link);
1422
1423    assert(cur_config_cache);
1424    assert(cur_config_cache->fs);
1425
1426    /* first check to see if we have the array information cached */
1427    if (cur_config_cache->server_count < 1)
1428    {
1429        /* we need to fill in this stuff in our config cache */
1430        cur_config_cache->server_count = 0;
1431        cur_config_cache->meta_server_count = 0;
1432        cur_config_cache->io_server_count = 0;
1433
1434        /* iterate through lists to come up with an upper bound for
1435         * the size of the arrays that we need
1436         */
1437        tmp_server = cur_config_cache->fs->meta_handle_ranges;
1438        while ((cur_mapping = PINT_llist_head(tmp_server)))
1439        {
1440            tmp_server = PINT_llist_next(tmp_server);
1441            cur_config_cache->meta_server_count++;
1442            cur_config_cache->server_count++;
1443        }
1444        tmp_server = cur_config_cache->fs->data_handle_ranges;
1445        while ((cur_mapping = PINT_llist_head(tmp_server)))
1446        {
1447            tmp_server = PINT_llist_next(tmp_server);
1448            cur_config_cache->io_server_count++;
1449            cur_config_cache->server_count++;
1450        }
1451
1452        cur_config_cache->meta_server_array = (phys_server_desc_s*)malloc(
1453            (cur_config_cache->meta_server_count *
1454             sizeof(phys_server_desc_s)));
1455        cur_config_cache->io_server_array = (phys_server_desc_s*)malloc(
1456            (cur_config_cache->io_server_count*
1457             sizeof(phys_server_desc_s)));
1458        cur_config_cache->server_array = (phys_server_desc_s*)malloc(
1459            (cur_config_cache->server_count*
1460             sizeof(phys_server_desc_s)));
1461
1462        if ((cur_config_cache->meta_server_array == NULL) ||
1463            (cur_config_cache->io_server_array == NULL) ||
1464            (cur_config_cache->server_array == NULL))
1465        {
1466            ret = -PVFS_ENOMEM;
1467            goto cleanup_allocations;
1468        }
1469        memset(cur_config_cache->server_array, 0,
1470               (cur_config_cache->server_count *
1471                sizeof(phys_server_desc_s)));
1472
1473        /* reset counts until we find out how many physical servers
1474         * are actually present
1475         */
1476        cur_config_cache->server_count = 0;
1477        cur_config_cache->meta_server_count = 0;
1478        cur_config_cache->io_server_count = 0;
1479
1480        for(i = 0; i < 2; i++)
1481        {
1482            if (i == 0)
1483            {
1484                tmp_server = cur_config_cache->fs->meta_handle_ranges;
1485                current = PINT_SERVER_TYPE_META;
1486            }
1487            else
1488            {
1489                tmp_server = cur_config_cache->fs->data_handle_ranges;
1490                current = PINT_SERVER_TYPE_IO;
1491            }
1492            while ((cur_mapping = PINT_llist_head(tmp_server)))
1493            {
1494                tmp_server = PINT_llist_next(tmp_server);
1495                server_bmi_str = cur_mapping->alias_mapping->bmi_address;
1496
1497                ret = BMI_addr_lookup(&tmp_bmi_addr,server_bmi_str);
1498                if (ret < 0)
1499                {
1500                    return(ret);
1501                }
1502
1503                /* see if we have already listed this BMI address */
1504                dup_flag = 0;
1505                for (j=0; j < array_index; j++)
1506                {
1507                    if (cur_config_cache->server_array[j].addr ==
1508                        tmp_bmi_addr)
1509                    {
1510                        cur_config_cache->server_array[j].server_type
1511                            |= current;
1512                        dup_flag = 1;
1513                        break;
1514                    }
1515                }
1516               
1517                if (!dup_flag)
1518                {
1519                    cur_config_cache->server_array[array_index].addr =
1520                        tmp_bmi_addr;
1521                    cur_config_cache->server_array[
1522                        array_index].addr_string = server_bmi_str;
1523                    cur_config_cache->server_array[
1524                        array_index].server_type = current;
1525                    array_index++;
1526                    cur_config_cache->server_count = array_index;
1527                }
1528            }
1529        }
1530
1531        /* now build meta and I/O arrays based on generic server list */
1532        array_index = 0;
1533        array_index2 = 0;
1534        for(i = 0; i < cur_config_cache->server_count; i++)
1535        {
1536            if (cur_config_cache->server_array[i].server_type &
1537                PINT_SERVER_TYPE_META)
1538            {
1539                cur_config_cache->meta_server_array[array_index] =
1540                    cur_config_cache->server_array[i];
1541                array_index++;
1542            }
1543            if (cur_config_cache->server_array[i].server_type &
1544                PINT_SERVER_TYPE_IO)
1545            {
1546                cur_config_cache->io_server_array[array_index2] =
1547                    cur_config_cache->server_array[i];
1548                array_index2++;
1549            }
1550        }
1551        cur_config_cache->meta_server_count = array_index;
1552        cur_config_cache->io_server_count = array_index2;
1553    }
1554    return 0;
1555
1556  cleanup_allocations:
1557    if (cur_config_cache->meta_server_array)
1558    {
1559        free(cur_config_cache->meta_server_array);
1560    }
1561    if (cur_config_cache->io_server_array)
1562    {
1563        free(cur_config_cache->io_server_array);
1564    }
1565    if (cur_config_cache->server_array)
1566    {
1567        free(cur_config_cache->server_array);
1568    }
1569    return ret;
1570}
1571
1572/* hash_fsid()
1573 *
1574 * hash function for fsids added to table
1575 *
1576 * returns integer offset into table
1577 */
1578static int hash_fsid(void *fsid, int table_size)
1579{
1580    unsigned long tmp = 0;
1581    PVFS_fs_id *real_fsid = (PVFS_fs_id *)fsid;
1582
1583    assert(PINT_fsid_config_cache_table);
1584
1585    tmp += (*(real_fsid));
1586    tmp = tmp%table_size;
1587
1588    return ((int) tmp);
1589}
1590
1591/* hash_fsid_compare()
1592 *
1593 * performs a comparison of a hash table entro to a given key (used
1594 * for searching)
1595 *
1596 * returns 1 if match found, 0 otherwise
1597 */
1598static int hash_fsid_compare(void *key, struct qlist_head *link)
1599{
1600    struct config_fs_cache_s *fs_info = NULL;
1601    PVFS_fs_id *real_fsid = (PVFS_fs_id *)key;
1602
1603    assert(PINT_fsid_config_cache_table);
1604
1605    fs_info = qlist_entry(link, struct config_fs_cache_s, hash_link);
1606    if ((PVFS_fs_id)fs_info->fs->coll_id == *real_fsid)
1607    {
1608        return 1;
1609    }
1610    return 0;
1611}
1612
1613/* handle_lookup_entry_compare()
1614 *  *
1615 *   * comparison function used by qsort()
1616 *    */
1617static int handle_lookup_entry_compare(const void *p1, const void *p2)
1618{
1619    const struct handle_lookup_entry* e1  = p1;
1620    const struct handle_lookup_entry* e2  = p2;
1621
1622    if(e1->extent.first < e2->extent.first)
1623        return(-1);
1624    if(e1->extent.first > e2->extent.first)
1625        return(1);
1626
1627    return(0);
1628}
1629
1630/* find_handle_lookup_entry()
1631 *
1632 * searches sorted table for extent that contains the specified handle
1633 *
1634 * returns pointer to table entry on success, NULL on failure
1635 */
1636static const struct handle_lookup_entry* find_handle_lookup_entry(
1637    PVFS_handle handle, PVFS_fs_id fsid)
1638{
1639    struct qlist_head *hash_link = NULL;
1640    struct config_fs_cache_s *cur_config_cache = NULL;
1641    int high, low, mid;
1642    int table_index;
1643
1644    assert(PINT_fsid_config_cache_table);
1645
1646    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1647    if(!hash_link)
1648    {
1649        return(NULL);
1650    }
1651
1652    cur_config_cache = qlist_entry(
1653        hash_link, struct config_fs_cache_s, hash_link);
1654
1655    assert(cur_config_cache);
1656    assert(cur_config_cache->fs);
1657
1658    /* iterative binary search through handle lookup table to find the
1659     * extent that this handle falls into
1660     */
1661    low = 0;
1662    high = cur_config_cache->handle_lookup_table_size;
1663    while (low < high)
1664    {
1665        mid = (low + high)/2;
1666        if (cur_config_cache->handle_lookup_table[mid].extent.first < handle)
1667            low = mid + 1;
1668        else
1669            high = mid;
1670    }
1671    if ((low < cur_config_cache->handle_lookup_table_size) &&
1672        (cur_config_cache->handle_lookup_table[low].extent.first == handle))
1673    {
1674        /* we happened to locate the first handle in a range */
1675        table_index = low;
1676    }
1677    else
1678    {
1679        /* this handle must fall into the previous range if any */
1680        table_index = low-1;
1681    }
1682
1683    /* confirm match */
1684    if(PINT_handle_in_extent(
1685        &cur_config_cache->handle_lookup_table[table_index].extent,
1686        handle))
1687    {
1688        return(&cur_config_cache->handle_lookup_table[table_index]);
1689    }
1690
1691    /* no match */
1692    return(NULL);
1693}
1694
1695/* load_handle_lookup_table()
1696 *
1697 * iterates through extents for all servers and constructs a table sorted by
1698 * the first handle in each extent.  This table can then be searched with a
1699 * binary algorithm to map handles to servers.  Table includes extent,
1700 * server name, and server's resolved bmi address.
1701 *
1702 * returns 0 on success, -PVFS_error on failure
1703 */
1704static int load_handle_lookup_table(
1705    struct config_fs_cache_s *cur_config_fs_cache)
1706{
1707    int ret = -PVFS_EINVAL;
1708    host_handle_mapping_s *cur_mapping = NULL;
1709    int count = 0;
1710    int table_offset = 0;
1711    PINT_llist* server_cursor;
1712    int i;
1713    int j;
1714    PINT_llist* range_list[2] =
1715    {
1716        cur_config_fs_cache->fs->meta_handle_ranges,
1717        cur_config_fs_cache->fs->data_handle_ranges
1718    };
1719
1720    /* count total number of extents */
1721    /* loop through both meta and data ranges */
1722    for(j=0; j<2; j++)
1723    {
1724        server_cursor = range_list[j];
1725        cur_mapping = PINT_llist_head(server_cursor);
1726        while(cur_mapping)
1727        {
1728            /* each server may have multiple extents */
1729            for(i=0; i<cur_mapping->handle_extent_array.extent_count; i++)
1730            {
1731                count += 1;
1732            }
1733            server_cursor = PINT_llist_next(server_cursor);
1734            cur_mapping = PINT_llist_head(server_cursor);
1735        }
1736    }
1737
1738    /* allocate a table to hold all extents for faster searching */
1739    if(cur_config_fs_cache->handle_lookup_table)
1740    {
1741        free(cur_config_fs_cache->handle_lookup_table);
1742    }
1743    cur_config_fs_cache->handle_lookup_table =
1744        malloc(sizeof(*cur_config_fs_cache->handle_lookup_table) * count);
1745    if(!cur_config_fs_cache->handle_lookup_table)
1746    {
1747        return(-PVFS_ENOMEM);
1748    }
1749    cur_config_fs_cache->handle_lookup_table_size = count;
1750
1751    /* populate table */
1752    /* loop through both meta and data ranges */
1753    for(j=0; j<2; j++)
1754    {
1755        server_cursor = range_list[j];
1756        cur_mapping = PINT_llist_head(server_cursor);
1757        while(cur_mapping)
1758        {
1759            for(i=0; i<cur_mapping->handle_extent_array.extent_count; i++)
1760            {
1761                cur_config_fs_cache->handle_lookup_table[table_offset].extent
1762                    = cur_mapping->handle_extent_array.extent_array[i];
1763                cur_config_fs_cache->handle_lookup_table[table_offset].server_name
1764                    = cur_mapping->alias_mapping->bmi_address;
1765                ret = BMI_addr_lookup(
1766                    &cur_config_fs_cache->handle_lookup_table[table_offset].server_addr,                 
1767                    cur_config_fs_cache->handle_lookup_table[table_offset].server_name);
1768                if(ret < 0)
1769                {
1770                    free(cur_config_fs_cache->handle_lookup_table);
1771                    gossip_err("Error: failed to resolve address of server: %s\n",
1772                        cur_config_fs_cache->handle_lookup_table[table_offset].server_name);
1773                    return(ret);
1774                }
1775                table_offset++;
1776            }
1777            server_cursor = PINT_llist_next(server_cursor);
1778            cur_mapping = PINT_llist_head(server_cursor);
1779        }
1780    }
1781
1782    /* sort table */
1783    qsort(cur_config_fs_cache->handle_lookup_table, table_offset,
1784        sizeof(*cur_config_fs_cache->handle_lookup_table),
1785        handle_lookup_entry_compare);
1786
1787    return(0);
1788}
1789
1790/* PINT_cached_config_server_names()
1791 *
1792 * Returns a list of pointers to the IO server names currently running in this   
1793 * file system.
1794 *
1795 * returns 0 on success, -PVFS_error on failure
1796 */
1797int PINT_cached_config_io_server_names( char ***list
1798                                      , int *size
1799                                      , PVFS_fs_id fsid)
1800{
1801    int i;
1802    struct qlist_head *hash_link = NULL;
1803    struct config_fs_cache_s *cur_config_cache = NULL;
1804
1805    assert(PINT_fsid_config_cache_table);
1806
1807    hash_link = qhash_search(PINT_fsid_config_cache_table,&(fsid));
1808    if(!hash_link)
1809    {
1810        return(-PVFS_ENOENT);
1811    }
1812
1813    cur_config_cache = qlist_entry(
1814        hash_link, struct config_fs_cache_s, hash_link);
1815
1816    assert(cur_config_cache);
1817
1818    *size = cur_config_cache->io_server_count;
1819
1820    *list = malloc(sizeof(char *) * (*size));
1821
1822    if (! (*list) )
1823       return(-PVFS_ENOMEM);
1824
1825    memset(*list,0,sizeof(char *) * (*size));
1826
1827    for (i=0; i<(*size); i++)
1828    {
1829        /*addr_string originates from the alias mapping->bmi_address*/
1830        (*list)[i] = cur_config_cache->io_server_array[i].addr_string;
1831    }
1832
1833   return(0);
1834}
1835
1836/*
1837 * Local variables:
1838 *  c-indent-level: 4
1839 *  c-basic-offset: 4
1840 * End:
1841 *
1842 * vim: ts=8 sts=4 sw=4 expandtab
1843 */
Note: See TracBrowser for help on using the browser.