Navigation


Changeset 1260:4f6f61e67599 in freeDiameter for extensions


Ignore:
Timestamp:
Mar 24, 2014, 9:21:41 PM (10 years ago)
Author:
Thomas Klausner <tk@giga.or.at>
Branch:
default
Phase:
public
Message:

Store redirect information for ALL_SESSION and ALL_USER in a hash.

This is a speedup if many of these exist (compared to checking a
linked list for matches as before).

Refactor a bit while here.

Use the uthash code from Troy D. Hanson,
http://troydhanson.github.com/uthash/

Location:
extensions/rt_redirect
Files:
1 added
5 edited

Legend:

Unmodified
Added
Removed
  • extensions/rt_redirect/CMakeLists.txt

    r717 r1260  
    99        redir_fwd.c
    1010        redir_out.c
     11        uthash.h
    1112        )
    1213
  • extensions/rt_redirect/redir_entries.c

    r1259 r1260  
    11/*********************************************************************************************************
    22* Software License Agreement (BSD License)                                                               *
    3 * Author: Sebastien Decugis <sdecugis@freediameter.net>                                                  *
     3* Authors: Sebastien Decugis <sdecugis@freediameter.net>                                                 *
     4* and Thomas Klausner <tk@giga.or.at>                                                                    *
    45*                                                                                                        *
    5 * Copyright (c) 2011, WIDE Project and NICT                                                              *
     6* Copyright (c) 2011, 2014, WIDE Project and NICT                                                        *
    67* All rights reserved.                                                                                   *
    78*                                                                                                        *
     
    3536
    3637#include "rt_redir.h"
     38#include "uthash.h"
    3739
    3840/* The array with all entries ordered by their data */
    3941struct redir_line redirects_usages[H_U_MAX + 1];
     42
     43/* for symmetry reasons, hash tables for all types exist, but only ALL_SESSION and ALL_USER will be used */
     44struct redir_entry *redirect_hash_table[H_U_MAX+1];
    4045
    4146/* Initialize the array */
     
    5055
    5156        for (i = 0; i <= H_U_MAX; i++) {
     57                /* only one of the two will be used for each type, but initialize both to be on the safe side */
     58
     59                /* initialize list */
    5260                CHECK_POSIX( pthread_rwlock_init( &redirects_usages[i].lock, NULL) );
    5361                fd_list_init( &redirects_usages[i].sentinel, &redirects_usages[i] );
     62
     63                /* initialize hash table */
     64                redirect_hash_table[i] = NULL;
    5465        }
    5566
     
    6677}
    6778
     79int redir_entry_fini()
     80{
     81        int i;
     82        struct redir_entry *current_entry, *tmp;
     83
     84        /* Empty all entries */
     85        CHECK_POSIX_DO( pthread_mutex_lock(&redir_exp_peer_lock),   );
     86        for (i = 0; i <= H_U_MAX; i++) {
     87                CHECK_POSIX_DO( pthread_rwlock_wrlock( &redirects_usages[i].lock), );
     88                switch(i) {
     89                case ALL_SESSION:
     90                case ALL_USER:
     91                        HASH_ITER(hh, redirect_hash_table[i], current_entry, tmp) {
     92                                HASH_DEL(redirect_hash_table[i], current_entry);
     93                                CHECK_FCT_DO( redir_entry_destroy(current_entry), );
     94                        }
     95                        break;
     96                default:
     97                        while (!FD_IS_LIST_EMPTY(&redirects_usages[i].sentinel)) {
     98                                struct redir_entry * e = redirects_usages[i].sentinel.next->o;
     99                                fd_list_unlink(&e->redir_list);
     100                                CHECK_FCT_DO( redir_entry_destroy(e), );
     101                        }
     102                }
     103                CHECK_POSIX_DO( pthread_rwlock_unlock( &redirects_usages[i].lock), );
     104                CHECK_POSIX_DO( pthread_rwlock_destroy( &redirects_usages[i].lock), );
     105        }
     106        CHECK_POSIX_DO( pthread_mutex_unlock(&redir_exp_peer_lock),   );
     107
     108        return 0;
     109}
    68110
    69111/* Create a new redir_entry and add the correct data */
     
    91133
    92134        entry->type = rhu;
     135        /* list entry for putting into redirects_usage; also doubles as pointer into that list so it can be removed easily */
    93136        fd_list_init(&entry->redir_list, entry);
    94137        /* finally initialize the data */
     
    238281{
    239282        struct fd_list * li;
     283        struct redir_entry * r = NULL;
    240284
    241285        TRACE_ENTRY("%p", e);
     
    245289        CHECK_POSIX( pthread_rwlock_wrlock( RWLOCK_REDIR(e) ) );
    246290
    247         for (li = redirects_usages[e->type].sentinel.next; li != &redirects_usages[e->type].sentinel; li = li->next) {
    248                 struct redir_entry * n = li->o;
    249                 int cmp = redir_entry_cmp_key[e->type](&e->data, &n->data);
    250                 if (cmp <= 0)
    251                         break;
    252         }
    253 
    254         fd_list_insert_before(li, &e->redir_list);
     291        switch (e->type) {
     292        case ALL_SESSION:
     293                HASH_FIND(hh, redirect_hash_table[e->type], e->data.session.s, e->data.session.l, r);
     294                if (r) {
     295                        /* previously existing entry, delete it from hash and free it */
     296                        HASH_DELETE(hh, redirect_hash_table[e->type], r);
     297                        CHECK_FCT_DO( redir_entry_destroy(r), );
     298                }
     299                HASH_ADD_KEYPTR(hh, redirect_hash_table[e->type], e->data.session.s, e->data.session.l, e);
     300                break;
     301        case ALL_USER:
     302                HASH_FIND(hh, redirect_hash_table[e->type], e->data.user.s, e->data.user.l, r);
     303                if (r) {
     304                        /* previously existing entry, delete it from hash and free it */
     305                        HASH_DELETE(hh, redirect_hash_table[e->type], r);
     306                        CHECK_FCT_DO( redir_entry_destroy(r), );
     307                }
     308                HASH_ADD_KEYPTR(hh, redirect_hash_table[e->type], e->data.user.s, e->data.user.l, e);
     309                break;
     310        default:
     311                for (li = redirects_usages[e->type].sentinel.next; li != &redirects_usages[e->type].sentinel; li = li->next) {
     312                        struct redir_entry * n = li->o;
     313                        int cmp = redir_entry_cmp_key[e->type](&e->data, &n->data);
     314                        if (cmp <= 0)
     315                                break;
     316                }
     317
     318                fd_list_insert_before(li, &e->redir_list);
     319                break;
     320        }
    255321
    256322        /* unLock the line */
     
    263329int redir_entry_destroy(struct redir_entry * e)
    264330{
     331        struct redir_entry *match;
    265332        TRACE_ENTRY("%p", e);
    266333        CHECK_PARAMS(e && (e->eyec == REDIR_ENTRY_EYEC));
    267334
    268         /* If the entry is linked, lock the rwlock also */
    269         if (!FD_IS_LIST_EMPTY(&e->redir_list)) {
    270                 CHECK_POSIX( pthread_rwlock_wrlock( RWLOCK_REDIR(e) ) );
    271                 fd_list_unlink(&e->redir_list);
    272                 CHECK_POSIX( pthread_rwlock_unlock( RWLOCK_REDIR(e) ) );
     335        switch (e->type) {
     336        case ALL_SESSION:
     337                /* If the entry is in the hash table, lock the rwlock also */
     338                HASH_FIND(hh, redirect_hash_table[e->type], e->data.session.s, e->data.session.l, match);
     339                if (match) {
     340                        /* TODO: check if e == match? */
     341                        CHECK_POSIX( pthread_rwlock_wrlock( RWLOCK_REDIR(e) ) );
     342                        HASH_DELETE(hh, redirect_hash_table[e->type], match);
     343                        CHECK_POSIX( pthread_rwlock_unlock( RWLOCK_REDIR(e) ) );
     344                }
     345                break;
     346        case ALL_USER:
     347                /* If the entry is in the hash table, lock the rwlock also */
     348                HASH_FIND(hh, redirect_hash_table[e->type], e->data.user.s, e->data.user.l, match);
     349                if (match) {
     350                        /* TODO: check if e == match? */
     351                        CHECK_POSIX( pthread_rwlock_wrlock( RWLOCK_REDIR(e) ) );
     352                        HASH_DELETE(hh, redirect_hash_table[e->type], match);
     353                        CHECK_POSIX( pthread_rwlock_unlock( RWLOCK_REDIR(e) ) );
     354                }
     355                break;
     356        default:
     357                /* If the entry is linked, lock the rwlock also */
     358                if (!FD_IS_LIST_EMPTY(&e->redir_list)) {
     359                        CHECK_POSIX( pthread_rwlock_wrlock( RWLOCK_REDIR(e) ) );
     360                        fd_list_unlink(&e->redir_list);
     361                        CHECK_POSIX( pthread_rwlock_unlock( RWLOCK_REDIR(e) ) );
     362                }
     363                break;
    273364        }
    274365
  • extensions/rt_redirect/redir_out.c

    r1259 r1260  
    11/*********************************************************************************************************
    22* Software License Agreement (BSD License)                                                               *
    3 * Author: Sebastien Decugis <sdecugis@freediameter.net>                                                  *
     3* Authors: Sebastien Decugis <sdecugis@freediameter.net>                                                 *
     4* and Thomas Klausner <tk@giga.or.at>                                                                    *
    45*                                                                                                        *
    5 * Copyright (c) 2013, WIDE Project and NICT                                                              *
     6* Copyright (c) 2013, 2014, WIDE Project and NICT                                                        *
    67* All rights reserved.                                                                                   *
    78*                                                                                                        *
     
    218219}
    219220
     221static int redir_exist_for_type(int rule_type)
     222{
     223        int ret;
     224
     225        switch(rule_type) {
     226        case ALL_SESSION:
     227        case ALL_USER:
     228                ret = redirect_hash_table[rule_type] != NULL;
     229                break;
     230        default:
     231                ret = !FD_IS_LIST_EMPTY(&redirects_usages[rule_type].sentinel);
     232                break;
     233        }
     234        return ret;
     235}
     236
     237static int match_message(int rule_type, struct msg *msg, union matchdata *data, struct fd_list * candidates)
     238{
     239        struct fd_list * li;
     240        struct redir_entry * e = NULL;
     241        int ret = 0;
     242
     243        switch(rule_type) {
     244        case ALL_SESSION:
     245                HASH_FIND(hh, redirect_hash_table[rule_type], data->session.s, data->session.l, e);
     246                if (e) {
     247                        /* This message matches a rule, apply */
     248                        CHECK_FCT_DO( ret = apply_rule(e, msg, candidates), break );
     249                }
     250                break;
     251        case ALL_USER:
     252                HASH_FIND(hh, redirect_hash_table[rule_type], data->user.s, data->user.l, e);
     253                if (e) {
     254                        /* This message matches a rule, apply */
     255                        CHECK_FCT_DO( ret = apply_rule(e, msg, candidates), break );
     256                }
     257                break;
     258        default:
     259                /* Attempt each rule we have stored */
     260                for (li = redirects_usages[rule_type].sentinel.next; li != &redirects_usages[rule_type].sentinel; li = li->next) {
     261                        e = li->o;
     262
     263                        /* Does it match ? */
     264                        if (rule_type != ALL_HOST) { /* this one is an exception, we handle it separately */
     265                                int cmp = redir_entry_cmp_key[rule_type](data, &e->data);
     266                                if (cmp > 0)
     267                                        continue;
     268                                if (cmp < 0)
     269                                        break;
     270                        }
     271
     272                        /* This rule matches (or we are in ALL_HOST), apply */
     273                        CHECK_FCT_DO( ret = apply_rule(e, msg, candidates), break );
     274
     275                        /* If this was a DONT_CACHE rule, we unlink it, so that it will not be used again */
     276                        if (rule_type == DONT_CACHE) {
     277                                li = li->prev;
     278                                fd_list_unlink( li->next );
     279                                /* We cannot delete here without taking the mutex, which would mean we have first to release the lock...
     280                                   just let expiry garbage collect the rule */
     281                        }
     282                }
     283        }
     284
     285        return ret;
     286}
    220287
    221288/* OUT callback */
     
    235302                }
    236303
    237                 if (!FD_IS_LIST_EMPTY(&redirects_usages[i].sentinel)) {
     304                if (redir_exist_for_type(i)) {
    238305                        union matchdata data;
    239306                        int nodata; /* The message does not allow to apply this rule, skip */
     
    242309                        CHECK_FCT_DO( ret = get_data_to_match(i, msg, &data, &nodata), goto out );
    243310
    244                         /* If this message may match some of our rules */
    245                         if (!nodata) {
    246                                 struct fd_list * li;
    247                                 /* Attempt each rule we have stored */
    248                                 for (li = redirects_usages[i].sentinel.next; li != &redirects_usages[i].sentinel; li = li->next) {
    249                                         struct redir_entry * e = li->o;
    250 
    251                                         /* Does it match ? */
    252                                         if (i != ALL_HOST) { /* this one is an exception, we handle it separately */
    253                                                 int cmp = redir_entry_cmp_key[i](&data, &e->data);
    254                                                 if (cmp > 0)
    255                                                         continue;
    256                                                 if (cmp < 0)
    257                                                         break;
    258                                         }
    259 
    260                                         /* This rule matches (or we are in ALL_HOST), apply */
    261                                         CHECK_FCT_DO( ret = apply_rule(e, msg, candidates), goto out );
    262 
    263                                         /* If this was a DONT_CACHE rule, we unlink it, so that it will not be used again */
    264                                         if (i == DONT_CACHE) {
    265                                                 li=li->prev;
    266                                                 fd_list_unlink( li->next );
    267                                                 /* We cannot delete here without taking the mutex, which would mean we have first to release the lock...
    268                                                         just let expiry garbage collet the rule */
    269                                         }
    270                                 }
    271                         }
    272 
     311                        /* If data found for this type of rule, then try matching it */
     312                        if (!nodata)
     313                                ret = match_message(i, msg, &data, candidates);
    273314                }
    274315out:
  • extensions/rt_redirect/rt_redir.c

    r1259 r1260  
    11/*********************************************************************************************************
    22* Software License Agreement (BSD License)                                                               *
    3 * Author: Sebastien Decugis <sdecugis@freediameter.net>                                                  *
     3* Authors: Sebastien Decugis <sdecugis@freediameter.net>                                                 *
     4* and Thomas Klausner <tk@giga.or.at>                                                                    *
    45*                                                                                                        *
    5 * Copyright (c) 2011, WIDE Project and NICT                                                              *
     6* Copyright (c) 2011, 2014, WIDE Project and NICT                                                        *
    67* All rights reserved.                                                                                   *
    78*                                                                                                        *
     
    7273void fd_ext_fini(void)
    7374{
    74         int i;
    75 
    7675        /* Unregister the callbacks */
    7776        if (fwd_hdl) {
     
    8685
    8786        /* Empty all entries */
    88         CHECK_POSIX_DO( pthread_mutex_lock(&redir_exp_peer_lock),   );
    89         for (i = 0; i <= H_U_MAX; i++) {
    90                 CHECK_POSIX_DO( pthread_rwlock_wrlock( &redirects_usages[i].lock), );
    91                 while (!FD_IS_LIST_EMPTY(&redirects_usages[i].sentinel)) {
    92                         struct redir_entry * e = redirects_usages[i].sentinel.next->o;
    93                         fd_list_unlink(&e->redir_list);
    94                         CHECK_FCT_DO( redir_entry_destroy(e), );
    95                 }
    96                 CHECK_POSIX_DO( pthread_rwlock_unlock( &redirects_usages[i].lock), );
    97                 CHECK_POSIX_DO( pthread_rwlock_destroy( &redirects_usages[i].lock), );
    98         }
    99         CHECK_POSIX_DO( pthread_mutex_unlock(&redir_exp_peer_lock),   );
     87        redir_entry_fini();
    10088
    10189        return;
  • extensions/rt_redirect/rt_redir.h

    r1259 r1260  
    11/*********************************************************************************************************
    22* Software License Agreement (BSD License)                                                               *
    3 * Author: Sebastien Decugis <sdecugis@freediameter.net>                                                  *
    4 *                                                                                                        *
    5 * Copyright (c) 2013, WIDE Project and NICT                                                              *
     3* Author: Sebastien Decugis <sdecugis@freediameter.net> and                                              *
     4* Thomas Klausner <tk@giga.or.at>                                                                        *
     5*                                                                                                        *
     6* Copyright (c) 2013, 2014, WIDE Project and NICT                                                        *
    67* All rights reserved.                                                                                   *
    78*                                                                                                        *
     
    3637/* Diameter Redirect management */
    3738#include <freeDiameter/extension.h>
     39
     40#include "uthash.h"
    3841
    3942/* There are 2 locks in this module. The priority is established as follow to avoid deadlocks:
     
    130133        struct fd_list   target_peers_list; /* The list of Redirect-Hosts for this entry */
    131134
    132         struct timespec  timeout;  /* When does this entry expires? */
     135        struct timespec  timeout;  /* When does this entry expire? */
    133136        struct fd_list   exp_list; /* chain in the expire_list list, ordered by expiration date, protected by exp_peer_lock */
    134137
    135         enum redir_h_u type;  /* Type of this entry */
     138        enum redir_h_u type;       /* Type of this entry */
    136139        struct fd_list redir_list; /* link in redirects_usages lists. Lists are ordered by the data value. Protected by rw locks */
    137         union matchdata data;   /* The strings are duplicated & must be freed in this structure */
     140        union matchdata data;      /* The strings are duplicated & must be freed in this structure */
     141        UT_hash_handle hh;         /* magic entry for hash table */
    138142};
    139143
     
    145149};
    146150extern struct redir_line redirects_usages[];
     151/* the hash table where entries are stored for ALL_SESSION and ALL_USER */
     152extern struct redir_entry *redirect_hash_table[];
    147153
    148154/* Accelerator to the line lock */
     
    158164/* Functions on redir_entry */
    159165int redir_entry_init();
     166int redir_entry_fini();
    160167int redir_entry_new(struct redir_entry ** e, struct fd_list * targets, uint32_t rhu, struct msg * qry, DiamId_t nh, size_t nhlen, os0_t oh, size_t ohlen);
    161168extern int (*redir_entry_cmp_key[])(union matchdata * , union matchdata *); /* compare functions */
Note: See TracChangeset for help on using the changeset viewer.