Changeset 1431

Show
Ignore:
Timestamp:
11/05/07 23:35:07 (1 year ago)
Author:
till
Message:

nebula
- queues as default data structures
- mem leaks fixed

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • nebula/trunk/ChangeLog

    r1418 r1431  
     10.1.0 
     2- queues as default data structures (restrictable in size) 
     30.0.1 
    14- throughput profiling 
    25- clean configure script 
  • nebula/trunk/configure.in

    r1418 r1431  
    11# $Id$  
    22AC_PREREQ(02.50) 
    3 AC_INIT([nebula], [0.0.1], [tillmann.werner@gmx.de]) 
     3AC_INIT([nebula], [0.1.0], [tillmann.werner@gmx.de]) 
    44AM_CONFIG_HEADER(config.h) 
    5 AM_INIT_AUTOMAKE(nebula,0.0.1
     5AM_INIT_AUTOMAKE(nebula,0.1.0
    66 
    77AC_PROG_CC 
  • nebula/trunk/src/Makefile.am

    r1418 r1431  
    99                        util.c util.h \ 
    1010                        trie.c trie.h \ 
    11                         hashq.c hashq.h \ 
    12                         ngram.c ngram.h \ 
     11                        queue.c queue.h \ 
     12                        hash.c hash.h \ 
    1313                        cluster.c cluster.h \ 
    1414                        nebula.c nebula.h 
  • nebula/trunk/src/cluster.c

    r1419 r1431  
    2323 
    2424#include "cluster.h" 
    25 #include "hashq.h" 
    2625#include "nebula.h" 
    27 #include "trie.h" 
     26#include "queue.h" 
    2827 
    2928 
     
    3938 
    4039        /* create element queue */ 
    41         if ((new->hq = calloc(1, sizeof(hashq))) == NULL) { 
     40        if ((new->hq = calloc(1, sizeof(queue))) == NULL) { 
    4241                fprintf(stderr, "Error - Unable to allocate memory: %m.\n"); 
    4342                exit(EXIT_FAILURE); 
     
    4948 
    5049/* delete cluster */ 
    51 void cluster_free(cluster *cl, u_char list_files, void(*cbfn)(hashq *hq, u_char flag)) { 
     50void cluster_free(void *cl, u_char list_flag) { 
    5251        if (!cl) return; 
    5352 
    54         if (cbfn) cbfn(cl->hq, list_files); 
     53        if (list_flag & list_files) printf("-- Cluster has %d elements\n", ((cluster *)cl)->hq->size); 
     54        queue_free(((cluster *)cl)->hq, list_flag & list_files, hash_free); 
    5555        free(cl); 
    5656 
    57         return; 
    58 } 
    59  
    60  
    61 /* free a cluster's hash queue and its hashes */ 
    62 void cluster_hashq_free(hashq *hq, u_char list_files) { 
    63         hashq_free(hq, list_files, hash_free); 
    6457        return; 
    6558} 
     
    6962        qelem   *new; 
    7063 
    71         if (cl->hq->size < clusterq_max) { 
     64        if (cl->hq->size < clusterhashq_max) { 
    7265                // set cluster pointer in hash struct 
    7366                entry->cl = cl; 
    7467 
    7568                // add hash to queue 
    76                 if ((new = hashq_prepend(cl->hq, entry)) == NULL) { 
     69                if ((new = queue_prepend(cl->hq, entry)) == NULL) { 
    7770                        fprintf(stderr, "Error - Could not add entry to cluster.\n"); 
    7871                        exit(EXIT_FAILURE); 
     
    9386        add_entry_to_cluster(cl, l2); 
    9487 
    95         /* prepend new cluster to list */ 
    96         cl->next = cluster_list; 
    97         if(cluster_list) cluster_list->prev = cl; 
    98         cluster_list = cl; 
    99  
    100         num_of_clusters++; 
    101  
    10288        return(cl); 
    10389} 
    10490 
    10591 
    106 cluster *clusters_merge(cluster *dst, cluster *new) { 
    107                 cluster *cl1, *cl2; 
     92cluster *clusters_merge(queue *q, cluster *dst, cluster *src) { 
    10893                qelem   *entry; 
    10994 
    110                 cl1 = dst; 
    111                 cl2 = new; 
     95                // concatenate hash queues 
     96                dst->hq->tail->next = src->hq->head; 
     97                dst->hq->tail = src->hq->tail; 
     98                dst->hq->size += src->hq->size; 
    11299 
    113                 // join lists 
    114                 cl1->hq->tail->next = cl2->hq->head; 
    115                 cl1->hq->tail = cl2->hq->tail; 
    116                 cl1->hq->size += cl2->hq->size; 
     100                // let elements of src point to dst 
     101                for (entry = src->hq->head; entry; entry = entry->next) ((hash*)entry->data)->cl = dst; 
     102                src->hq->head = src->hq->tail = NULL; 
    117103 
    118                 // let elements of cl2 point to cl1 
    119                 for (entry = cl2->hq->head; entry; entry = entry->next) ((hash*)entry->data)->cl = cl1; 
    120                 cl2->hq->head = cl2->hq->tail = NULL; 
    121  
    122                 // unlink and free cluster 2 
    123                 if(cl2->prev) cl2->prev->next = cl2->next; 
    124                 if(cl2->next) cl2->next->prev = cl2->prev; 
    125  
    126                 // check whether cl2 is the list head 
    127                 if (cluster_list == cl2) cluster_list = cl2->next; 
    128  
    129  
    130                 hashq_free(cl2->hq, 0, NULL); 
    131                 cluster_free(cl2, 0, NULL); 
    132                 num_of_clusters--; 
     104                // unlink and free old cluster 
     105                queue_free(src->hq, 0, NULL); 
     106                entry = queue_unlink(q, src->parent); 
     107                cluster_free(entry->data, 1); 
     108                free(entry); 
    133109 
    134110                return(dst); 
    135111} 
    136  
    137  
    138 void clusterlist_delete(cluster *list, u_char list_files) { 
    139         cluster         *cl; 
    140  
    141         while(list) { 
    142                 cl = list; 
    143                 list = cl->next; 
    144                 if (!hide_result) printf("Cluster has %u entries.\n", cl->hq->size); 
    145                 cluster_free(cl, list_files, cluster_hashq_free); 
    146         } 
    147 } 
  • nebula/trunk/src/cluster.h

    r1414 r1431  
    1919 */ 
    2020 
    21 #ifndef __NEBULA_CLUSTER_H 
    22 #define __NEBULA_CLUSTER_H 1 
     21#ifndef __NEBULA_CLUSTERQ_H 
     22#define __NEBULA_CLUSTERQ_H 1 
    2323 
    2424#if HAVE_CONFIG_H 
     
    2828#include <stdlib.h> 
    2929 
    30 #include "hashq.h" 
     30#include "hash.h" 
    3131#include "trie.h" 
     32#include "queue.h" 
    3233 
    3334/* this struct can be extended when using different metrics, 
     
    3637typedef struct cluster { 
    3738        u_int16_t cnt; 
     39        void *parent; 
    3840        struct cluster *prev; 
    3941        struct cluster *next; 
    40         hashq *hq; 
     42        queue *hq; 
    4143} cluster; 
    4244 
     45 
     46 
     47inline cluster *cluster_new(void); 
     48void cluster_free(void *cl, u_char list_flag); 
    4349 
    4450inline cluster *create_hashlist(hash *hl1, hash *hl2); 
    4551cluster *add_entry_to_cluster(cluster *cl, hash *entry); 
    4652cluster *create_cluster(hash *l1, hash *l2); 
    47 cluster *clusters_merge(cluster *dst, cluster *new); 
     53cluster *clusters_merge(queue *q, cluster *dst, cluster *src); 
    4854void clusterlist_delete(cluster *list, u_char list_files); 
    4955 
  • nebula/trunk/src/nebula.c

    r1421 r1431  
    4646 
    4747void usage(const char* progname, const int exit_val) { 
    48 #ifdef PROFILE 
    49         printf("Usage: %s [-lpstv] [-c maximum cluster size] [-r cluster radius] [-q maximum outlier queue size] [-d directory] [file ...]\n", progname); 
    50 #else 
    51         printf("Usage: %s [-lpstv] [-a profiling interval] [-c maximum cluster size] [-r cluster radius] [-q maximum outlier queue size] [-d directory] [file ...]\n", progname); 
    52 #endif 
     48        printf("Usage: %s " 
     49                " -C <size>\t cluster queue size\n" 
     50                "\t\t -E <size>\t cluster element queue size\n" 
     51                "\t\t -O <size>\t outlier queue size\n" 
     52#ifdef PROFILE 
     53                "\t\t -a <seconds>\t alarm interval for profiling output\n" 
     54#endif 
     55                "\t\t -c <similarity> cluster criteria (a similarity measure in percent)\n" 
     56                "\t\t -d <directory>\t process direcory content\n" 
     57                "\t\t -h\t\t show this help\n" 
     58                "\t\t -l\t\t list clustered files in result\n" 
     59                "\t\t -o\t\t list outlier in result\n" 
     60                "\t\t -p\t\t show progress\n" 
     61                "\t\t -r\t\t hide result (only calculate cluster)\n" 
     62                "\t\t -t\t\t sort input files by creation time\n" 
     63                "\t\t -v\t\t be verbose\n" 
     64                "\t\t\t\t [files ...]\n", 
     65                progname); 
    5366 
    5467        exit(exit_val); 
     
    5669 
    5770int main(int argc, char *argv[]) { 
     71//int j; 
    5872        int             i, qsize; 
    5973        u_char          time_sort, *content, *tmpbuf; 
    6074        char            option, *dirname, *filename; 
    6175        hash            *tmp_hash; 
    62         qelem           *cur_hq, *tmp_hq; 
    63         cluster         *cl; 
     76        qelem           *cur_cqelem, *tmp_cqelem, *cur_hqelem, *tmp_hqelem; 
    6477        double          score; 
    6578        trie_node       *t; 
    6679        bstring         bstr; 
    6780        int             n; 
    68         struct dirent** namelist; 
    6981 
    7082 
    7183        dirname                 = NULL; 
     84        namelist                = NULL; 
    7285 
    7386        outlierq                = NULL; 
    74         cluster_list          = NULL; 
     87        clusterq              = NULL; 
    7588 
    7689        content                 = NULL; 
     
    91104        show_progress           = 0;    // don't show progress dots 
    92105        list_files              = 0;    // don't list cluster objects 
     106        list_outlier            = 0;    // don't list outlier  
    93107        cluster_radius          = 95.0; // 95% similarity as cluster criteria 
    94108        outlierq_max            = 500000; 
    95         clusterq_max            = 500000; 
     109        clusterhashq_max        = 500000; 
     110        clusterq_max            = 5000; 
    96111 
    97112        memset(&md5sum_trie, 0, sizeof(trie_node)); 
     
    102117        // process args 
    103118#ifdef PROFILE 
    104         while((option = getopt(argc, argv, "c:q:a:stplvd:r:h?")) > 0) { 
     119        while((option = getopt(argc, argv, "a:c:C:E:O:rtplovd:h?")) > 0) { 
    105120#else 
    106         while((option = getopt(argc, argv, "c:q:stplvd:r:h?")) > 0) { 
     121        while((option = getopt(argc, argv, "c:C:E:O:rtplovd:h?")) > 0) { 
    107122#endif 
    108123                switch(option) { 
     
    110125                        case 'a': 
    111126                                alarm_time = atoi(optarg); 
    112                                 if (alarm_time < 1) { 
    113                                         fprintf(stderr, "Error - Profile time interval must be at least one second.\n"); 
     127                                if (alarm_time < 0) { 
     128                                        fprintf(stderr, "Error - Profile time interval must be a non-negative value (0 means 'off').\n"); 
    114129                                        exit(EXIT_FAILURE); 
    115130                                } 
     
    117132#endif 
    118133                        case 'c': 
     134                                cluster_radius = atof(optarg); 
     135                                if ((cluster_radius < 0) || (cluster_radius > 100)) { 
     136                                        fprintf(stderr, "Error - Cluster radius must be a value between 0 and 100 (in percent).\n"); 
     137                                        exit(EXIT_FAILURE); 
     138                                } 
     139                                break; 
     140                        case 'C': 
    119141                                clusterq_max = atoi(optarg); 
    120                                 if (clusterq_max < 2) { 
    121                                         fprintf(stderr, "Error - Maximum cluster size must be at least 2.\n"); 
     142                                if (clusterq_max < 1) { 
     143                                        fprintf(stderr, "Error - Cluster queue size must be a non-negative value.\n"); 
    122144                                        exit(EXIT_FAILURE); 
    123145                                } 
     
    129151                                } 
    130152                                break; 
     153                        case 'E': 
     154                                clusterhashq_max = atoi(optarg); 
     155                                if (clusterhashq_max < 2) { 
     156                                        fprintf(stderr, "Error - Cluster element queue size must be at least 2.\n"); 
     157                                        exit(EXIT_FAILURE); 
     158                                } 
     159                                break; 
    131160                        case 'l': 
    132161                                list_files = 1; 
    133162                                break; 
    134                         case 'p': 
    135                                 show_progress = 1; 
    136                                 break; 
    137                         case 'q': 
     163                        case 'o': 
     164                                list_outlier = 1; 
     165                                break; 
     166                        case 'O': 
    138167                                outlierq_max = atoi(optarg); 
    139168                                if (outlierq_max < 1) { 
     
    142171                                } 
    143172                                break; 
     173                        case 'p': 
     174                                show_progress = 1; 
     175                                break; 
    144176                        case 'r': 
    145                                 cluster_radius = atof(optarg); 
    146                                 if ((cluster_radius < 0) || (cluster_radius > 100)) { 
    147                                         fprintf(stderr, "Error - Cluster radius must be a value between 0 and 100 (in percent).\n"); 
    148                                         exit(EXIT_FAILURE); 
    149                                 } 
    150                                 break; 
    151                         case 's': 
    152177                                hide_result = 1; 
    153178                                break; 
     
    195220 
    196221        // initialize outlier queue 
    197         outlierq = hashq_new(); 
    198  
    199  
    200 #ifdef PROFILE 
    201         alarm(alarm_time); 
    202         printf("Profiling enabled, printing statistics every %d seconds.\n", alarm_time); 
    203         files_in_interval = 0; 
    204         bytes_in_interval = 0; 
    205         checkpoint = 0; 
     222        outlierq = queue_new(); 
     223        clusterq = queue_new(); 
     224 
     225 
     226#ifdef PROFILE 
     227        if (alarm_time) { 
     228                alarm(alarm_time); 
     229                printf("Profiling enabled, printing statistics every %d seconds.\n", alarm_time); 
     230                files_in_interval = 0; 
     231                bytes_in_interval = 0; 
     232                checkpoint = 0; 
     233        } 
    206234#endif 
    207235 
     
    227255                        printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"); 
    228256                        if (num_of_files < total_files) 
    229                                 printf("files processed: %05.2f%% (%04d clusters)", num_of_files/total_files*100, num_of_clusters); 
     257                                printf("files processed: %05.2f%% (%04d clusters)", num_of_files/total_files*100, clusterq->size); 
    230258                        else 
    231                                 printf("files processed: 100.00%% (%04d clusters)\n", num_of_clusters); 
     259                                printf("files processed: 100.00%% (%04d clusters)\n", clusterq->size); 
    232260                        fflush(stdout); 
    233261                } 
     
    271299 
    272300                        // connect all clusters within range 
    273                         for (cl = cluster_list; cl; cl = cl->next) { 
    274                                 for (cur_hq = cl->hq->head; cur_hq; cur_hq = cur_hq->next) 
    275                                         if ((score = spamsum_match(((hash*)t->data)->spamsum, ((hash*)cur_hq->data)->spamsum)) >= cluster_radius) { 
     301                        for (cur_cqelem = clusterq->head; cur_cqelem; cur_cqelem = cur_cqelem->next) { 
     302                                for (cur_hqelem = ((cluster *)cur_cqelem->data)->hq->head; cur_hqelem; cur_hqelem = cur_hqelem->next) { 
     303                                        if ((score = spamsum_match(((hash*)t->data)->spamsum, ((hash*)cur_hqelem->data)->spamsum)) >= cluster_radius) { 
    276304                                                if (!((hash*)t->data)->cl) { 
    277                                                         add_entry_to_cluster(cl, (hash*)t->data); 
     305                                                        add_entry_to_cluster((cluster *)cur_cqelem->data, (hash*)t->data); 
    278306                                                        break; 
    279307                                                } else { 
    280                                                         if (cl != ((hash*)t->data)->cl) { 
    281                                                                 clusters_merge(cl, ((hash*)t->data)->cl); 
    282                                                         } 
     308                                                        if ((cluster *) cur_cqelem->data != ((hash*)t->data)->cl) 
     309                                                                clusters_merge(clusterq, (cluster *) cur_cqelem->data, ((hash*)t->data)->cl); 
    283310                                                        break; 
    284311                                                } 
    285312                                        } 
     313                                } 
    286314                        } 
    287315 
    288316                        // connect all outliers within range 
    289                         for (cur_hq = outlierq->head; cur_hq; cur_hq = cur_hq->next) { 
    290                                 if ((score = spamsum_match(((hash*)t->data)->spamsum, ((hash*)cur_hq->data)->spamsum)) >= cluster_radius) { 
     317                        for (cur_hqelem = outlierq->head; cur_hqelem; cur_hqelem = cur_hqelem->next) { 
     318                                if ((score = spamsum_match(((hash*)t->data)->spamsum, ((hash*)cur_hqelem->data)->spamsum)) >= cluster_radius) { 
    291319                                        // unlink match from outlier list 
    292                                         tmp_hq = cur_hq
    293                                         cur_hq = cur_hq->next; 
    294                                         if ((tmp_hash = hashq_unlink(outlierq, tmp_hq)) == NULL) { 
     320                                        tmp_hqelem = cur_hqelem
     321                                        cur_hqelem = cur_hqelem->next; 
     322                                        if ((tmp_hash = queue_unlink(outlierq, tmp_hqelem)) == NULL) { 
    295323                                                fprintf(stderr, "Error - Unable to unlink outlier from queue.\n"); 
    296324                                                exit(EXIT_FAILURE); 
     
    298326                                        if (((hash*)t->data)->cl) { 
    299327                                                // add other outliers to cluster 
    300                                                 if (add_entry_to_cluster(((hash*)t->data)->cl, tmp_hash) == NULL) 
     328                                                if (add_entry_to_cluster(((hash*)t->data)->cl, tmp_hash) == NULL) { 
     329                                                        trie_del_memstr(&md5sum_trie, (u_char *) tmp_hash->md5sum, strlen(tmp_hash->md5sum)); 
     330                                                        trie_del_memstr(&spamsum_trie, (u_char *) tmp_hash->spamsum, strlen(tmp_hash->spamsum)); 
    301331                                                        hash_free(tmp_hash, 0); 
     332                                                } 
    302333                                        } else { 
    303334                                                // create new cluster of two outliers 
    304                                                 create_cluster(((hash*)t->data), tmp_hash); 
     335                                                if ((tmp_cqelem = queue_ins(clusterq, create_cluster(((hash*)t->data), tmp_hash), clusterq_max)) != NULL) { 
     336                                                        /* cluster queue is full, last element was dropped and must be free()d */ 
     337                                                         
     338                                                        /* first remove hashes from tries */ 
     339                                                        for (tmp_hqelem = ((cluster *)tmp_cqelem->data)->hq->head; tmp_hqelem; tmp_hqelem = tmp_hqelem->next) { 
     340                                                                trie_del_memstr(&md5sum_trie, (u_char *) ((hash *)tmp_hqelem->data)->md5sum, 
     341                                                                        strlen(((hash *)tmp_hqelem->data)->md5sum)); 
     342                                                                trie_del_memstr(&spamsum_trie, (u_char *) ((hash *)tmp_hqelem->data)->spamsum, 
     343                                                                        strlen(((hash *)tmp_hqelem->data)->spamsum)); 
     344                                                        } 
     345                                                        /* now free cluster */ 
     346                                                        cluster_free((cluster *)tmp_cqelem->data, 0); 
     347                                                        free(tmp_cqelem); 
     348                                                } 
     349                                                /* set cluster element's parent pointer to cluster queue head 
     350                                                 * we need this to be able to unlink a cluster from the queue */ 
     351                                                ((cluster *) clusterq->head->data)->parent = clusterq->head; 
    305352                                        } 
    306353                                } 
    307                                 if (!cur_hq) break; 
     354                                if (!cur_hqelem) break; 
    308355                        } 
    309356 
     
    314361                                // insert outlier into queue 
    315362                                if (outlierq->size >= outlierq_max) { 
    316                                         tmp_hash = hashq_unlink(outlierq, outlierq->tail); 
     363                                        tmp_hash = queue_unlink(outlierq, outlierq->tail); 
    317364                                        trie_del_memstr(&md5sum_trie, (u_char *) tmp_hash->md5sum, strlen(tmp_hash->md5sum)); 
    318365                                        trie_del_memstr(&spamsum_trie, (u_char *) tmp_hash->spamsum, strlen(tmp_hash->spamsum)); 
    319366                                        hash_free(tmp_hash, 0); 
    320367                                } 
    321                                 hashq_ins(outlierq, t->data, outlierq_max); 
     368                                queue_ins(outlierq, t->data, outlierq_max); 
    322369                        } 
    323370                } 
  • nebula/trunk/src/nebula.h

    r1419 r1431  
    2929 
    3030#include "cluster.h" 
    31 #include "hashq.h" 
     31#include "hash.h" 
    3232 
    33 u_char          verbose, list_files, show_progress, hide_result; 
    34 int             clusterq_max, outlierq_max;  
     33u_char          verbose, list_files, list_outlier, show_progress, hide_result; 
     34struct dirent   **namelist; 
     35ssize_t         clusterq_max, clusterhashq_max, outlierq_max;  
    3536u_int16_t       num_of_clusters; 
    3637u_int32_t       num_of_duplicates; 
     
    3839double          cluster_radius; 
    3940trie_node       spamsum_trie, md5sum_trie; 
    40 cluster                *cluster_list
    41 hashq         *outlierq; 
     41queue          *clusterq
     42queue         *outlierq; 
    4243 
    4344#ifdef PROFILE 
  • nebula/trunk/src/signals.c

    r1419 r1431  
    3434        printf("Premature termination forced (signal %d caught).\n", sig); 
    3535 
     36exit(EXIT_FAILURE); 
    3637        cleanup(); 
    3738        exit(EXIT_SUCCESS); 
  • nebula/trunk/src/spamsum.h

    r1414 r1431  
    2626#endif 
    2727 
    28 #include "hashq.h" 
    2928 
    3029char *spamsum(const u_char *in, size_t length, u_int32_t bsize); 
  • nebula/trunk/src/util.c

    r1420 r1431  
    3030 
    3131#include "cluster.h" 
    32 #include "hashq.h" 
     32#include "hash.h" 
    3333#include "nebula.h" 
     34#include "queue.h" 
    3435#include "signals.h" 
    3536#include "trie.h" 
     
    113114 
    114115void cleanup(void) { 
     116        int     i; 
    115117#ifdef PROFILE 
    116118        struct sigaction        s_action; 
     
    129131 
    130132        // free data structures 
    131         if (!hide_result) printf("%u files form %u clustes and %u outliers (%u duplicates).\n%s\n", 
    132                 (unsigned int) num_of_files, num_of_clusters, outlierq->size, num_of_duplicates, 
    133                 "-----------------------------------------------------------------"); 
     133        if (namelist) { 
     134                if (namelist) for (i = 0; namelist[i]; free(namelist[i++])); 
     135                free(namelist); 
     136        } 
    134137 
    135         hashq_free(outlierq, 0, hash_free); 
    136         clusterlist_delete(cluster_list, list_files); 
     138        if (!hide_result) printf("%u files form %u clustes and %u outliers (%u duplicates).\n", 
     139                (unsigned int) num_of_files, clusterq->size, outlierq->size, num_of_duplicates); 
     140 
     141        if (list_outlier) printf("========== Outlier ==========\n"); 
     142        queue_free(outlierq, list_outlier, hash_free); 
     143        if (list_files) printf("========== Cluster ==========\n"); 
     144        queue_free(clusterq, list_files, cluster_free); 
    137145        trie_delete(md5sum_trie.childlist, md5sum_trie.childlist_len, NULL); 
    138146        trie_delete(spamsum_trie.childlist, spamsum_trie.childlist_len, NULL);