source: tags/svn.1.5.4/ARBDB/adtcp.cxx

Last change on this file was 8041, checked in by westram, 14 years ago

merge from dev [7990] [7991] [7992] [7993] [7994] [7995] [7996] [7998] [8001] [8003] [8005] [8006] [8007] [8008] [8009] [8011] [8012] [8019]

  • added a faked ecoli to ptserver test-db
  • added unit-tests for gene-ptserver
  • rename ptserver testdb
  • ptserver db-cleanup
    • size of mapfile for SSUREF108 is reduced by 85% (3,4Gb → 519Mb)
  • ptserver
    • refactored
      • prefix tree builders
      • probe_input_data
    • removed ptnd_new_match (dead code)
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 17.7 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : adtcp.cxx                                         //
4//   Purpose   : arb_tcp.dat handling                              //
5//                                                                 //
6//   Coded by Ralf Westram (coder@reallysoft.de) in April 2007     //
7//   Institute of Microbiology (Technical University Munich)       //
8//   http://www.arb-home.de/                                       //
9//                                                                 //
10// =============================================================== //
11
12#include <ctime>
13#include <sys/stat.h>
14
15#include <arbdbt.h>
16#include <arb_str.h>
17
18#include "gb_local.h"
19
20#if defined(DEBUG)
21// #define DUMP_ATD_ACCESS
22#endif // DEBUG
23
24// ------------------------------------------------------------
25// Data representing current content of arb_tcp.dat
26
27class ArbTcpDat : virtual Noncopyable {
28    GB_ULONG  modtime;                              // modification time of read-in arb_tcp.dat
29    char     *filename;                             // pathname of loaded arb_tcp.dat
30
31    char **content; /* zero-pointer terminated array of multi-separated strings
32                     * (strings have same format as the result of
33                     * GBS_read_arb_tcp(), but also contain the first element,
34                     * i.e. the server id)
35                     */
36    int serverCount;
37   
38
39    void freeContent() {
40        if (content) {
41            for (int c = 0; content[c]; c++) free(content[c]);
42            freenull(content);
43        }
44    }
45    GB_ERROR read(int *versionFound);
46
47public:
48    ArbTcpDat() : modtime(-1) , filename(NULL) , content(NULL), serverCount(-1) { }
49
50    ~ArbTcpDat() {
51        free(filename);
52        freeContent();
53    }
54
55    GB_ERROR update();
56
57    int get_server_count() const { return serverCount; }
58    const char *get_serverID(int idx) const { gb_assert(idx >= 0 && idx<serverCount); return content[idx]; }
59    const char *get_entry(const char *serverID) const;
60    const char *get_filename() const { return filename; }
61
62#if defined(DUMP_ATD_ACCESS)
63    void dump();
64#endif
65};
66
67const char *ArbTcpDat::get_entry(const char *serverID) const {
68    const char *result = 0;
69    if (content) {
70        int c;
71        for (c = 0; content[c]; c++) {
72            const char *id = content[c];
73
74            if (strcmp(id, serverID) == 0) {
75                result = strchr(id, 0)+1; // return pointer to first parameter
76                break;
77            }
78        }
79    }
80    return result;
81}
82
83#if defined(DUMP_ATD_ACCESS)
84void ArbTcpDat::dump() {
85    printf("filename='%s'\n", filename);
86    printf("modtime='%lu'\n", modtime);
87    if (content) {
88        int c;
89        for (c = 0; content[c]; c++) {
90            char *data = content[c];
91            char *tok  = data;
92            printf("Entry #%i:\n", c);
93
94            while (tok[0]) {
95                printf("- '%s'\n", tok);
96                tok = strchr(tok, 0)+1;
97            }
98        }
99    }
100    else {
101        printf("No content\n");
102    }
103}
104#endif // DUMP_ATD_ACCESS
105
106#define MAXLINELEN 512
107#define MAXTOKENS  10
108
109GB_ERROR ArbTcpDat::read(int *versionFound) {
110    // used to read arb_tcp.dat or arb_tcp_org.dat
111    GB_ERROR  error = 0;
112    FILE     *in    = fopen(filename, "rt");
113
114    *versionFound = 1; // default to version 1 (old format)
115
116#if defined(DUMP_ATD_ACCESS)
117    printf("(re)reading %s\n", filename);
118#endif // DUMP_ATD_ACCESS
119
120    freeContent();
121
122    if (!in) {
123        error = GBS_global_string("Can't read '%s'", filename);
124    }
125    else {
126        char   buffer[MAXLINELEN+1];
127        char  *lp;
128        int    lineNumber = 0;
129        char **tokens     = (char**)malloc(MAXTOKENS*sizeof(*tokens));
130
131        int    entries_allocated = 30;
132        int    entries           = 0;
133        char **entry             = (char**)malloc(entries_allocated*sizeof(*entry));
134
135        if (!tokens || !entry) error = "Out of memory";
136
137        for (lp = fgets(buffer, MAXLINELEN, in);
138             lp && !error;
139             lp = fgets(buffer, MAXLINELEN, in))
140        {
141            char *tok;
142            int   tokCount = 0;
143            int   t;
144
145            lineNumber++;
146
147            while ((tok = strtok(lp, " \t\n"))) {
148                if (tok[0] == '#') break; // EOL comment -> stop
149                if (tokCount >= MAXTOKENS) { error = "Too many tokens"; break; }
150                tokens[tokCount] = tokCount ? GBS_eval_env(tok) : strdup(tok);
151                if (!tokens[tokCount]) { error = GB_await_error(); break; }
152                tokCount++;
153                lp = 0;
154            }
155
156            if (!error && tokCount>0) {
157                if (strcmp(tokens[0], "ARB_TCP_DAT_VERSION") == 0) {
158                    if (tokCount>1) *versionFound = atoi(tokens[1]);
159                }
160                else {
161                    char *data;
162                    {
163                        int allsize = 0;
164                        int size[MAXTOKENS];
165
166                        for (t = 0; t<tokCount; t++) {
167                            size[t]  = strlen(tokens[t])+1;
168                            allsize += size[t];
169                        }
170                        allsize++;      // additional zero byte
171
172                        data = (char*)malloc(allsize);
173                        {
174                            char *d = data;
175                            for (t = 0; t<tokCount; t++) {
176                                memmove(d, tokens[t], size[t]);
177                                d += size[t];
178                            }
179                            d[0] = 0;
180                        }
181                    }
182
183                    if (entries == entries_allocated) {
184                        entries_allocated = (int)(entries_allocated*1.5);
185                        char **entry2     = (char**)realloc(entry, entries_allocated*sizeof(*entry));
186
187                        if (!entry2) error = "Out of memory";
188                        else entry = entry2;
189                    }
190                    if (!error) {
191                        entry[entries++] = data;
192                        data             = 0;
193                    }
194                    free(data);
195                }
196            }
197
198            if (error) error = GBS_global_string("%s (in line %i of '%s')", error, lineNumber, filename);
199            for (t = 0; t<tokCount; t++) freenull(tokens[t]);
200        }
201
202        content = (char**)realloc(entry, (entries+1)*sizeof(*entry));
203        if (!content) {
204            error   = "Out of memory";
205            serverCount = 0;
206        }
207        else {
208            content[entries] = 0;
209            serverCount      = entries;
210        }
211
212        free(tokens);
213        fclose(in);
214    }
215
216#if defined(DUMP_ATD_ACCESS)
217    dump();
218#endif // DUMP_ATD_ACCESS
219    return error;
220}
221
222char *GB_arbtcpdat_path() {
223    return GB_lib_file(true, "", "arb_tcp.dat");
224}
225
226GB_ERROR ArbTcpDat::update() {
227    // read arb_tcp.dat (once or if changed on disk)
228    GB_ERROR error = 0;
229
230    if (!filename) filename = GB_arbtcpdat_path();
231
232    if (!filename) {
233        error = "File $ARBHOME/lib/arb_tcp.dat missing or unreadable";
234    }
235    else {
236        struct stat st;
237        if (stat(filename, &st) == 0) {
238            GB_ULONG mtime = st.st_mtime;
239            if (modtime != mtime) { // read once or when changed
240                int arb_tcp_version;
241                error = read(&arb_tcp_version);
242
243                if (!error) {
244                    int expected_version = 2;
245                    if (arb_tcp_version != expected_version) {
246                        error = GBS_global_string("Expected arb_tcp.dat version %i\n"
247                                                  "Your '%s' has version %i\n"
248                                                  "To solve the problem\n"
249                                                  "- either reinstall ARB and do not select\n"
250                                                  "  'Use information of already installed ARB'\n"
251                                                  "  (any changes to arb_tcp.dat will be lost)\n"
252                                                  "- or backup your changed %s,\n"
253                                                  "  replace it by the contents from $ARBHOME/lib/arb_tcp_org.dat\n"
254                                                  "  and edit it to fit your needs.",
255                                                  expected_version,
256                                                  filename, arb_tcp_version,
257                                                  filename);
258                    }
259                }
260                modtime = error ? -1 : mtime;
261            }
262        }
263        else {
264            error = GBS_global_string("Can't stat '%s'", filename);
265        }
266    }
267   
268    if (error) freenull(filename);
269
270#if defined(DUMP_ATD_ACCESS)
271    printf("error=%s\n", error);
272#endif // DUMP_ATD_ACCESS
273
274    return error;
275}
276
277static ArbTcpDat arb_tcp_dat;
278
279// --------------------------------------------------------------------------------
280
281const char *GBS_scan_arb_tcp_param(const char *ipPort, const char *wantedParam) {
282    /* search a specific server parameter in result from GBS_read_arb_tcp()
283     * wantedParam may be sth like '-d' (case is ignored!)
284     */
285    const char *result = 0;
286    if (ipPort) {
287        const char *exe   = strchr(ipPort, 0)+1;
288        const char *param = strchr(exe, 0)+1;
289        size_t      plen  = strlen(param);
290        size_t      wplen = strlen(wantedParam);
291
292        while (plen) {
293            if (strncasecmp(param, wantedParam, wplen) == 0) { // starts with wantedParam
294                result = param+wplen;
295                break;
296            }
297            param += plen+1;    // position behind 0-delimiter
298            plen   = strlen(param);
299        }
300    }
301    return result;
302}
303
304// AISC_MKPT_PROMOTE:#ifdef UNIT_TESTS
305// AISC_MKPT_PROMOTE:#define TEST_SERVER_ID (-666)
306// AISC_MKPT_PROMOTE:#define TEST_GENESERVER_ID (-667)
307// AISC_MKPT_PROMOTE:#endif
308
309const char *GBS_nameserver_tag(const char *add_field) {
310    if (add_field && add_field[0]) {
311        char *tag = GBS_global_string_copy("ARB_NAME_SERVER_%s", add_field);
312        ARB_strupper(tag);
313        RETURN_LOCAL_ALLOC(tag);
314    }
315    return "ARB_NAME_SERVER";
316}
317
318const char *GBS_ptserver_tag(int id) {
319#ifdef UNIT_TESTS
320    if (id == TEST_SERVER_ID) return "ARB_TEST_PT_SERVER";
321    if (id == TEST_GENESERVER_ID) return "ARB_TEST_PT_SERVER_GENE";
322#endif // UNIT_TESTS
323    gb_assert(id >= 0);
324    const int   MAXIDSIZE = 30;
325    static char server_tag[MAXIDSIZE];
326    // ASSERT_RESULT_BELOW(int, sprintf(server_tag, "ARB_PT_SERVER%i", id), MAXIDSIZE);
327    ASSERT_RESULT_PREDICATE(isBelow<int>(MAXIDSIZE), sprintf(server_tag, "ARB_PT_SERVER%i", id));
328    return server_tag;
329}
330
331const char *GBS_read_arb_tcp(const char *env) {
332    /*! Find an entry in the $ARBHOME/lib/arb_tcp.dat file
333     *
334     * Be aware: GBS_read_arb_tcp returns a quite unusual string containing several string delimiters (0-characters).
335     * It contains all words (separated by space or tab in arb_tcp.dat) of the corresponding line in arb_tcp.dat.
336     * These words get concatenated (separated by 0 characters).
337     *
338     * The first word (which matches the parameter env) is skipped.
339     * The second word (the socket info = "host:port") is returned directly as result.
340     * The third word is the server executable name.
341     * The fourth and following words are parameters to the executable.
342     *
343     * To access these words follow this example:
344     *
345     * const char *ipPort = GBS_read_arb_tcp(GBS_nameserver_tag(NULL));
346     * if (ipPort) {
347     *     const char *serverExe = strchr(ipPort, 0)+1;
348     *     const char *para1     = strchr(serverExe, 0)+1; // always exists!
349     *     const char *para2     = strchr(para1, 0)+1;
350     *     if (para2[0]) {
351     *         // para2 exists
352     *     }
353     * }
354     *
355     * see also GBS_read_arb_tcp_param() above
356     *
357     * Returns NULL on error (which is exported in that case)
358     */
359
360    const char *result = 0;
361    GB_ERROR    error  = 0;
362
363    if (strchr(env, ':')) {
364        static char *resBuf = 0;
365        freedup(resBuf, env);
366        result = resBuf;
367    }
368    else {
369        error = arb_tcp_dat.update(); // load once or reload after change on disk
370        if (!error) {
371            const char *user = GB_getenvUSER();
372            if (!user) {
373                error = "Environment variable 'USER' not defined";
374            }
375            else {
376                char *envuser = GBS_global_string_copy("%s:%s", user, env);
377                result        = arb_tcp_dat.get_entry(envuser);
378
379                if (!result) { // no user-specific entry found
380                    result = arb_tcp_dat.get_entry(env);
381                    if (!result) {
382                        error = GBS_global_string("Expected entry '%s' or '%s' in '%s'",
383                                                  env, envuser, arb_tcp_dat.get_filename());
384                    }
385                }
386                free(envuser);
387            }
388        }
389    }
390
391    gb_assert(result||error);
392    if (error) {
393        GB_export_error(error);
394        result = 0;
395    }
396    return result;
397}
398
399const char * const *GBS_get_arb_tcp_entries(const char *matching) {
400    /*! returns a list of all matching non-user-specific entries found in arb_tcp.dat
401     * match is performed by GBS_string_matches (e.g. use "ARB_PT_SERVER*")
402     */
403    static const char **matchingEntries     = 0;
404    static int          matchingEntriesSize = 0;
405
406    GB_ERROR error = 0;
407
408    error = arb_tcp_dat.update();
409    if (!error) {
410        int count = arb_tcp_dat.get_server_count();
411
412        if (matchingEntriesSize != count) {
413            freeset(matchingEntries, (const char **)malloc((count+1)*sizeof(*matchingEntries)));
414            matchingEntriesSize = count;
415        }
416
417        int matched = 0;
418        for (int c = 0; c<count; c++) {
419            const char *id = arb_tcp_dat.get_serverID(c);
420
421            if (strchr(id, ':') == 0) { // not user-specific
422                if (GBS_string_matches(id, matching, GB_MIND_CASE)) { // matches
423                    matchingEntries[matched++] = id;
424                }
425            }
426        }
427        matchingEntries[matched] = 0; // end of array
428    }
429    if (error) GB_export_error(error);
430    return error ? 0 : matchingEntries;
431}
432
433// ---------------------------
434//      pt server related
435
436const char *GBS_ptserver_logname() {
437    RETURN_ONETIME_ALLOC(nulldup(GB_path_in_ARBLIB("pts/ptserver.log")));
438}
439
440void GBS_add_ptserver_logentry(const char *entry) {
441    FILE *log = fopen(GBS_ptserver_logname(), "at");
442    if (log) {
443        chmod(GBS_ptserver_logname(), 0666);
444
445        char    atime[256];
446        time_t  t   = time(0);
447        tm     *tms = localtime(&t);
448
449        strftime(atime, 255, "%Y/%m/%d %k:%M:%S", tms);
450        fprintf(log, "%s %s\n", atime, entry);
451        fclose(log);
452    }
453    else {
454        fprintf(stderr, "Failed to write to '%s'\n", GBS_ptserver_logname());
455    }
456}
457
458char *GBS_ptserver_id_to_choice(int i, int showBuild) {
459    /* Return a readable name for PTserver number 'i'
460     * If 'showBuild' then show build info as well.
461     *
462     * Return NULL in case of error (which was exported then)
463     */
464    const char *ipPort = GBS_read_arb_tcp(GBS_ptserver_tag(i));
465    char       *result = 0;
466
467    if (ipPort) {
468        const char *file     = GBS_scan_arb_tcp_param(ipPort, "-d");
469        const char *nameOnly = strrchr(file, '/');
470
471        if (nameOnly) nameOnly++;   // position behind '/'
472        else nameOnly = file;       // otherwise show complete file
473
474        {
475            char *remote      = strdup(ipPort);
476            char *colon       = strchr(remote, ':');
477            if (colon) *colon = 0; // hide port
478
479            if (strcmp(remote, "localhost") == 0) { // hide localhost
480                result = nulldup(nameOnly);
481            }
482            else {
483                result = GBS_global_string_copy("%s: %s", remote, nameOnly);
484            }
485            free(remote);
486        }
487
488
489        if (showBuild) {
490            struct stat  st;
491
492            if (stat(file, &st) == 0) { // xxx.arb present
493                time_t  fileMod   = st.st_mtime;
494                char   *serverDB  = GBS_global_string_copy("%s.pt", file);
495                char   *newResult = 0;
496
497                if (stat(serverDB, &st) == 0) { // pt-database present
498                    if (st.st_mtime < fileMod) { // DB is newer than pt-database
499                        newResult = GBS_global_string_copy("%s [starting or failed update]", result);
500                    }
501                    else {
502                        char  atime[256];
503                        tm   *tms = localtime(&st.st_mtime);
504
505                        strftime(atime, 255, "%Y/%m/%d %k:%M", tms);
506                        newResult = GBS_global_string_copy("%s [%s]", result, atime);
507                    }
508                }
509                else { // check for running build
510                    char *serverDB_duringBuild = GBS_global_string_copy("%s%%", serverDB);
511                    if (stat(serverDB_duringBuild, &st) == 0) {
512                        newResult = GBS_global_string_copy("%s [building..]", result);
513                    }
514                    free(serverDB_duringBuild);
515                }
516
517                if (newResult) freeset(result, newResult);
518                free(serverDB);
519            }
520        }
521    }
522
523    return result;
524}
525
526// --------------------------------------------------------------------------------
527
528#ifdef UNIT_TESTS
529
530#include <test_unit.h>
531
532void TEST_GBS_servertags() {
533    TEST_ASSERT_EQUAL(GBS_ptserver_tag(0), "ARB_PT_SERVER0");
534    TEST_ASSERT_EQUAL(GBS_ptserver_tag(7), "ARB_PT_SERVER7");
535   
536    TEST_ASSERT_EQUAL(GBS_nameserver_tag(NULL),   "ARB_NAME_SERVER");
537    TEST_ASSERT_EQUAL(GBS_nameserver_tag(""),     "ARB_NAME_SERVER");
538    TEST_ASSERT_EQUAL(GBS_nameserver_tag("test"), "ARB_NAME_SERVER_TEST");
539}
540
541#endif
Note: See TracBrowser for help on using the repository browser.