modules_k/presence Fixed DB Storage Modes
authorAnca Vamanu <anca.vamanu@1and1.ro>
Wed, 15 Feb 2012 11:39:55 +0000 (13:39 +0200)
committerAnca Vamanu <anca.vamanu@1and1.ro>
Wed, 15 Feb 2012 11:39:55 +0000 (13:39 +0200)
- removed db_mode and fallback2db parameters and added two new
  parameters: subs_db_mode and publ_cache
- fixed and extended the storage modes for subscriptions: Memory Only,
  Write Through, Write Back, DB Only
- publ_cache parameter offers the possibility to disable publish cache
- some other fixes:
    - delete subscription only for 481 or 408 reply for Notify
    - call child_init also for main process (no shutdown DB flush was
      being performed)

22 files changed:
modules_k/presence/README
modules_k/presence/bind_presence.c
modules_k/presence/bind_presence.h
modules_k/presence/doc/presence_admin.xml
modules_k/presence/doc/presence_devel.xml
modules_k/presence/event_list.c
modules_k/presence/event_list.h
modules_k/presence/hash.c
modules_k/presence/hash.h
modules_k/presence/notify.c
modules_k/presence/notify.h
modules_k/presence/presence.c
modules_k/presence/presence.h
modules_k/presence/presentity.c
modules_k/presence/presentity.h
modules_k/presence/publish.c
modules_k/presence/publish.h
modules_k/presence/subscribe.c
modules_k/presence/subscribe.h
modules_k/presence/utils_func.c
modules_k/presence/utils_func.h
modules_k/pua/hash.h

index b66415c..f2bb932 100644 (file)
@@ -16,9 +16,9 @@ Edited by
 
 Juha Heinanen
 
-   Copyright © 2006 Voice Sistem SRL
+   Copyright Â© 2006 Voice Sistem SRL
 
-   Copyright © 2009 Juha Heinanen
+   Copyright Â© 2009 Juha Heinanen
      __________________________________________________________________
 
    Table of Contents
@@ -43,8 +43,8 @@ Juha Heinanen
               3.8. expires_offset (int)
               3.9. max_expires (int)
               3.10. server_address (str)
-              3.11. fallback2db (int)
-              3.12. db_mode (int)
+              3.11. subs_db_mode (int)
+              3.12. publ_cache (int)
               3.13. subs_htable_size (int)
               3.14. pres_htable_size (int)
               3.15. send_fast_notify (int)
@@ -99,8 +99,8 @@ Juha Heinanen
    1.8. Set expires_offset parameter
    1.9. Set max_expires parameter
    1.10. Set server_address parameter
-   1.11. Set fallback2db parameter
-   1.12. Set db_mode parameter
+   1.11. Set subs_db_mode parameter
+   1.12. Set publ_cache parameter
    1.13. Set subs_htable_size parameter
    1.14. Set pres_htable_size parameter
    1.15. Set send_fast_notify parameter
@@ -136,8 +136,8 @@ Chapter 1. Admin Guide
         3.8. expires_offset (int)
         3.9. max_expires (int)
         3.10. server_address (str)
-        3.11. fallback2db (int)
-        3.12. db_mode (int)
+        3.11. subs_db_mode (int)
+        3.12. publ_cache (int)
         3.13. subs_htable_size (int)
         3.14. pres_htable_size (int)
         3.15. send_fast_notify (int)
@@ -170,23 +170,13 @@ Chapter 1. Admin Guide
    from the presence_xml module and message-summary from the presence_mwi
    module.
 
-   The module uses database storage and memory caching (to improve
-   performance). The SIP SUBSCRIBE dialog information is stored in memory
-   and is periodically updated in the database, while for PUBLISH only the
-   presence or absence of stored info for a certain resource is maintained
-   in memory to avoid unnecessary, costly database operations. It is
-   possible to disable in-memory caching by configuring a fallback to
-   database mode (by setting the module parameter "fallback2db"). In this
-   mode, in case a searched record is not found in cache, the search is
-   continued in database. This is useful for an architecture in which
-   processing and memory load might be divided on several Kamailio
-   instances, maybe on different servers using the same database. This
-   parameter remains only for legacy purposes. As a new feature for the
-   presence engine, it is possible to have three database modes, which one
-   can configure through the db_mode parameter. Setting db_mode to 0, 1, 2
-   respective will cause the subscribers to be retrieved from memory only,
-   from memory and to fallback to database mode in case a record is not
-   found in memory, and from database only.
+   The module can use database and memory storage (to improve
+   performance). For subscriptions it supports the 4 storage modes: Memory
+   Only, Write Back, Write Through and DB Only. For publishes, it stores
+   the state documents in database only(because of the large size) and it
+   can store a publish cache in memory to avoid unnecessairy database
+   queries. Read the subs_db_mode and publ_cache parameter sections to
+   decide which is the best storage configuration for you.
 
    The module implements several API functions, that can be used by other
    modules. In fact, it can be used only as a resource module, or
@@ -224,8 +214,8 @@ Chapter 1. Admin Guide
    3.8. expires_offset (int)
    3.9. max_expires (int)
    3.10. server_address (str)
-   3.11. fallback2db (int)
-   3.12. db_mode (int)
+   3.11. subs_db_mode (int)
+   3.12. publ_cache (int)
    3.13. subs_htable_size (int)
    3.14. pres_htable_size (int)
    3.15. send_fast_notify (int)
@@ -240,7 +230,7 @@ Chapter 1. Admin Guide
    If set, the module is a fully operational presence server. Otherwise,
    it is used as a 'library', for its exported functions.
 
-   Default value is "NULL".
+   Default value is “NULL”.
 
    Example 1.1. Set db_url parameter
 ...
@@ -252,7 +242,7 @@ modparam("presence", "db_url",
 
    The name of the db table where PUBLISH presence information is stored.
 
-   Default value is "presentity".
+   Default value is “presentity”.
 
    Example 1.2. Set presentity_table parameter
 ...
@@ -264,7 +254,7 @@ modparam("presence", "presentity_table", "presentity")
    The name of the db table where active subscription information is
    stored.
 
-   Default value is "active_watchers".
+   Default value is “active_watchers”.
 
    Example 1.3. Set active_watchers_table parameter
 ...
@@ -275,7 +265,7 @@ modparam("presence", "active_watchers_table", "active_watchers")
 
    The name of the db table where subscription states are stored.
 
-   Default value is "watchers".
+   Default value is “watchers”.
 
    Example 1.4. Set watchers_table parameter
 ...
@@ -287,7 +277,7 @@ modparam("presence", "watchers_table", "watchers")
    The period in seconds between checks if there are expired messages
    stored in database.
 
-   Default value is "100". A zero or negative value disables this
+   Default value is “100”. A zero or negative value disables this
    activity.
 
    Example 1.5. Set clean_period parameter
@@ -300,7 +290,7 @@ modparam("presence", "clean_period", 100)
    The period at which to synchronize cached subscriber info with the
    database.
 
-   Default value is "100". A zero or negative value disables
+   Default value is “100”. A zero or negative value disables
    synchronization.
 
    Example 1.6. Set db_update_period parameter
@@ -313,7 +303,7 @@ modparam("presence", "db_update_period", 100)
    The prefix used when generating to_tag when sending replies for
    SUBSCRIBE requests.
 
-   Default value is "10".
+   Default value is “10”.
 
    Example 1.7. Set to_tag_pref parameter
 ...
@@ -326,7 +316,7 @@ modparam("presence", "to_tag_pref", 'pres')
    when sending a 200OK for a publish. It is used for forcing the client
    to send an update before the old publish expires.
 
-   Default value is "0".
+   Default value is “0”.
 
    Example 1.8. Set expires_offset parameter
 ...
@@ -338,7 +328,7 @@ modparam("presence", "expires_offset", 10)
    The the maximum admissible expires value for PUBLISH/SUBSCRIBE message
    (in seconds).
 
-   Default value is "3600".
+   Default value is “3600”.
 
    Example 1.9. Set max_expires parameter
 ...
@@ -356,34 +346,64 @@ modparam("presence", "max_expires", 3600)
 modparam("presence", "server_address", "sip:10.10.10.10:5060")
 ...
 
-3.11. fallback2db (int)
+3.11. subs_db_mode (int)
 
-   Setting this parameter enables a fallback to db mode of operation. In
-   this mode, in case a searched record is not found in cache, the search
-   is continued in database. Useful for an architecture in which
-   processing and memory load might be divided on more servers using the
-   same database. This parameter overwrite the configuration specified
-   from the "db_mode" parameter.
+   The presence module can utilize database for persistent subscription
+   storage. If you use database, your subscriptions will survive machine
+   restarts or SW crashes. The disadvantage is that accessing database can
+   be time consuming. Therefore, presence module implements four database
+   accessing modes:
+     * 0 - This disables database completely. Only memory will be used.
+       Subscriptions will not survive restart. Use this value if you need
+       a really fast presence module and subscription persistence is not
+       necessary or is provided by other means.
+     * 1 - Write-Through scheme. Subscriptions are updated synchronously
+       in database and in memory(used for read operations). Use this
+       scheme if speed is not top priority, but it's important that no
+       subscriptions will be lost during crash or reboot or if you have an
+       external application that reads the state of the subscriptions from
+       database and they need to be updated synchronously.
+     * 2 - Write-Back scheme. This is a combination of previous two
+       schemes. All changes are made to memory and database
+       synchronization is done in the timer. The timer deletes all expired
+       contacts and flushes all modified or new subscriptions to database.
+       Use this scheme if you encounter high-load peaks and want them to
+       process as fast as possible. Latency of this mode is much lower
+       than latency of mode 1, but slightly higher than latency of mode 0.
+       To control the interval at which data is flushed to database, set
+       the db_update_period parameter.
+     * 3 - DB-Only scheme. No memory cache is kept, all operations being
+       directly performed with the database. The timer deletes all expired
+       subscriptions from database. The mode is useful if you configure
+       more servers sharing the same DB without any replication at SIP
+       level. The mode may be slower due the high number of DB operation.
 
-   This parameter is obsolet and will be removed in future releases.
+   Default value is 2 (Write-Back scheme).
 
-   Example 1.11. Set fallback2db parameter
+   Example 1.11. Set subs_db_mode parameter
 ...
-modparam("presence", "fallback2db", 1)
+modparam("presence", "subs_db_mode", 1)
 ...
 
-3.12. db_mode (int)
+3.12. publ_cache (int)
 
-   This parameter sets the mode in which records are retrieved. Setting
-   this parameter to 0 or 1 is equivalent to setting fallback2db to 0 or
-   1, respectiv. The db_mode parameter can also take a third value, 2, in
-   which records are retrieved from database only. So, the three database
-   modes in which the presence engine can operate are: memory only,
-   fallback to database, and database only.
+   To improve performance, the presence module holds by default a publish
+   cache that says if a certain publication exists in database. This is
+   only a list of URI + event, so it does not use much memory. The cache
+   is used when a Subscription is received to check if there is any
+   published state in database. This way unnecessary queries in presentity
+   table are avoided.
 
-   Example 1.12. Set db_mode parameter
+   Setting this parameter to 0 will disable the usage of the publish
+   cache. This is desirable when you have more servers sharing the same
+   database or there are other external entities inserting data into the
+   presentity table.
+
+   Default value is “1”.
+
+   Example 1.12. Set publ_cache parameter
 ...
-modparam("presence", "db_mode", 2)
+modparam("presence", "publ_cache", 0)
 ...
 
 3.13. subs_htable_size (int)
@@ -392,7 +412,7 @@ modparam("presence", "db_mode", 2)
    This parameter will be used as the power of 2 when computing table
    size.
 
-   Default value is "9 (512)".
+   Default value is “9 (512)”.
 
    Example 1.13. Set subs_htable_size parameter
 ...
@@ -404,7 +424,7 @@ modparam("presence", "subs_htable_size", 11)
    The size of the in-memory hash table to store publish records. This
    parameter will be used as the power of 2 when computing table size.
 
-   Default value is "9 (512)".
+   Default value is “9 (512)”.
 
    Example 1.14. Set pres_htable_size parameter
 ...
@@ -419,7 +439,7 @@ modparam("presence", "pres_htable_size", 11)
    empty NOTIFY to an message-summary event. This parameter is enabled by
    default, thus addering to the standard.
 
-   Default value is "1 ".
+   Default value is “1 ”.
 
    Example 1.15. Set send_fast_notify parameter
 ...
@@ -434,7 +454,7 @@ modparam("presence", "send_fast_notify", 0)
    this check requires extra processing that should be avoided if this
    feature is not supported by the clients.
 
-   Default value is "0 ".
+   Default value is “0 ”.
 
    Example 1.16. Set enable_sphere_check parameter
 ...
@@ -449,7 +469,7 @@ modparam("presence", "enable_sphere_check", 1)
    on. Disabling this will keep subscriptions active on unreliable
    networks.
 
-   Default value is "1".
+   Default value is “1”.
 
    Example 1.17. Set timeout_rm_subs parameter
 ...
@@ -475,7 +495,7 @@ modparam("presence", "fetch_rows", 1000)
    4.4. pres_refresh_watchers(uri, event, type)
    4.5. pres_update_watchers(uri, event)
 
-4.1. handle_publish(char* sender_uri)
+4.1.  handle_publish(char* sender_uri)
 
    Handles PUBLISH requests by storing and updating published information
    in memory cache and database, then calls functions to send NOTIFY
@@ -507,7 +527,7 @@ modparam("presence", "fetch_rows", 1000)
         }
 ...
 
-4.2. handle_subscribe()
+4.2.  handle_subscribe()
 
    The function which handles SUBSCRIBE requests. It stores or updates
    information in memory and database and calls functions to send NOTIFY
@@ -527,7 +547,7 @@ if(method=="SUBSCRIBE")
     handle_subscribe();
 ...
 
-4.3. pres_auth_status(watcher_uri, presentity_uri)
+4.3.  pres_auth_status(watcher_uri, presentity_uri)
 
    The function checks if watcher is authorized to subscribe event
    'presence' of presentity. Both watcher_uri and presentity_uri are
@@ -550,7 +570,7 @@ if (method=="MESSAGE") {
 }
 ...
 
-4.4. pres_refresh_watchers(uri, event, type)
+4.4.  pres_refresh_watchers(uri, event, type)
 
    The function can be used in configuration to triger notifies to
    watchers if a change in watchers authorization or in published state
@@ -574,7 +594,7 @@ if (method=="MESSAGE") {
 pres_refresh_watchers("sip:test@kamailio.org", "presence", 1);
 ...
 
-4.5. pres_update_watchers(uri, event)
+4.5.  pres_update_watchers(uri, event)
 
    The function can be used in configuration to triger updates to watchers
    status if a change in watchers authorization state occurred (i.e.,
@@ -597,7 +617,7 @@ pres_update_watchers("sip:test@kamailio.org", "presence");
    5.1. refreshWatchers
    5.2. cleanup
 
-5.1. refreshWatchers
+5.1.  refreshWatchers
 
    Triggers sending Notify messages to watchers if a change in watchers
    authorization or in published state occurred.
@@ -623,7 +643,7 @@ pres_update_watchers("sip:test@kamailio.org", "presence");
                 1
                 _empty_line_
 
-5.2. cleanup
+5.2.  cleanup
 
    Manually triggers the cleanup functions for watchers and presentity
    tables. Useful if you have set clean_period to zero or less.
@@ -670,7 +690,7 @@ Chapter 2. Developer Guide
    The module provides the following functions that can be used in other
    Kamailio modules.
 
-1. bind_presence(presence_api_t* api)
+1.  bind_presence(presence_api_t* api)
 
    This function binds the presence modules and fills the structure with
    one exported function -> add_event, which when called adds a new event
@@ -696,7 +716,7 @@ typedef struct presence_api {
         /* function to duplicate a subs structure*/
         mem_copy_subs_t  mem_copy_subs;
         /* function used for update in database*/
-        update_db_subs_t update_db_subs;
+        update_db_subs_t update_db_subs_timer;
         /* function to extract dialog information from a
         SUBSCRIBE message */
         extract_sdialog_info_t extract_sdialog_info;
@@ -706,7 +726,7 @@ typedef struct presence_api {
 }presence_api_t;
 ...
 
-2. add_event
+2.  add_event
 
    Field type:
 ...
@@ -769,7 +789,7 @@ makes a
 }pres_ev_t;
 ...
 
-3. get_rules_doc
+3.  get_rules_doc
 
    Filed type:
 ...
@@ -782,7 +802,7 @@ typedef int (get_rules_doc_t)(str* user, str* domain, str** rules_doc);
    auth_rules_doc of the subs_t structure given as a parameter to the
    functions described bellow.
 
-4. get_auth_status
+4.  get_auth_status
 
    This filed is a function to be called for a subscription request to
    return the state for that subscription according to authorization
@@ -797,7 +817,7 @@ typedef int (get_rules_doc_t)(str* user, str* domain, str** rules_doc);
 typedef int (is_allowed_t)(struct subscription* subs);
 ...
 
-5. apply_auth_nbody
+5.  apply_auth_nbody
 
    This parameter should be a function to be called for an event that
    requires authorization, when constructing final body. The authorization
@@ -809,7 +829,7 @@ typedef int (is_allowed_t)(struct subscription* subs);
 typedef int (apply_auth_t)(str* , struct subscription*, str** );
 ...
 
-6. agg_nbody
+6.  agg_nbody
 
    If present, this field marks that the events requires aggregation of
    states. This function receives a body array and should return the final
@@ -823,7 +843,7 @@ typedef str* (agg_nbody_t)(str* pres_user, str* pres_domain,
 str** body_array, int n, int off_index);
 ..
 
-7. free_body
+7.  free_body
 
    This field must be field in if subsequent processing is performed on
    the info from database before being inserted in Notify message body(if
@@ -835,7 +855,7 @@ str** body_array, int n, int off_index);
 typedef void(free_body_t)(char* body);
 ..
 
-8. aux_body_processing
+8.  aux_body_processing
 
    This field must be set if the module needs to manipulate the NOTIFY
    body for each watcher. E.g. if the XML body includes a 'version'
@@ -849,7 +869,7 @@ typedef void(free_body_t)(char* body);
 typedef str* (aux_body_processing_t)(struct subscription *subs, str* body);
 ..
 
-9. aux_free_body
+9.  aux_free_body
 
    This field must be set if the module registers the aux_body_processing
    function and allocates memory for the new modified body. Then, this
@@ -864,7 +884,7 @@ typedef str* (aux_body_processing_t)(struct subscription *subs, str* body);
 typedef void(free_body_t)(char* body);
 ..
 
-10. evs_publ_handl
+10.  evs_publ_handl
 
    This function is called when handling Publish requests. Most contain
    body correctness check.
@@ -873,7 +893,7 @@ typedef void(free_body_t)(char* body);
 typedef int (publ_handling_t)(struct sip_msg*);
 ..
 
-11. evs_subs_handl
+11.  evs_subs_handl
 
    It is not compulsory. Should contain event specific handling for
    Subscription requests.
@@ -883,7 +903,7 @@ typedef int (publ_handling_t)(struct sip_msg*);
 typedef int (subs_handling_t)(struct sip_msg*);
 ..
 
-12. contains_event
+12.  contains_event
 
    Field type:
 ..
@@ -896,7 +916,7 @@ event_t* parsed_event);
    found. If the second argument is an allocated event_t* structure it
    fills it with the result of the parsing.
 
-13. get_event_list
+13.  get_event_list
 
    Field type:
 ...
@@ -906,7 +926,7 @@ typedef int (*get_event_list_t) (str** ev_list);
    This function returns a string representation of the events registered
    in presence module.( used for Allowed-Events header).
 
-14. update_watchers_status
+14.  update_watchers_status
 
    Field type:
 ...
@@ -920,7 +940,7 @@ str* rules_doc);
    (used by presence_xml module when notified through an MI command of a
    change in an xcap document).
 
-15. get_sphere
+15.  get_sphere
 
    Field type:
 ...
@@ -931,7 +951,7 @@ typedef char* (*pres_get_sphere_t)(str* pres_uri);
    information if this has type RPID. If not found returns NULL. (the
    return value is allocated in private memory and should be freed)
 
-16. get_presentity
+16.  get_presentity
 
    Field type:
 ...
@@ -947,7 +967,7 @@ r *contact);
    Once you are finished with the presentity document you must call
    free_presentity to free the allocated memory.
 
-17. free_presentity
+17.  free_presentity
 
    Field type:
 ...
index ec55033..1f95e61 100644 (file)
@@ -23,7 +23,7 @@
  *
  * History:
  * --------
- *  2007-04-17  initial version (anca)
+ *  2007-04-17  initial version (Anca Vamanu)
  */
 
 /*! \file
@@ -63,7 +63,7 @@ int bind_presence(presence_api_t* api)
        api->delete_shtable= delete_shtable;
        api->update_shtable= update_shtable;
        api->mem_copy_subs= mem_copy_subs;
-       api->update_db_subs= update_db_subs;
+       api->update_db_subs_timer= update_db_subs_timer;
        api->extract_sdialog_info= extract_sdialog_info;
        api->get_sphere= get_sphere;
        api->get_presentity= get_p_notify_body;
index 0582997..b9446e0 100644 (file)
@@ -23,7 +23,7 @@
  *
  * History:
  * --------
- *  2007-04-17  initial version (anca)
+ *  2007-04-17  initial version (Anca Vamanu)
  */
 /*! \file
  * \brief SIP-Router Presence :: Kamailio generic presence module
@@ -61,7 +61,7 @@ typedef struct presence_api {
        delete_shtable_t delete_shtable;
        update_shtable_t update_shtable;
        mem_copy_subs_t  mem_copy_subs;
-       update_db_subs_t update_db_subs;
+       update_db_subs_t update_db_subs_timer;
        extract_sdialog_info_t extract_sdialog_info;
        pres_get_sphere_t get_sphere;
        pres_get_presentity_t get_presentity;
index 3966644..c6db6b5 100644 (file)
        module and message-summary from the presence_mwi module.
        </para>
        <para>
-       The module uses database storage and memory caching (to improve performance).
-       The SIP SUBSCRIBE dialog information is stored in memory and 
-       is periodically updated in the database, while for PUBLISH only the presence
-       or absence of stored info for a certain resource is maintained in memory
-       to avoid unnecessary, costly database operations. 
-       It is possible to disable in-memory caching by configuring a fallback to database mode 
-       (by setting the module parameter "fallback2db"). In this mode, in case a searched record is not 
-       found in cache, the search is continued in database. This is useful for
-       an architecture in which processing and memory load might be divided on 
-       several &kamailio; instances, maybe on different servers using the same database.
-        This parameter remains only for legacy purposes. As a new feature for the presence engine, it is possible
-        to have three database modes, which one can configure through the db_mode parameter.
-        Setting db_mode to 0, 1, 2 respective will cause the subscribers to be retrieved from memory only,
-        from memory and to fallback to database mode in case a record is not found in memory, and from database only.
+       The module can use database and memory storage (to improve performance).
+       For subscriptions it supports the 4 storage modes: Memory Only, Write Back,
+       Write Through and DB Only. For publishes, it stores the state documents in
+       database only(because of the large size) and it can store a publish cache in
+       memory to avoid unnecessairy database queries. Read the 
+       <emphasis>subs_db_mode</emphasis> and <emphasis>publ_cache</emphasis> parameter
+       sections to decide which is the best storage configuration for you.
        </para>
        <para>The module implements several API functions, that can be used by other
        modules. In fact, it can be used only as a resource module, or "library".
@@ -98,8 +91,7 @@
                its exported functions.
                </para>
                <para>
-               <emphasis>      Default value is <quote>NULL</quote>.   
-               </emphasis>
+               <emphasis>Default value is <quote>NULL</quote>.</emphasis>
                </para>
                <example>
                <title>Set <varname>db_url</varname> parameter</title>
@@ -262,8 +254,8 @@ modparam("presence", "expires_offset", 10)
 modparam("presence", "max_expires", 3600)
 ...
 </programlisting>
-               </example>
-       </section>
+       </example>
+</section>
 
 <section>
                <title><varname>server_address</varname> (str)</title>
@@ -280,51 +272,108 @@ modparam("presence", "server_address", "sip:10.10.10.10:5060")
 </programlisting>
                </example>
        </section>
+
 <section>
-               <title><varname>fallback2db</varname> (int)</title>
+               <title><varname>subs_db_mode</varname> (int)</title>
                <para>
-               Setting this parameter enables a fallback to db mode of operation.
-               In this mode, in case a searched record is not found in cache, 
-               the search is continued in database. Useful for an architecture in
-               which processing and memory load might be divided on more servers
-               using the same database. This parameter overwrite the configuration
-               specified from the <quote>db_mode</quote> parameter.
+               The presence module can utilize database for persistent subscription storage.
+               If you use database, your subscriptions will survive machine restarts or
+               SW crashes. The disadvantage is that accessing database can be time consuming.
+               Therefore, presence module implements four database accessing modes:
                </para>
+               <itemizedlist>
+               <listitem>
+                       <para>
+                       0 - This disables database completely. Only memory will be used.
+                       Subscriptions will not survive restart. Use this value if you need a
+                       really fast presence module and subscription persistence is not necessary or
+                       is provided by other means.
+                       </para>
+               </listitem>
+               <listitem>
+                       <para>
+                       1 - Write-Through scheme. Subscriptions are updated synchronously
+                       in database and in memory(used for read operations). Use this
+                       scheme if speed is not top priority, but it's important that no
+                       subscriptions will be lost during crash or reboot or if you have
+                       an external application that reads the state of the subscriptions
+                       from database and they need to be updated synchronously.
+                       </para>
+               </listitem>
+               <listitem>
+                       <para>
+                       2 - Write-Back scheme. This is a combination of previous two
+                       schemes. All changes are made to memory and database
+                       synchronization is done in the timer. The timer deletes all
+                       expired contacts and flushes all modified or new subscriptions to
+                       database. Use this scheme if you encounter high-load peaks
+                       and want them to process as fast as possible. Latency of this
+                       mode is much lower than latency of mode 1, but slightly higher
+                       than latency of mode 0. To control the interval at which data is
+                       flushed to database, set the <emphasis>db_update_period</emphasis>
+                       parameter.
+                       </para>
+               </listitem>
+               <listitem>
+                       <para>
+                       3 - DB-Only scheme. No memory cache is kept, all operations being
+                       directly performed with the database. The timer deletes all expired
+                       subscriptions from database. The mode is useful if you configure
+                       more servers sharing the same DB without any replication at SIP
+                       level. The mode may be slower due the high number of DB operation.
+                       </para>
+               </listitem>
+               </itemizedlist>
                <para>
-               This parameter is obsolet and will be removed in future releases.
+               <emphasis>Default value is 2 (Write-Back scheme).</emphasis>
                </para>
+
                <example>
-               <title>Set <varname>fallback2db</varname> parameter</title>
+               <title>Set <varname>subs_db_mode</varname> parameter</title>
                <programlisting format="linespecific">
 ...
-modparam("presence", "fallback2db", 1)
+modparam("presence", "subs_db_mode", 1)
 ...
 </programlisting>
                </example>
        </section>
-<section>
-               <title><varname>db_mode</varname> (int)</title>
+
+       <section>
+               <title><varname>publ_cache</varname> (int)</title>
+               <para>
+               To improve performance, the presence module holds by default a
+               publish cache that says if a certain publication exists in database.
+               This is only a list of URI + event, so it does not use much memory.
+               The cache is used when a Subscription is received to check if there
+               is any published state in database. This way unnecessary queries in
+               presentity table are avoided.
+               </para>
+               <para>
+               Setting this parameter to 0 will disable the usage of the publish
+               cache. This is desirable when you have more servers sharing the same
+               database or there are other external entities inserting data into the
+               presentity table.
+               </para>
                <para>
-               This parameter sets the mode in which records are retrieved.
-                Setting this parameter to 0 or 1 is equivalent to setting fallback2db to 0 or 1, respectiv.
-                The db_mode parameter can also take a third value, 2, in which records are retrieved from database only.
-                So, the three database modes in which the presence engine can operate are: memory only, fallback to database, and database only.
+               <emphasis>Default value is <quote>1</quote>.
+               </emphasis>
                </para>
                <example>
-               <title>Set <varname>db_mode</varname> parameter</title>
+               <title>Set <varname>publ_cache</varname> parameter</title>
                <programlisting format="linespecific">
 ...
-modparam("presence", "db_mode", 2)
+modparam("presence", "publ_cache", 0)
 ...
-</programlisting>
+       </programlisting>
                </example>
        </section>
+
        <section>
                <title><varname>subs_htable_size</varname> (int)</title>
                <para>
                The size of the in-memory hash table to store subscription dialogs.
-               This parameter will be used as the power of 2 when computing table size.
-               </para>
+               This parameter will be used as the power of 2 when computing table size.
+               </para>
                <para>
                <emphasis>Default value is <quote>9 (512)</quote>.
                </emphasis>
index a9f11d3..7c0fae0 100644 (file)
@@ -46,7 +46,7 @@ typedef struct presence_api {
        /* function to duplicate a subs structure*/
        mem_copy_subs_t  mem_copy_subs;
        /* function used for update in database*/
-       update_db_subs_t update_db_subs;
+       update_db_subs_t update_db_subs_timer;
        /* function to extract dialog information from a
        SUBSCRIBE message */
        extract_sdialog_info_t extract_sdialog_info;
index eb83d6b..14df4f5 100644 (file)
@@ -19,7 +19,7 @@
  *
  * History:
  * --------
- *  2007-04-04  initial version (anca)
+ *  2007-04-04  initial version (Anca Vamanu)
  */
 
 /*!
index 23fdeba..93f1969 100644 (file)
@@ -19,7 +19,7 @@
  *
  * History:
  * --------
- *  2007-04-05  initial version (anca)
+ *  2007-04-05  initial version (Anca Vamanu)
  */
 
 /*!
index 7f754c9..87b0908 100644 (file)
@@ -23,7 +23,7 @@
  *
  * History:
  * --------
- *  2007-08-20  initial version (anca)
+ *  2007-08-20  initial version (Anca Vamanu)
  */
 
 /*! \file
@@ -257,31 +257,16 @@ int insert_shtable(shtable_t htable,unsigned int hash_code, subs_t* subs)
        if(new_rec== NULL)
        {
                LM_ERR("copying in share memory a subs_t structure\n");
-               goto error;
+               return -1;
        }
-
        new_rec->expires+= (int)time(NULL);
-       if(dbmode == DB_FALLBACK) {
-               if(new_rec->db_flag == 0)
-                       new_rec->db_flag = INSERTDB_FLAG;
-       } else {
-               new_rec->db_flag = NO_UPDATEDB_FLAG;
-       }
 
        lock_get(&htable[hash_code].lock);
-       
        new_rec->next= htable[hash_code].entries->next;
-       
        htable[hash_code].entries->next= new_rec;
-       
        lock_release(&htable[hash_code].lock);
-       
-       return 0;
 
-error:
-       if(new_rec)
-               shm_free(new_rec);
-       return -1;
+       return 0;
 }
 
 int delete_shtable(shtable_t htable,unsigned int hash_code,str to_tag)
@@ -295,11 +280,11 @@ int delete_shtable(shtable_t htable,unsigned int hash_code,str to_tag)
        s= ps->next;
                
        while(s)
-       {       
+       {
                if(s->to_tag.len== to_tag.len &&
                                strncmp(s->to_tag.s, to_tag.s, to_tag.len)== 0)
                {
-                       found= s->local_cseq;
+                       found= s->local_cseq +1;
                        ps->next= s->next;
                        if(s->contact.s!=NULL)
                                shm_free(s->contact.s);
index ba9a0ab..7c7010d 100644 (file)
@@ -23,7 +23,7 @@
  *
  * History:
  * --------
- *  2007-08-20  initial version (anca)
+ *  2007-08-20  initial version (Anca Vamanu)
  */
 
 /*! \file
index eaef923..4527b5a 100644 (file)
@@ -23,7 +23,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*! \file
@@ -357,6 +357,7 @@ str* get_wi_notify_body(subs_t* subs, subs_t* watcher_subs)
        unsigned int hash_code;
        subs_t* s= NULL;
        int state = FULL_STATE_FLAG;
+       unsigned int now = (int)time(NULL);
 
        hash_code = 0;
        version_str = int2str(subs->version, &len);
@@ -373,8 +374,8 @@ str* get_wi_notify_body(subs_t* subs, subs_t* watcher_subs)
        }
        memset(watchers, 0, sizeof(watcher_t));
 
-       if(watcher_subs != NULL) 
-       {               
+       if(watcher_subs != NULL)
+       {
                if(add_watcher_list(watcher_subs, watchers)< 0)
                        goto error;
                state = PARTIAL_STATE_FLAG;
@@ -382,63 +383,52 @@ str* get_wi_notify_body(subs_t* subs, subs_t* watcher_subs)
                goto done;
        }
 
-       if(dbmode != DB_MEMORY_ONLY)
+       if(subs_dbmode == DB_ONLY)
        {
                if(get_wi_subs_db(subs, watchers)< 0)
                {
                        LM_ERR("getting watchers from database\n");
                        goto error;
                }
-       }
-
-       hash_code= core_hash(&subs->pres_uri, &subs->event->wipeer->name,
-            shtable_size);
-       lock_get(&subs_htable[hash_code].lock);
-
-       s= subs_htable[hash_code].entries;
-
-    while(s->next)
-       {
-               s= s->next;
+       } else {
+               hash_code= core_hash(&subs->pres_uri, &subs->event->wipeer->name,
+                               shtable_size);
+               lock_get(&subs_htable[hash_code].lock);
+               s= subs_htable[hash_code].entries;
+               while(s->next)
+               {
+                       s= s->next;
 
-               if(s->expires< (int)time(NULL))
-               {       
-                       LM_DBG("expired record\n");
-                       continue;
-               }
+                       if(s->expires< now)
+                       {
+                               LM_DBG("expired record\n");
+                               continue;
+                       }
 
-               if(dbmode != DB_MEMORY_ONLY && s->db_flag!= INSERTDB_FLAG)
-               {
-                       LM_DBG("record already found in database\n");
-                       continue;
+                       if(s->event== subs->event->wipeer &&
+                               s->pres_uri.len== subs->pres_uri.len &&
+                               strncmp(s->pres_uri.s, subs->pres_uri.s,subs->pres_uri.len)== 0)
+                       {
+                               if(add_watcher_list(s, watchers)< 0)
+                               {
+                                       lock_release(&subs_htable[hash_code].lock);
+                                       goto error;
+                               }
+                       }
                }
+               lock_release(&subs_htable[hash_code].lock);
 
-        if(s->event== subs->event->wipeer &&
-                       s->pres_uri.len== subs->pres_uri.len &&
-                       strncmp(s->pres_uri.s, subs->pres_uri.s,subs->pres_uri.len)== 0)
+               if(add_waiting_watchers(watchers, subs->pres_uri,
+                                       subs->event->wipeer->name)< 0 )
                {
-                       if(add_watcher_list(s, watchers)< 0)
-                       {
-                               lock_release(&subs_htable[hash_code].lock);
-                               goto error;
-                       }
+                       LM_ERR("failed to add waiting watchers\n");
+                       goto error;
                }
        }
-       
-       if(add_waiting_watchers(watchers, subs->pres_uri,
-                               subs->event->wipeer->name)< 0 )
-       {
-               LM_ERR("failed to add waiting watchers\n");
-               goto error;
-       }
 
 done:
        notify_body = create_winfo_xml(watchers,version_str,subs->pres_uri,
                        subs->event->wipeer->name, state);
-       
-       if(watcher_subs == NULL) 
-               lock_release(&subs_htable[hash_code].lock);
-
        if(notify_body== NULL)
        {
                LM_ERR("in function create_winfo_xml\n");
@@ -448,12 +438,6 @@ done:
        return notify_body;
 
 error:
-       if(notify_body)
-       {
-               if(notify_body->s)
-                       xmlFree(notify_body->s);
-               pkg_free(notify_body);
-       }
        free_watcher_list(watchers);
        return NULL;
 }
@@ -637,31 +621,26 @@ str* get_p_notify_body(str pres_uri, pres_ev_t* event, str* etag,
                LM_ERR("while parsing uri\n");
                return NULL;
        }
-       
+
        /* if in db_only mode, get the presentity information from database - skip htable search */
-       if(dbmode == DB_ONLY)
-       {
-               goto db_query;
-       }
-       /* search in hash table if any record exists */
-       hash_code= core_hash(&pres_uri, NULL, phtable_size);
-       if(search_phtable(&pres_uri, event->evp->type, hash_code)== NULL)
+       if( publ_cache_enabled )
        {
-               LM_DBG("No record exists in hash_table\n");
-               if(dbmode != DB_MEMORY_ONLY)
-                       goto db_query;
-
-               /* for pidf manipulation */
-               if(event->agg_nbody)
+               /* search in hash table if any record exists */
+               hash_code= core_hash(&pres_uri, NULL, phtable_size);
+               if(search_phtable(&pres_uri, event->evp->type, hash_code)== NULL)
                {
-                       notify_body = event->agg_nbody(&uri.user, &uri.host, NULL, 0, -1);
-                       if(notify_body)
-                               goto done;
-               }                       
-               return NULL;
-       }
+                       LM_DBG("No record exists in hash_table\n");
 
-db_query:
+                       /* for pidf manipulation */
+                       if(event->agg_nbody)
+                       {
+                               notify_body = event->agg_nbody(&uri.user, &uri.host, NULL, 0, -1);
+                               if(notify_body)
+                                       goto done;
+                       }
+                       return NULL;
+               }
+       }
 
        query_cols[n_query_cols] = &str_domain_col;
        query_vals[n_query_cols].type = DB1_STR;
@@ -1248,24 +1227,20 @@ subs_t* get_subs_dialog(str* pres_uri, pres_ev_t* event, str* sender)
        unsigned int hash_code;
        subs_t* s= NULL, *s_new;
        subs_t* s_array= NULL;
-       int n= 0, i= 0;
+       int n= 0;
        
-       /* if in memory mode, should take the subscriptions from the hashtable only
-          in dbonly mode should take all dialogs from db
-          in fallback mode, should take those dialogs with db_flag = INSERTDB_FLAG
+       /* if subs_dbmode!=DB_ONLY, should take the subscriptions from the hashtable only
+          in DB_ONLY mode should take all dialogs from db
        */
 
-       if(dbmode != DB_MEMORY_ONLY)
+       if(subs_dbmode == DB_ONLY)
        {
-               if(get_subs_db(pres_uri, event, sender, &s_array, &n)< 0)                       
+               if(get_subs_db(pres_uri, event, sender, &s_array, &n)< 0)
                {
                        LM_ERR("getting dialogs from database\n");
                        goto error;
                }
-       }
-       
-       if(dbmode != DB_ONLY)
-       {
+       }else {
                hash_code= core_hash(pres_uri, &event->name, shtable_size);
                
                lock_get(&subs_htable[hash_code].lock);
@@ -1275,15 +1250,15 @@ subs_t* get_subs_dialog(str* pres_uri, pres_ev_t* event, str* sender)
                while(s->next)
                {
                        s= s->next;
-               
+
                        printf_subs(s);
-                       
+
                        if(s->expires< (int)time(NULL))
                        {
                                LM_DBG("expired subs\n");
                                continue;
                        }
-                       
+
                        if((!(s->status== ACTIVE_STATUS &&
                    s->reason.len== 0 &&
                                s->event== event && s->pres_uri.len== pres_uri->len &&
@@ -1292,28 +1267,6 @@ subs_t* get_subs_dialog(str* pres_uri, pres_ev_t* event, str* sender)
                                strncmp(sender->s, s->contact.s, sender->len)== 0))
                                continue;
 
-                       if(dbmode == DB_FALLBACK)
-                       {
-                               if(s->db_flag== NO_UPDATEDB_FLAG)
-                               {
-                                       LM_DBG("s->db_flag==NO_UPDATEDB_FLAG\n");
-                                       continue;
-                               }
-                               
-                               if(s->db_flag== UPDATEDB_FLAG)
-                               {
-                                       LM_DBG("s->db_flag== UPDATEDB_FLAG\n");
-                                       if(n>0 && update_in_list(s, s_array, i, n)< 0)
-                                       {
-                                               LM_DBG("dialog not found in list fetched from database\n");
-                                               /* insert record */
-                                       }
-                                       else
-                                               continue;                       
-                               }
-                       }
-                       
-                       LM_DBG("s->db_flag= INSERTDB_FLAG\n");
                        s_new= mem_copy_subs(s, PKG_MEM_TYPE);
                        if(s_new== NULL)
                        {
@@ -1324,13 +1277,9 @@ subs_t* get_subs_dialog(str* pres_uri, pres_ev_t* event, str* sender)
                        s_new->expires-= (int)time(NULL);
                        s_new->next= s_array;
                        s_array= s_new;
-                       i++;
                }
-               
-       lock_release(&subs_htable[hash_code].lock);
+               lock_release(&subs_htable[hash_code].lock);
        }
-       
-       LM_DBG("found %d dialogs( %d in database and %d in hash_table)\n",n+i,n,i);
 
        return s_array;
 
@@ -1493,19 +1442,19 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs,
                }
                else
                        notify_body= n_body;
-       }       
+       }
        else
-       {       
+       {
                if(subs->status== TERMINATED_STATUS || 
                                subs->status== PENDING_STATUS) 
                {
                        LM_DBG("state terminated or pending- notify body NULL\n");
                        notify_body = NULL;
                }
-               else  
-               {               
-                       if(subs->event->type & WINFO_TYPE)      
-                       {       
+               else 
+               {
+                       if(subs->event->type & WINFO_TYPE)
+                       {
                                notify_body = get_wi_notify_body(subs, watcher_subs);
                                if(notify_body == NULL)
                                {
@@ -1524,7 +1473,6 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs,
                                else            /* apply authorization rules if exists */
                                if(subs->event->req_auth)
                                {
-                                        
                                        if(subs->auth_rules_doc && subs->event->apply_auth_nbody
                                                        && subs->event->apply_auth_nbody(notify_body,
                                                                subs,&final_body)<0)
@@ -1542,12 +1490,12 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs,
                        }
                }
        }
-       
+
 jump_over_body:
 
        if(subs->expires<= 0)
        {
-        subs->expires= 0;
+               subs->expires= 0;
                subs->status= TERMINATED_STATUS;
                subs->reason.s= "timeout";
                subs->reason.len= 7;
@@ -1558,7 +1506,7 @@ jump_over_body:
        {
                LM_ERR("while building headers\n");
                goto error;
-       }       
+       }
        LM_DBG("headers:\n%.*s\n", str_hdr.len, str_hdr.s);
 
        /* construct the dlg_t structure */
@@ -1566,15 +1514,20 @@ jump_over_body:
        if(td ==NULL)
        {
                LM_ERR("while building dlg_t structure\n");
-               goto error;     
+               goto error;
        }
 
-       cb_param = shm_dup_cbparam(subs);
-       if(cb_param == NULL)
+       LM_DBG("expires %d status %d\n", subs->expires, subs->status);
+       /* if status is TERMINATED_STATUS, the subscription will be deleted so no need to send a parameter */
+       if(subs->status != TERMINATED_STATUS)
        {
-               LM_ERR("while duplicating cb_param in share memory\n");
-               goto error;     
-       }       
+               cb_param = shm_dup_cbparam(subs);
+               if(cb_param == NULL)
+               {
+                       LM_ERR("while duplicating cb_param in share memory\n");
+                       goto error;
+               }
+       }
 
        set_uac_req(&uac_r, &met, &str_hdr, notify_body, td, TMCB_LOCAL_COMPLETED,
                        p_tm_callback, (void*)cb_param);
@@ -1582,8 +1535,9 @@ jump_over_body:
        if(result< 0)
        {
                LM_ERR("in function tmb.t_request_within\n");
-               free_cbparam(cb_param);
-               goto error;     
+               if(cb_param)
+                       free_cbparam(cb_param);
+               goto error;
        }
 
        LM_INFO("NOTIFY %.*s via %.*s on behalf of %.*s for event %.*s\n",
@@ -1622,7 +1576,7 @@ error:
                        }
                        pkg_free(notify_body);
                }
-       }       
+       }
        return -1;
 }
 
@@ -1636,17 +1590,17 @@ int notify(subs_t* subs, subs_t * watcher_subs,str* n_body,int force_null_body)
                hash_code= core_hash(&subs->pres_uri, &subs->event->name, shtable_size);
 
                /* if subscriptions are held also in memory, update the subscription hashtable */
-               if(dbmode != DB_ONLY)
+               if(subs_dbmode != DB_ONLY)
                {
-                       if(update_shtable(subs_htable, hash_code, subs, LOCAL_TYPE) < 0 && dbmode == DB_MEMORY_ONLY)
+                       if(update_shtable(subs_htable, hash_code, subs, LOCAL_TYPE) < 0)
                        {
                                /* subscriptions are held only in memory, and hashtable update failed */
                                LM_ERR("updating subscription record in hash table\n");
                                return -1;
                        }
                }
-               /* if dbonly mode, or if fallback2db mode and the subscription was inserted into the database */
-               if((dbmode == DB_ONLY) || (subs->db_flag != INSERTDB_FLAG && dbmode == DB_FALLBACK))
+               /* if DB_ONLY mode or WRITE_THROUGH update in database */
+               if(subs_dbmode == DB_ONLY || subs_dbmode == WRITE_THROUGH)
                {
                        LM_DBG("updating subscription to database\n");
                        if(update_subs_db(subs, LOCAL_TYPE)< 0)
@@ -1656,7 +1610,7 @@ int notify(subs_t* subs, subs_t * watcher_subs,str* n_body,int force_null_body)
                        }
                }
        }
-     
+
        if(subs->reason.s && subs->status== ACTIVE_STATUS && 
        subs->reason.len== 12 && strncmp(subs->reason.s, "polite-block", 12)== 0)
        {
@@ -1673,36 +1627,27 @@ int notify(subs_t* subs, subs_t * watcher_subs,str* n_body,int force_null_body)
 
 void p_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
 {
-       if(ps->param==NULL || *ps->param==NULL || 
-                       ((c_back_param*)(*ps->param))->pres_uri.s == NULL || 
+       c_back_param*  cb;
+
+       if(ps->param==NULL || *ps->param==NULL ||
+                       ((c_back_param*)(*ps->param))->pres_uri.s == NULL ||
                        ((c_back_param*)(*ps->param))->ev_name.s== NULL ||
                        ((c_back_param*)(*ps->param))->to_tag.s== NULL)
        {
-               LM_DBG("message id not received\n");
+               LM_DBG("message id not received, probably a timeout notify\n");
                if(ps->param != NULL && *ps->param !=NULL)
                        free_cbparam((c_back_param*)(*ps->param));
                return;
        }
-       
-       LM_DBG("completed with status %d [to_tag:%.*s]\n",
-                       ps->code,((c_back_param*)(*ps->param))->to_tag.len,
-                       ((c_back_param*)(*ps->param))->to_tag.s);
 
-       if(ps->code >= 300 && (ps->code != 408 || timeout_rm_subs))
-       {
-               unsigned int hash_code;
-
-               c_back_param*  cb= (c_back_param*)(*ps->param);
-
-               hash_code= core_hash(&cb->pres_uri, &cb->ev_name, shtable_size);
-               delete_shtable(subs_htable, hash_code, cb->to_tag);
+       cb= (c_back_param*)(*ps->param);
+       LM_DBG("completed with status %d [to_tag:%.*s]\n",
+                       ps->code, cb->to_tag.len, cb->to_tag.s);
 
-               delete_db_subs(cb->pres_uri, cb->ev_name, cb->to_tag);
-       }       
+       if(ps->code == 481 || (ps->code == 408 && timeout_rm_subs))
+               delete_subs(&cb->pres_uri, &cb->ev_name, &cb->to_tag);
 
-       if(*ps->param !=NULL  )
-               free_cbparam((c_back_param*)(*ps->param));
-       return ;
+       free_cbparam(cb);
 }
 
 void free_cbparam(c_back_param* cb_param)
index 1e8eba1..9a03f56 100644 (file)
@@ -23,7 +23,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*! \file
index bd7cb15..58ddbd4 100644 (file)
@@ -19,7 +19,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*!
@@ -134,11 +134,11 @@ int expires_offset = 0;
 int max_expires= 3600;
 int shtable_size= 9;
 shtable_t subs_htable= NULL;
-int dbmode = 0;
-int fallback2db = 0;
+int subs_dbmode = WRITE_BACK;
 int sphere_enable= 0;
 int timeout_rm_subs = 1;
 int send_fast_notify = 1;
+int publ_cache_enabled = 1;
 
 int phtable_size= 9;
 phtable_t* pres_htable=NULL;
@@ -175,11 +175,11 @@ static param_export_t params[]={
        { "server_address",         STR_PARAM, &server_address.s},
        { "subs_htable_size",       INT_PARAM, &shtable_size},
        { "pres_htable_size",       INT_PARAM, &phtable_size},
-       { "db_mode",                INT_PARAM, &dbmode},
-       { "fallback2db",            INT_PARAM, &fallback2db},
+       { "subs_db_mode",           INT_PARAM, &subs_dbmode},
+       { "publ_cache",             INT_PARAM, &publ_cache_enabled},
        { "enable_sphere_check",    INT_PARAM, &sphere_enable},
        { "timeout_rm_subs",        INT_PARAM, &timeout_rm_subs},
-       { "send_fast_notify",       INT_PARAM, &send_fast_notify},
+       { "send_fast_notify",       INT_PARAM, &send_fast_notify},
        { "fetch_rows",             INT_PARAM, &pres_fetch_rows},
     {0,0,0}
 };
@@ -226,15 +226,15 @@ static int mod_init(void)
        if(db_url.s== NULL)
                library_mode= 1;
 
+       EvList= init_evlist();
+       if(!EvList){
+               LM_ERR("unsuccessful initialize event list\n");
+               return -1;
+       }
+
        if(library_mode== 1)
        {
                LM_DBG("Presence module used for API library purpose only\n");
-               EvList= init_evlist();
-               if(!EvList)
-               {
-                       LM_ERR("unsuccessful initialize event list\n");
-                       return -1;
-               }
                return 0;
        }
 
@@ -298,33 +298,29 @@ static int mod_init(void)
        
        /*verify table versions */
        if((db_check_table_version(&pa_dbf, pa_db, &presentity_table, P_TABLE_VERSION) < 0) ||
-               (db_check_table_version(&pa_dbf, pa_db, &active_watchers_table, ACTWATCH_TABLE_VERSION) < 0) ||
                (db_check_table_version(&pa_dbf, pa_db, &watchers_table, S_TABLE_VERSION) < 0)) {
                        LM_ERR("error during table version check\n");
                        return -1;
        }
 
-       EvList= init_evlist();
-       if(!EvList)
-       {
-               LM_ERR("initializing event list\n");
+       if(subs_dbmode != NO_DB &&
+               db_check_table_version(&pa_dbf, pa_db, &active_watchers_table, ACTWATCH_TABLE_VERSION) < 0) {
+               LM_ERR("wrong table version for %s\n", active_watchers_table.s);
                return -1;
        }
 
-       if(shtable_size< 1)
-               shtable_size= 512;
-       else
-               shtable_size= 1<< shtable_size;
-
-       subs_htable= new_shtable(shtable_size);
-       if(subs_htable== NULL)
-       {
-               LM_ERR(" initializing subscribe hash table\n");
-               return -1;
-       }
+       if(subs_dbmode != DB_ONLY) {
+               if(shtable_size< 1)
+                       shtable_size= 512;
+               else
+                       shtable_size= 1<< shtable_size;
 
-       if(dbmode != DB_ONLY)
-       {
+               subs_htable= new_shtable(shtable_size);
+               if(subs_htable== NULL)
+               {
+                       LM_ERR(" initializing subscribe hash table\n");
+                       return -1;
+               }
                if(restore_db_subs()< 0)
                {
                        LM_ERR("restoring subscribe info from database\n");
@@ -332,8 +328,7 @@ static int mod_init(void)
                }
        }
 
-       if(dbmode != DB_ONLY)
-       {       
+       if(publ_cache_enabled) {
                if(phtable_size< 1)
                        phtable_size= 256;
                else
@@ -354,31 +349,18 @@ static int mod_init(void)
        }
 
        startup_time = (int) time(NULL);
-       
        if(clean_period>0)
        {
                register_timer(msg_presentity_clean, 0, clean_period);
                register_timer(msg_watchers_clean, 0, clean_period);
        }
-       
+
        if(db_update_period>0)
                register_timer(timer_db_update, 0, db_update_period);
 
-       if(pa_db)
-               pa_dbf.close(pa_db);
+       pa_dbf.close(pa_db);
        pa_db = NULL;
-       
-       /* for legacy, we also keep the fallback2db parameter, but make sure for consistency */
-       if(fallback2db)
-       {
-               if (dbmode == DB_ONLY) 
-                       LM_ERR( "fallback2db ignored as in DB_ONLY mode\n" );
-               else
-                       dbmode = DB_FALLBACK;
-       }
 
-       if (dbmode == DB_ONLY)
-               LM_INFO( "Database mode set to DB_ONLY\n" );
        return 0;
 }
 
@@ -387,7 +369,7 @@ static int mod_init(void)
  */
 static int child_init(int rank)
 {
-       if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
+       if (rank==PROC_INIT || rank==PROC_TCP_MAIN)
                return 0; /* do nothing for the main process */
 
        pid = my_pid();
@@ -409,7 +391,7 @@ static int child_init(int rank)
                return -1;
        }
        
-       if (pa_dbf.use_table(pa_db, &presentity_table) < 0)  
+       if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
        {
                LM_ERR( "child %d:unsuccessful use_table presentity_table\n", rank);
                return -1;
@@ -491,7 +473,7 @@ static void destroy(void)
 
        if(pa_db && pa_dbf.close)
                pa_dbf.close(pa_db);
-       
+
        destroy_evlist();
 }
 
@@ -1045,18 +1027,18 @@ send_notify:
                        goto done;
                }
 
-        /* delete from database also */
-        if(s->status== TERMINATED_STATUS)
-        {
-            if(pres_db_delete_status(s)<0)
-            {
-                err_ret= -1;
-                LM_ERR("failed to delete terminated dialog from database\n");
-                goto done;
-            }
-        }
+               /* delete from database also */
+               if(s->status== TERMINATED_STATUS)
+               {
+                       if(pres_db_delete_status(s)<0)
+                       {
+                               err_ret= -1;
+                               LM_ERR("failed to delete terminated dialog from database\n");
+                               goto done;
+                       }
+               }
 
-        s= s->next;
+               s= s->next;
        }
 
        free_subs_list(subs_array, PKG_MEM_TYPE, 0);
@@ -1316,7 +1298,7 @@ static int update_pw_dialogs(subs_t* subs, unsigned int hash_code, subs_t** subs
 
        LM_DBG("start\n");
 
-       if (dbmode == DB_ONLY) return(update_pw_dialogs_dbonlymode(subs, subs_array));
+       if (subs_dbmode == DB_ONLY) return(update_pw_dialogs_dbonlymode(subs, subs_array));
 
        lock_get(&subs_htable[hash_code].lock);
        
index 7d4ba08..fc0c9ec 100644 (file)
@@ -20,7 +20,7 @@
  *
  * History:
  * ---------
- *  2006-10-09  first version (anca)
+ *  2006-10-09  first version (Anca Vamanu)
  */
 
 /*!
 
 /* DB modes */
 
-/** subscriptions are held in memory and periodically updated to db, but retrieved from db only at startup */
-#define DB_MEMORY_ONLY 0
-/** same as memory_only, but if a subscription is not found, it falls back to db */
-#define DB_FALLBACK 1
-/** subscriptions are held only in database */
-#define DB_ONLY 2
+/** subscriptions are stored only in memory */
+#define NO_DB            0
+/** subscriptions are written in memory and in DB synchronously and read only from memory */
+#define WRITE_THROUGH    1
+/** subscriptions are stored in memory and periodically updated in DB */
+#define WRITE_BACK       2
+/** subscriptions are stored only in database */
+#define DB_ONLY          3
 
 /** TM bind */
 extern struct tm_binds tmb;
@@ -72,7 +74,8 @@ extern char *to_tag_pref;
 extern int expires_offset;
 extern str server_address;
 extern int max_expires;
-extern int dbmode;
+extern int subs_dbmode;
+extern int publ_cache_enabled;
 extern int sphere_enable;
 extern int timeout_rm_subs;
 extern int send_fast_notify;
index 0762da0..e315c98 100644 (file)
@@ -19,7 +19,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*!
@@ -339,7 +339,7 @@ int update_presentity(struct sip_msg* msg, presentity_t* presentity, str* body,
        {
                /* insert new record in hash_table */
 
-               if ( dbmode != DB_ONLY && 
+               if ( publ_cache_enabled &&
                        insert_phtable(&pres_uri, presentity->event->evp->type, sphere)< 0)
                {
                        LM_ERR("inserting record in hash table\n");
@@ -491,8 +491,7 @@ after_dialog_check:
                                                presentity->user.s);
 
                                /* delete from hash table */
-       
-                               if(dbmode != DB_ONLY && 
+                               if( publ_cache_enabled &&
                                        delete_phtable(&pres_uri, presentity->event->evp->type)< 0)
                                {
                                        LM_ERR("deleting record from hash table\n");
@@ -588,8 +587,8 @@ after_dialog_check:
                                if(sphere_enable && 
                                                presentity->event->evp->type== EVENT_PRESENCE)
                                {
-                                       if(dbmode != DB_ONLY && 
-                                               update_phtable(presentity, pres_uri, *body)< 0)
+                                       if( publ_cache_enabled &&
+                                                       update_phtable(presentity, pres_uri, *body)< 0)
                                        {
                                                LM_ERR("failed to update sphere for presentity\n");
                                                goto error;
@@ -690,7 +689,7 @@ int pres_htable_restore(void)
         * in presentity table */
        db_key_t result_cols[6];
        db1_res_t *result= NULL;
-       db_row_t *row= NULL ;   
+       db_row_t *row= NULL ;
        db_val_t *row_vals;
        int  i;
        str user, domain, ev_str, uri, body;
@@ -700,12 +699,6 @@ int pres_htable_restore(void)
        event_t ev;
        char* sphere= NULL;
 
-       if ( dbmode == DB_ONLY )
-       {
-               LM_ERR( "Can't restore when dbmode is DB_ONLY\n" );
-               return(-1);
-       } 
-
        result_cols[user_col= n_result_cols++]= &str_username_col;
        result_cols[domain_col= n_result_cols++]= &str_domain_col;
        result_cols[event_col= n_result_cols++]= &str_event_col;
@@ -718,6 +711,7 @@ int pres_htable_restore(void)
                LM_ERR("unsuccessful use table sql operation\n");
                goto error;
        }
+
        static str query_str = str_init("username");
        if (db_fetch_query(&pa_dbf, pres_fetch_rows, pa_db, 0, 0, 0, result_cols,
                                0, n_result_cols, &query_str, &result) < 0)
@@ -875,7 +869,7 @@ char* get_sphere(str* pres_uri)
        db_val_t query_vals[6];
        db_key_t result_cols[6];
        db1_res_t *result = NULL;
-       db_row_t *row= NULL ;   
+       db_row_t *row= NULL;
        db_val_t *row_vals;
        int n_result_cols = 0;
        int n_query_cols = 0;
@@ -886,7 +880,7 @@ char* get_sphere(str* pres_uri)
        if(!sphere_enable)
                return NULL;
 
-       if ( dbmode != DB_ONLY )
+       if ( publ_cache_enabled )
        {
                /* search in hash table*/
                hash_code= core_hash(pres_uri, NULL, phtable_size);
@@ -913,12 +907,6 @@ char* get_sphere(str* pres_uri)
                lock_release(&pres_htable[hash_code].lock);
        }
 
-       /* if record not found and subscriptions are held also in database, query database*/
-       if(dbmode == DB_MEMORY_ONLY)
-       {
-               return NULL;
-       }
-
        if(parse_uri(pres_uri->s, pres_uri->len, &uri)< 0)
        {
                LM_ERR("failed to parse presentity uri\n");
index 2d5e9e5..bf671cb 100644 (file)
@@ -19,7 +19,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*!
index 15b3f8f..a89b585 100644 (file)
@@ -19,7 +19,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*!
@@ -68,7 +68,7 @@ void msg_presentity_clean(unsigned int ticks,void *param)
        db_op_t  db_ops[2] ;
        db_key_t result_cols[6];
        db1_res_t *result = NULL;
-       db_row_t *row ; 
+       db_row_t *row ;
        db_val_t *row_vals ;
        int i =0, size= 0;
        struct p_modif* p= NULL;
@@ -81,20 +81,19 @@ void msg_presentity_clean(unsigned int ticks,void *param)
        str* rules_doc= NULL;
 
 
+       LM_DBG("cleaning expired presentity information\n");
        if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
        {
                LM_ERR("in use_table\n");
                return ;
        }
-       
-       LM_DBG("cleaning expired presentity information\n");
 
        db_keys[0] = &str_expires_col;
        db_ops[0] = OP_LT;
        db_vals[0].type = DB1_INT;
        db_vals[0].nul = 0;
        db_vals[0].val.int_val = (int)time(NULL);
-               
+
        result_cols[user_col= n_result_cols++] = &str_username_col;
        result_cols[domain_col=n_result_cols++] = &str_domain_col;
        result_cols[etag_col=n_result_cols++] = &str_etag_col;
@@ -104,32 +103,32 @@ void msg_presentity_clean(unsigned int ticks,void *param)
        if(pa_dbf.query(pa_db, db_keys, db_ops, db_vals, result_cols,
                                                1, n_result_cols, &query_str, &result )< 0)
        {
-               LM_ERR("querying database for expired messages\n");
+               LM_ERR("failed to query database for expired messages\n");
                if(result)
                        pa_dbf.free_result(pa_db, result);
-               return;
+               goto delete_pres;
        }
        if(result== NULL)
                return;
 
        if(result && result->n<= 0)
        {
-               pa_dbf.free_result(pa_db, result);      
+               pa_dbf.free_result(pa_db, result);
                return;
        }
        LM_DBG("found n= %d expires messages\n ",result->n);
 
        n= result->n;
-       
+
        p= (struct p_modif*)pkg_malloc(n* sizeof(struct p_modif));
        if(p== NULL)
        {
-               ERR_MEM(PKG_MEM_STR);   
+               ERR_MEM(PKG_MEM_STR);
        }
        memset(p, 0, n* sizeof(struct p_modif));
 
        for(i = 0; i< n; i++)
-       {       
+       {
                row = &result->rows[i];
                row_vals = ROW_VALUES(row);     
        
@@ -154,8 +153,8 @@ void msg_presentity_clean(unsigned int ticks,void *param)
                }
                memset(pres, 0, size);
                size= sizeof(presentity_t);
-               
-               pres->user.s= (char*)pres+ size;        
+
+               pres->user.s= (char*)pres+ size;
                memcpy(pres->user.s, user.s, user.len);
                pres->user.len= user.len;
                size+= user.len;
@@ -176,7 +175,7 @@ void msg_presentity_clean(unsigned int ticks,void *param)
                        LM_ERR("event not found\n");
                        free_event_params(ev.params.list, PKG_MEM_TYPE);
                        goto error;
-               }       
+               }
        
                p[i].p= pres;
                if(uandd_to_uri(user, domain, &p[i].uri)< 0)
@@ -187,7 +186,7 @@ void msg_presentity_clean(unsigned int ticks,void *param)
                }
                
                /* delete from hash table */
-               if(dbmode != DB_ONLY && delete_phtable(&p[i].uri, ev.type)< 0)
+               if(publ_cache_enabled && delete_phtable(&p[i].uri, ev.type)< 0)
                {
                        LM_ERR("deleting from pres hash table\n");
                        free_event_params(ev.params.list, PKG_MEM_TYPE);
@@ -224,26 +223,20 @@ void msg_presentity_clean(unsigned int ticks,void *param)
                        pkg_free(rules_doc);
                }
                rules_doc= NULL;
+               pkg_free(p[i].p);
+               pkg_free(p[i].uri.s);
        }
+       pkg_free(p);
 
-       if (pa_dbf.use_table(pa_db, &presentity_table) < 0) 
+       if (pa_dbf.use_table(pa_db, &presentity_table) < 0)
        {
                LM_ERR("in use_table\n");
                goto error;
        }
-       
-       if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, 1) < 0) 
-               LM_ERR("cleaning expired messages\n");
-       
-       for(i= 0; i< n; i++)
-       {
-               if(p[i].p)
-                       pkg_free(p[i].p);
-               if(p[i].uri.s)
-                       pkg_free(p[i].uri.s);
 
-       }
-       pkg_free(p);
+delete_pres:
+       if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, 1) < 0) 
+               LM_ERR("failed to delete expired records from DB\n");
 
        return;
 
@@ -254,7 +247,6 @@ error:
        {
                for(i= 0; i< n; i++)
                {
-                       
                        if(p[i].p)
                                pkg_free(p[i].p);
                        if(p[i].uri.s)
@@ -271,7 +263,7 @@ error:
                pkg_free(rules_doc);
        }
 
-       return; 
+       return;
 }
 
 /**
index 5960e24..f5ca80a 100644 (file)
@@ -19,7 +19,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*!
index 7f40872..3bd6fc6 100644 (file)
@@ -23,7 +23,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*! \file
@@ -138,7 +138,7 @@ error:
 }
 
 
-int delete_db_subs(str pres_uri, str ev_stored_name, str to_tag)
+int delete_db_subs(str* pres_uri, str* ev_stored_name, str* to_tag)
 {
        db_key_t query_cols[5];
        db_val_t query_vals[5];
@@ -147,19 +147,19 @@ int delete_db_subs(str pres_uri, str ev_stored_name, str to_tag)
        query_cols[n_query_cols] = &str_presentity_uri_col;
        query_vals[n_query_cols].type = DB1_STR;
        query_vals[n_query_cols].nul = 0;
-       query_vals[n_query_cols].val.str_val = pres_uri;
+       query_vals[n_query_cols].val.str_val = *pres_uri;
        n_query_cols++;
 
        query_cols[n_query_cols] = &str_event_col;
        query_vals[n_query_cols].type = DB1_STR;
        query_vals[n_query_cols].nul = 0;
-       query_vals[n_query_cols].val.str_val = ev_stored_name;
+       query_vals[n_query_cols].val.str_val = *ev_stored_name;
        n_query_cols++;
 
        query_cols[n_query_cols] = &str_to_tag_col;
        query_vals[n_query_cols].type = DB1_STR;
        query_vals[n_query_cols].nul = 0;
-       query_vals[n_query_cols].val.str_val = to_tag;
+       query_vals[n_query_cols].val.str_val = *to_tag;
        n_query_cols++;
        
        if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) 
@@ -405,37 +405,40 @@ int update_subs_db(subs_t* subs, int type)
        return 0;
 }
 
+void delete_subs(str* pres_uri, str* ev_name, str* to_tag)
+{
+       /* delete record from hash table also if not in dbonly mode */
+       if(subs_dbmode != DB_ONLY)
+       {
+               unsigned int hash_code= core_hash(pres_uri, ev_name, shtable_size);
+               if(delete_shtable(subs_htable, hash_code, *to_tag) < 0)
+                       LM_ERR("Failed to delete subscription from memory\n");
+       }
+
+       if(subs_dbmode != NO_DB && delete_db_subs(pres_uri, ev_name, to_tag)< 0)
+               LM_ERR("Failed to delete subscription from database\n");
+}
+
+
 int update_subscription(struct sip_msg* msg, subs_t* subs, int to_tag_gen,
                int* sent_reply)
-{      
+{
        unsigned int hash_code;
-       
-       printf_subs(subs);      
-       
-       *sent_reply= 0;
 
-       hash_code= core_hash(&subs->pres_uri, &subs->event->name, shtable_size);
+       printf_subs(subs);
+
+       *sent_reply= 0;
 
        if( to_tag_gen ==0) /*if a SUBSCRIBE within a dialog */
        {
                if(subs->expires == 0)
                {
                        LM_DBG("expires =0 -> deleting record\n");
-               
-                       if( delete_db_subs(subs->pres_uri, 
-                                               subs->event->name, subs->to_tag)< 0)
-                       {
-                               LM_ERR("deleting subscription record from database\n");
-                               goto error;
-                       }
-                       /* delete record from hash table also if not in dbonly mode */
-                       if(dbmode != DB_ONLY)
-                       {
-                               subs->local_cseq= delete_shtable(subs_htable, hash_code, subs->to_tag);
-                       }
-               
+
+                       delete_subs(&subs->pres_uri, &subs->event->name, &subs->to_tag);
+
                        if(subs->event->type & PUBL_TYPE)
-                       {       
+                       {
                                if( send_2XX_reply(msg, 202, subs->expires,
                                                        &subs->local_contact) <0)
                                {
@@ -453,7 +456,7 @@ int update_subscription(struct sip_msg* msg, subs_t* subs, int to_tag_gen,
                                        }
                                }
 
-                       }       
+                       }
                        else /* if unsubscribe for winfo */
                        {
                                if( send_2XX_reply(msg, 200, subs->expires,
@@ -472,21 +475,18 @@ int update_subscription(struct sip_msg* msg, subs_t* subs, int to_tag_gen,
                        }
                        return 1;
                }
-               /* if subscribers are held in memory, update them */
-               if(dbmode != DB_ONLY)
+               /* if subscriptions are stored in memory, update them */
+               if(subs_dbmode != DB_ONLY)
                {
+                       hash_code= core_hash(&subs->pres_uri, &subs->event->name, shtable_size);
                        if(update_shtable(subs_htable, hash_code, subs, REMOTE_TYPE)< 0)
                        {
-                               /* if subscribers are also retrieved from database, it is not a fatal error */
-                               if(dbmode != DB_MEMORY_ONLY)
-                               {
-                                       LM_ERR("updating subscription record in hash table\n");
-                                       goto error;
-                               }
+                               LM_ERR("failed to update subscription in memory\n");
+                               goto error;
                        }
                }
-               /* if subscribers are retrieved from db also, update the subscription in database immediately */
-               if(dbmode != DB_MEMORY_ONLY)
+               /* for modes that update the subscription synchronously in database, write in db */
+               if(subs_dbmode == DB_ONLY ||  subs_dbmode== WRITE_THROUGH)
                {
                        /* update in database table */
                        if(update_subs_db(subs, REMOTE_TYPE)< 0)
@@ -501,20 +501,23 @@ int update_subscription(struct sip_msg* msg, subs_t* subs, int to_tag_gen,
                LM_DBG("subscription not in dialog\n");
                if(subs->expires!= 0)
                {
-                       if(dbmode != DB_ONLY)
+                       if(subs_dbmode != DB_ONLY)
                        {
                                LM_DBG("inserting in shtable\n");
+                               subs->db_flag = (subs_dbmode==WRITE_THROUGH)?WTHROUGHDB_FLAG:INSERTDB_FLAG;
+                               hash_code= core_hash(&subs->pres_uri, &subs->event->name, shtable_size);
                                if(insert_shtable(subs_htable,hash_code,subs)< 0)
                                {
-                                       LM_ERR("inserting new record in subs_htable\n");
+                                       LM_ERR("failed to insert new record in subs htable\n");
                                        goto error;
                                }
                        }
-                       else
+
+                       if(subs_dbmode == DB_ONLY || subs_dbmode == WRITE_THROUGH)
                        {
                                if(insert_subs_db(subs, REMOTE_TYPE) < 0)
                                {
-                                       LM_ERR("inserting new record in db\n");
+                                       LM_ERR("failed to insert new record in database\n");
                                        goto error;
                                }
                        }
@@ -594,13 +597,12 @@ error:
 
 void msg_watchers_clean(unsigned int ticks,void *param)
 {
-       db_key_t db_keys[3], result_cols[1];
-       db_val_t db_vals[3];
-       db_op_t  db_ops[3] ;
-       db1_res_t *result= NULL;
+       db_key_t db_keys[2];
+       db_val_t db_vals[2];
+       db_op_t  db_ops[2] ;
 
        LM_DBG("cleaning pending subscriptions\n");
-       
+
        db_keys[0] = &str_inserted_time_col;
        db_ops[0] = OP_LT;
        db_vals[0].type = DB1_INT;
@@ -612,32 +614,14 @@ void msg_watchers_clean(unsigned int ticks,void *param)
        db_vals[1].type = DB1_INT;
        db_vals[1].nul = 0;
        db_vals[1].val.int_val = PENDING_STATUS;
-       
-       result_cols[0]= &str_id_col;
 
        if (pa_dbf.use_table(pa_db, &watchers_table) < 0) 
        {
                LM_ERR("unsuccessful use table sql operation\n");
                return ;
        }
-       
-       if(pa_dbf.query(pa_db, db_keys, db_ops, db_vals, result_cols, 2, 1, 0, &result )< 0)
-       {
-               LM_ERR("querying database for expired messages\n");
-               if(result)
-                       pa_dbf.free_result(pa_db, result);
-               return;
-       }
-       if(result == NULL)
-               return;
-       if(result->n <= 0)
-       {
-               pa_dbf.free_result(pa_db, result);
-               return;
-       }
-       pa_dbf.free_result(pa_db, result);
 
-       if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, 2) < 0) 
+       if (pa_dbf.delete(pa_db, db_keys, db_ops, db_vals, 2) < 0)
                LM_ERR("cleaning pending subscriptions\n");
 }
 
@@ -703,7 +687,7 @@ int handle_subscribe(struct sip_msg* msg, char* str1, char* str2)
                        break;
                }
                ev_param= ev_param->next;
-       }               
+       }
        
        if(extract_sdialog_info(&subs, msg, max_expires, &to_tag_gen,
                                server_address)< 0)
@@ -1117,12 +1101,15 @@ error:
 
 int get_stored_info(struct sip_msg* msg, subs_t* subs, int* reply_code,
                str* reply_str)
-{      
+{
        str pres_uri= {0, 0}, reason={0, 0};
        subs_t* s;
        int i;
        unsigned int hash_code;
 
+       if(subs_dbmode == DB_ONLY)
+               return get_database_info(msg, subs, reply_code, reply_str);
+
        /* first try to_user== pres_user and to_domain== pres_domain */
        if(subs->pres_uri.s == NULL)
        {
@@ -1138,18 +1125,16 @@ int get_stored_info(struct sip_msg* msg, subs_t* subs, int* reply_code,
 
        hash_code= core_hash(&pres_uri, &subs->event->name, shtable_size);
        lock_get(&subs_htable[hash_code].lock);
-       i= hash_code;
        s= search_shtable(subs_htable, subs->callid, subs->to_tag,
-                       subs->from_tag, hash_code);
+               subs->from_tag, hash_code);
        if(s)
-       {
                goto found_rec;
-       }
+
        lock_release(&subs_htable[hash_code].lock);
 
        if(subs->pres_uri.s)
                goto not_found;
-       
+
        pkg_free(pres_uri.s);
        pres_uri.s= NULL;
 
@@ -1161,49 +1146,36 @@ int get_stored_info(struct sip_msg* msg, subs_t* subs, int* reply_code,
                s= search_shtable(subs_htable, subs->callid,subs->to_tag,subs->from_tag, i);
                if (s)
                {
-                       if(!EVENT_DIALOG_SLA(s->event->evp))
+                       pres_uri.s= (char*)pkg_malloc(s->pres_uri.len* sizeof(char));
+                       if(pres_uri.s== NULL)
                        {
-                               pres_uri.s= (char*)pkg_malloc(s->pres_uri.len* sizeof(char));
-                               if(pres_uri.s== NULL)
-                               {
-                                       lock_release(&subs_htable[i].lock);
-                                       ERR_MEM(PKG_MEM_STR);
-                               }
-                               memcpy(pres_uri.s, s->pres_uri.s, s->pres_uri.len);
-                               pres_uri.len= s->pres_uri.len;
+                               lock_release(&subs_htable[i].lock);
+                               ERR_MEM(PKG_MEM_STR);
                        }
-                       goto found_rec;
+                       memcpy(pres_uri.s, s->pres_uri.s, s->pres_uri.len);
+                       pres_uri.len= s->pres_uri.len;
+
+                       hash_code = i;
+                       break;
                }
                lock_release(&subs_htable[i].lock);
        }
 
-not_found:
-       if(dbmode != DB_MEMORY_ONLY)
-       {
-               return get_database_info(msg, subs, reply_code, reply_str);
-       }
-
-       LM_INFO("record not found in hash_table\n");
-       *reply_code= 481;
-       *reply_str= pu_481_rpl;
-
-       return -1;
-
 found_rec:
 
        LM_DBG("Record found in hash_table\n");
 
-       if(!EVENT_DIALOG_SLA(s->event->evp))
+       if(subs->pres_uri.s == NULL)
                subs->pres_uri= pres_uri;
 
        subs->version = s->version;
        subs->status= s->status;
        if(s->reason.s && s->reason.len)
-       {       
+       {
                reason.s= (char*)pkg_malloc(s->reason.len* sizeof(char));
                if(reason.s== NULL)
                {
-                       lock_release(&subs_htable[i].lock);
+                       lock_release(&subs_htable[hash_code].lock);
                        ERR_MEM(PKG_MEM_STR);
                }
                memcpy(reason.s, s->reason.s, s->reason.len);
@@ -1216,6 +1188,7 @@ found_rec:
                        (s->record_route.len* sizeof(char));
                if(subs->record_route.s== NULL)
                {
+                       lock_release(&subs_htable[hash_code].lock);
                        ERR_MEM(PKG_MEM_STR);
                }
                memcpy(subs->record_route.s, s->record_route.s, s->record_route.len);
@@ -1223,7 +1196,7 @@ found_rec:
        }
 
        subs->local_cseq= s->local_cseq;
-       
+
        if(subs->remote_cseq<= s->remote_cseq)
        {
                LM_ERR("wrong sequence number;received: %d - stored: %d\n",
@@ -1232,13 +1205,21 @@ found_rec:
                *reply_code= 400;
                *reply_str= pu_400_rpl;
 
-               lock_release(&subs_htable[i].lock);
+               lock_release(&subs_htable[hash_code].lock);
                goto error;
-       }       
-       lock_release(&subs_htable[i].lock);
+       }
+       lock_release(&subs_htable[hash_code].lock);
 
        return 0;
 
+not_found:
+
+       LM_INFO("record not found in hash_table\n");
+       *reply_code= 481;
+       *reply_str= pu_481_rpl;
+
+       return -1;
+
 error:
        if(subs->reason.s)
                pkg_free(subs->reason.s);
@@ -1250,7 +1231,7 @@ error:
 }
 
 int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* reply_str)
-{      
+{
        db_key_t query_cols[3];
        db_val_t query_vals[3];
        db_key_t result_cols[7];
@@ -1410,47 +1391,229 @@ int handle_expired_subs(subs_t* s)
 
 }
 
-void timer_db_update(unsigned int ticks,void *param)
-{      
-       int no_lock=0;
-       LM_DBG("db_update timer\n");
-       if(ticks== 0 && param == NULL)
-               no_lock= 1;
-       
+void update_db_subs_timer_dbonly(void)
+{
+       db_op_t qops[1];
+       db_key_t qcols[1];
+       db_val_t qvals[1];
+       db_key_t result_cols[16];
+       int pres_uri_col, to_user_col, to_domain_col, from_user_col, from_domain_col,
+               callid_col, totag_col, fromtag_col, event_col, event_id_col,
+               local_cseq_col, expires_col, rr_col, sockinfo_col,
+               contact_col, lcontact_col;
+       int n_result_cols = 0;
+       db1_res_t *result= NULL;
+       db_row_t *row = NULL;
+       db_val_t *row_vals= NULL;
+       int i;
+       subs_t s, *s_new, *s_array = NULL, *s_del;
+       str ev_name;
+       pres_ev_t* event;
+
+       LM_DBG("update_db_subs_timer_dbonly: start\n");
+
+       qcols[0]= &str_expires_col;
+       qvals[0].type = DB1_INT;
+       qvals[0].nul = 0;
+       qvals[0].val.int_val= (int)time(NULL) - expires_offset;
+       qops[0]= OP_LT;
+
+       /* query the expired subscriptions */
+       result_cols[pres_uri_col=n_result_cols++]   =&str_presentity_uri_col;
+       result_cols[expires_col=n_result_cols++]    =&str_expires_col;
+       result_cols[event_col=n_result_cols++]      =&str_event_col;
+       result_cols[event_id_col=n_result_cols++]   =&str_event_id_col;
+       result_cols[to_user_col=n_result_cols++]    =&str_to_user_col;
+       result_cols[to_domain_col=n_result_cols++]  =&str_to_domain_col;
+       result_cols[from_user_col=n_result_cols++]  =&str_watcher_username_col;
+       result_cols[from_domain_col=n_result_cols++]=&str_watcher_domain_col;
+       result_cols[callid_col=n_result_cols++]     =&str_callid_col;
+       result_cols[totag_col=n_result_cols++]      =&str_to_tag_col;
+       result_cols[fromtag_col=n_result_cols++]    =&str_from_tag_col;
+       result_cols[local_cseq_col= n_result_cols++]=&str_local_cseq_col;
+       result_cols[rr_col= n_result_cols++]        =&str_record_route_col;
+       result_cols[sockinfo_col= n_result_cols++]  =&str_socket_info_col;
+       result_cols[contact_col= n_result_cols++]   =&str_contact_col;
+       result_cols[lcontact_col= n_result_cols++]  =&str_local_contact_col;
+
        if(pa_dbf.use_table(pa_db, &active_watchers_table)< 0)
        {
                LM_ERR("sql use table failed\n");
                return;
        }
 
-       update_db_subs(pa_db, pa_dbf, subs_htable, 
-                       shtable_size, no_lock, handle_expired_subs);
+       if (pa_dbf.query(pa_db, qcols, qops, qvals, result_cols,
+                               1, n_result_cols, 0, &result) < 0) {
+               LM_ERR("failed to query database for expired subscriptions\n");
+               if(result)
+                       pa_dbf.free_result(pa_db, result);
+               return;
+       }
+
+       if(result== NULL)
+               return;
+
+       if(result->n <=0 ) {
+               pa_dbf.free_result(pa_db, result);
+               return;
+       }
+       LM_DBG("found %d dialogs\n", result->n);
+       
+       for(i=0; i<result->n; i++)
+       {
+               row = &result->rows[i];
+               row_vals = ROW_VALUES(row);
+
+               memset(&s, 0, sizeof(subs_t));
+
+               s.pres_uri.s= (char*)row_vals[pres_uri_col].val.string_val;
+               s.pres_uri.len = strlen(s.pres_uri.s);
+
+               s.to_user.s= (char*)row_vals[to_user_col].val.string_val;
+               s.to_user.len= strlen(s.to_user.s);
+
+               s.to_domain.s= (char*)row_vals[to_domain_col].val.string_val;
+               s.to_domain.len= strlen(s.to_domain.s);
+
+               s.from_user.s= (char*)row_vals[from_user_col].val.string_val;
+               s.from_user.len= strlen(s.from_user.s);
+
+               s.from_domain.s= (char*)row_vals[from_domain_col].val.string_val;
+               s.from_domain.len= strlen(s.from_domain.s);
+
+               s.event_id.s=(char*)row_vals[event_id_col].val.string_val;
+               s.event_id.len= (s.event_id.s)?strlen(s.event_id.s):0;
+
+               s.to_tag.s= (char*)row_vals[totag_col].val.string_val;
+               s.to_tag.len= strlen(s.to_tag.s);
+
+               s.from_tag.s= (char*)row_vals[fromtag_col].val.string_val; 
+               s.from_tag.len= strlen(s.from_tag.s);
+
+               s.callid.s= (char*)row_vals[callid_col].val.string_val;
+               s.callid.len= strlen(s.callid.s);
+
+               s.record_route.s=  (char*)row_vals[rr_col].val.string_val;
+               s.record_route.len= (s.record_route.s)?strlen(s.record_route.s):0;
+
+               s.contact.s= (char*)row_vals[contact_col].val.string_val;
+               s.contact.len= strlen(s.contact.s);
+
+               s.sockinfo_str.s = (char*)row_vals[sockinfo_col].val.string_val;
+               s.sockinfo_str.len = s.sockinfo_str.s?strlen(s.sockinfo_str.s):0;
+
+               s.local_contact.s = (char*)row_vals[lcontact_col].val.string_val;
+               s.local_contact.len = s.local_contact.s?strlen(s.local_contact.s):0;
+
+               ev_name.s= (char*)row_vals[event_col].val.string_val;
+               ev_name.len= strlen(ev_name.s);
+
+               event= contains_event(&ev_name, 0);
+               if(event== NULL) {
+                       LM_ERR("Wrong event in database %.*s\n", ev_name.len, ev_name.s);
+                       continue;
+               }
+               s.event= event;
+
+               s.local_cseq = row_vals[local_cseq_col].val.int_val;
+               s.expires = 0;
+
+               s_new= mem_copy_subs(&s, PKG_MEM_TYPE);
+               if(s_new== NULL)
+               {
+                       LM_ERR("while copying subs_t structure\n");
+                       continue;
+               }
+               s_new->next= s_array;
+               s_array= s_new;
+               printf_subs(s_new);
+       }
+       pa_dbf.free_result(pa_db, result);
+
+       s_new = s_array;
+       while(s_new) {
+               handle_expired_subs(s_new);
+               s_del = s_new;
+               s_new = s_new->next;
+               pkg_free(s_del);
+       }
 
+       /* delete the expired subscriptions */
+       if(pa_dbf.delete(pa_db, qcols, qops, qvals, 1) < 0)
+       {
+               LM_ERR("deleting expired information from database\n");
+       }
 }
 
-void update_db_subs(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
+void update_db_subs_timer_dbnone(int no_lock)
+{
+       int i;
+       int now = (int)time(NULL);
+       subs_t* s= NULL, *prev_s= NULL, *del_s;
+
+       LM_DBG("update_db_subs_timer_dbnone: start\n");
+
+       for(i=0; i<shtable_size; i++) {
+               if(!no_lock)
+                       lock_get(&subs_htable[i].lock);
+
+               prev_s= subs_htable[i].entries;
+               s= prev_s->next;
+
+               while(s) {
+                       printf_subs(s);
+                       if(s->expires < now - expires_offset) {
+                               LM_DBG("Found expired record\n");
+                               if(!no_lock) {
+                                       if(handle_expired_subs(s)< 0) {
+                                               LM_ERR("in function handle_expired_record\n");
+                                       }
+                               }
+                               del_s= s;
+                               s= s->next;
+                               prev_s->next= s;
+
+                               if (del_s->contact.s)
+                                       shm_free(del_s->contact.s);
+                               shm_free(del_s);
+                               continue;
+                       }
+                       prev_s= s;
+                       s= s->next;
+               }
+               if(!no_lock)
+                       lock_release(&subs_htable[i].lock);
+       }
+}
+
+
+
+void update_db_subs_timer(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
        int htable_size, int no_lock, handle_expired_func_t handle_expired_func)
-{      
+{
        db_key_t query_cols[22], update_cols[7];
        db_val_t query_vals[22], update_vals[7];
        db_op_t update_ops[1];
        subs_t* del_s;
        int pres_uri_col, to_user_col, to_domain_col, from_user_col, from_domain_col,
-               callid_col, totag_col, fromtag_col, event_col,status_col, event_id_col, 
-               local_cseq_col, remote_cseq_col, expires_col, record_route_col, 
+               callid_col, totag_col, fromtag_col, event_col,status_col, event_id_col,
+               local_cseq_col, remote_cseq_col, expires_col, record_route_col,
                contact_col, local_contact_col, version_col,socket_info_col,reason_col;
-       int u_expires_col, u_local_cseq_col, u_remote_cseq_col, u_version_col, 
-               u_reason_col, u_status_col; 
+       int u_expires_col, u_local_cseq_col, u_remote_cseq_col, u_version_col,
+               u_reason_col, u_status_col;
        int i;
        subs_t* s= NULL, *prev_s= NULL;
        int n_query_cols= 0, n_update_cols= 0;
        int n_query_update;
+       int now = (int)time(NULL);
+
+       LM_DBG("update_db_subs_timer: start\n");
 
        query_cols[pres_uri_col= n_query_cols] =&str_presentity_uri_col;
        query_vals[pres_uri_col].type = DB1_STR;
        query_vals[pres_uri_col].nul = 0;
        n_query_cols++;
-       
+
        query_cols[callid_col= n_query_cols] =&str_callid_col;
        query_vals[callid_col].type = DB1_STR;
        query_vals[callid_col].nul = 0;
@@ -1477,7 +1640,7 @@ void update_db_subs(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
        query_vals[to_domain_col].type = DB1_STR;
        query_vals[to_domain_col].nul = 0;
        n_query_cols++;
-       
+
        query_cols[from_user_col= n_query_cols] =&str_watcher_username_col;
        query_vals[from_user_col].type = DB1_STR;
        query_vals[from_user_col].nul = 0;
@@ -1491,7 +1654,7 @@ void update_db_subs(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
        query_cols[event_col= n_query_cols] =&str_event_col;
        query_vals[event_col].type = DB1_STR;
        query_vals[event_col].nul = 0;
-       n_query_cols++; 
+       n_query_cols++;
 
        query_cols[event_id_col= n_query_cols] =&str_event_id_col;
        query_vals[event_id_col].type = DB1_STR;
@@ -1573,65 +1736,48 @@ void update_db_subs(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
        update_vals[u_local_cseq_col].type = DB1_INT;
        update_vals[u_local_cseq_col].nul = 0;
        n_update_cols++;
-       
+
        update_cols[u_version_col= n_update_cols]= &str_version_col;
        update_vals[u_version_col].type = DB1_INT;
        update_vals[u_version_col].nul = 0;
        n_update_cols++;
 
-
-       if(db== NULL)
-       {
-               LM_ERR("null database connection\n");
-               return;
-       }
-       
-       /* if in dbonly mode, no update to database is required */
-       if(dbmode == DB_ONLY)
-       {
-               goto delete_expired_subs;
-       }
-       
        for(i=0; i<htable_size; i++) 
        {
                if(!no_lock)
-                       lock_get(&hash_table[i].lock);  
+                       lock_get(&hash_table[i].lock);
 
                prev_s= hash_table[i].entries;
                s= prev_s->next;
-       
+
                while(s)
                {
                        printf_subs(s);
-                       if(s->expires < (int)time(NULL)- expires_offset)        
+                       if(s->expires < now- expires_offset)
                        {
                                LM_DBG("Found expired record\n");
                                if(!no_lock)
                                {
                                        if(handle_expired_func(s)< 0)
-                                       {
                                                LM_ERR("in function handle_expired_record\n");
-                                               if(!no_lock)
-                                                       lock_release(&hash_table[i].lock);      
-                                               return ;
-                                       }
                                }
-                               del_s= s;       
+                               del_s= s;
                                s= s->next;
                                prev_s->next= s;
                                
                                /* need for a struct free/destroy? */
                                if (del_s->contact.s)
                                        shm_free(del_s->contact.s);
-
                                shm_free(del_s);
                                continue;
                        }
                        switch(s->db_flag)
                        {
                                case NO_UPDATEDB_FLAG:
-                                       LM_DBG("NO_UPDATEDB_FLAG\n");
-                                       break;                    
+                               case WTHROUGHDB_FLAG:
+                                       LM_DBG("%s\n", (s->db_flag==NO_UPDATEDB_FLAG)?
+                                                       "NO_UPDATEDB_FLAG":"WTHROUGHDB_FLAG");
+                                       break;
 
                                case UPDATEDB_FLAG:
                                        LM_DBG("UPDATEDB_FLAG\n");
@@ -1653,7 +1799,7 @@ void update_db_subs(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
                                        {
                                                LM_ERR("updating in database\n");
                                        } else {
-                                               s->db_flag= NO_UPDATEDB_FLAG;   
+                                               s->db_flag= NO_UPDATEDB_FLAG;
                                        }
                                        break;
 
@@ -1680,32 +1826,62 @@ void update_db_subs(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
                                        query_vals[status_col].val.int_val= s->status;
                                        query_vals[reason_col].val.str_val= s->reason;
                                        query_vals[socket_info_col].val.str_val= s->sockinfo_str;
-                               
+
                                        if(dbf.insert(db,query_cols,query_vals,n_query_cols )<0)
                                        {
                                                LM_ERR("unsuccessful sql insert\n");
                                        } else {
-                                               s->db_flag= NO_UPDATEDB_FLAG;   
+                                               s->db_flag= NO_UPDATEDB_FLAG;
                                        }
-                                       break;                                                                          
+                                       break;
                        } /* switch */
                        prev_s= s;
                        s= s->next;
                }
                if(!no_lock)
-                       lock_release(&hash_table[i].lock);      
+                       lock_release(&hash_table[i].lock);
        }
 
-delete_expired_subs:
        update_vals[0].val.int_val= (int)time(NULL) - expires_offset;
        update_ops[0]= OP_LT;
        if(dbf.delete(db, update_cols, update_ops, update_vals, 1) < 0)
        {
                LM_ERR("deleting expired information from database\n");
        }
+}
+
+/**
+ * timer_db_update function does the following tasks:
+ *     1. checks for expires subscriptions and does the corresponding processing
+ *             - if db_mode != DB_ONLY : checks by traversing the hash table
+ *             - if db_mode == DB_ONLY : checks by querying database
+ *     2. if db_mode == WRITE_BACK : updates the subscriptions in database
+*/
+void timer_db_update(unsigned int ticks,void *param)
+{
+       int no_lock=0;
+       LM_DBG("db_update timer\n");
+       if(ticks== 0 && param == NULL)
+               no_lock= 1;
 
+
+       switch (subs_dbmode) {
+               case DB_ONLY:   update_db_subs_timer_dbonly();
+                                               break;
+               case NO_DB:             update_db_subs_timer_dbnone(no_lock);
+                                               break;
+               default:
+                               if(pa_dbf.use_table(pa_db, &active_watchers_table)< 0)
+                               {
+                                       LM_ERR("sql use table failed\n");
+                                       return;
+                               }
+                               update_db_subs_timer(pa_db, pa_dbf, subs_htable, shtable_size,
+                                               no_lock, handle_expired_subs);
+       }
 }
 
+
 int restore_db_subs(void)
 {
        db_key_t result_cols[22]; 
@@ -1878,9 +2054,7 @@ int restore_db_subs(void)
        
                        s.sockinfo_str.s=(char*)row_vals[sockinfo_col].val.string_val;
                        s.sockinfo_str.len= strlen(s.sockinfo_str.s);
-
-                       if(dbmode == DB_FALLBACK)
-                               s.db_flag = NO_UPDATEDB_FLAG;
+                       s.db_flag = (subs_dbmode==WRITE_THROUGH)?WTHROUGHDB_FLAG:NO_UPDATEDB_FLAG;
                        hash_code= core_hash(&s.pres_uri, &s.event->name, shtable_size);
                        if(insert_shtable(subs_htable, hash_code, &s)< 0)
                        {
@@ -1894,13 +2068,14 @@ int restore_db_subs(void)
 
        pa_dbf.free_result(pa_db, result);
 
-       /* delete all records */
-       if(dbmode != DB_MEMORY_ONLY && pa_dbf.delete(pa_db, 0,0,0,0)< 0)
-       {
-               LM_ERR("deleting all records from database table\n");
-               return -1;
+       /* delete all records  only if in memory mode */
+       if(subs_dbmode == NO_DB) {
+               if(pa_dbf.delete(pa_db, 0,0,0,0)< 0)
+               {
+                       LM_ERR("deleting all records from database table\n");
+                       return -1;
+               }
        }
-
        return 0;
 
 error:
index 97e5309..d76bf4f 100644 (file)
@@ -21,7 +21,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*! \file
@@ -90,8 +90,6 @@ void msg_watchers_clean(unsigned int ticks,void *param);
 
 int handle_subscribe(struct sip_msg*, char*, char*);
 
-int delete_db_subs(str pres_uri, str ev_stored_name, str to_tag);
-
 void timer_db_update(unsigned int ticks,void *param);
 
 int update_subs_db(subs_t* subs, int type);
@@ -105,7 +103,7 @@ int restore_db_subs(void);
 
 typedef int (*handle_expired_func_t)(subs_t* );
 
-void update_db_subs(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
+void update_db_subs_timer(db1_con_t *db,db_func_t dbf, shtable_t hash_table,
        int htable_size, int no_lock, handle_expired_func_t handle_expired_func);
 
 typedef void (*update_db_subs_t)(db1_con_t * ,db_func_t ,shtable_t ,int ,int ,
@@ -115,5 +113,6 @@ int extract_sdialog_info(subs_t* subs,struct sip_msg* msg, int max_expire,
                int* to_tag_gen, str scontact);
 typedef int (*extract_sdialog_info_t)(subs_t* subs, struct sip_msg* msg,
                int max_expire, int* to_tag_gen, str scontact);
+void delete_subs(str* pres_uri, str* ev_name, str* to_tag);
 
 #endif
index 3212972..80f794f 100644 (file)
@@ -23,7 +23,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*! \file
index 16e427d..8a76944 100644 (file)
@@ -23,7 +23,7 @@
  *
  * History:
  * --------
- *  2006-08-15  initial version (anca)
+ *  2006-08-15  initial version (Anca Vamanu)
  */
 
 /*! \file
index 21065e6..99c6ec8 100644 (file)
@@ -60,6 +60,7 @@
 #define NO_UPDATEDB_FLAG    1<<0
 #define UPDATEDB_FLAG       1<<1
 #define INSERTDB_FLAG       1<<2
+#define WTHROUGHDB_FLAG     1<<3
 
 #define MAX_FORWARD  70