Add support for compacting DBusStrings to release wasted memory.
authorRyan Lortie <desrt@desrt.ca>
Thu, 20 Sep 2007 04:13:35 +0000 (00:13 -0400)
committerRyan Lortie <desrt@desrt.ca>
Thu, 20 Sep 2007 04:13:35 +0000 (00:13 -0400)
2007-09-19  Ryan Lortie  <desrt@desrt.ca>

        * dbus/dbus-string.[ch] (compact, _dbus_string_compact,
        _dbus_string_lock): new compact function to free up allocated memory
        that is no longer used.

        * dbus/dbus-message.c (load_message): call _dbus_string_compact on the
        message loader buffer.

        * dbus/dbus-transport-socket.c (do_reading, do_writing): call
        _dbus_string_compact on the incoming/outgoing "encoded" buffers.

        * dbus/dbus-string-util.c (_dbus_string_test): add a few tests for
        string compacting.

ChangeLog
dbus/dbus-message.c
dbus/dbus-string-util.c
dbus/dbus-string.c
dbus/dbus-string.h
dbus/dbus-transport-socket.c

index 1c9168f..32c6436 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,20 @@
+2007-09-19  Ryan Lortie  <desrt@desrt.ca>
+
+       Add support for compacting DBusStrings to release wasted memory.
+
+       * dbus/dbus-string.[ch] (compact, _dbus_string_compact,
+       _dbus_string_lock): new compact function to free up allocated memory
+       that is no longer used.
+
+       * dbus/dbus-message.c (load_message): call _dbus_string_compact on the
+       message loader buffer.
+
+       * dbus/dbus-transport-socket.c (do_reading, do_writing): call
+       _dbus_string_compact on the incoming/outgoing "encoded" buffers.
+
+       * dbus/dbus-string-util.c (_dbus_string_test): add a few tests for
+       string compacting.
+
 2007-09-13  Ryan Lortie  <desrt@desrt.ca>
 
        * HACKING: add more explicit git branch/tag instructions
 2007-06-14  Havoc Pennington  <hp@redhat.com>
 
        * bus/dispatch.c (check_get_connection_unix_process_id): mop up
-       getpid() (noticed by Peter KKümmel) and adapt the test to 
+       getpid() (noticed by Peter Kümmel) and adapt the test to 
        expect a "pid unknown" error when running on Windows.
 
 2007-06-14  Havoc Pennington  <hp@redhat.com>
 2007-06-14  Simon McVittie  <simon.mcvittie@collabora.co.uk>
 
        * doc/dbus-specification.xml: say the protocol version is 1 instead of
-       0 (patch from Kristoffer Lundén, fd.o#10033) and remove the FIXME
+       0 (patch from Kristoffer Lundén, fd.o#10033) and remove the FIXME
        about removing protocol version from messages (as per Havoc's comment
        on that bug)
 
 2006-12-12  John (J5) Palmieri  <johnp@redhat.com>
 
        * bus/signal.c: Fix match_rule_equal errata
-       (CVE-2006-6107 - Patch from Kimmo HÃ\83¤mÃ\83¤lÃ\83¤inen 
+       (CVE-2006-6107 - Patch from Kimmo Hämäläinen 
        <kimmo.hamalainen@nokia.com>)
 
 2006-11-19  Thiago Macieira  <thiago@kde.org>
index 91f6ebe..cd44798 100644 (file)
@@ -3545,6 +3545,9 @@ load_message (DBusMessageLoader *loader,
 
   _dbus_string_delete (&loader->data, 0, header_len + body_len);
 
+  /* don't waste more than 2k of memory */
+  _dbus_string_compact (&loader->data, 2048);
+
   _dbus_assert (_dbus_string_get_length (&message->header.data) == header_len);
   _dbus_assert (_dbus_string_get_length (&message->body) == body_len);
 
index cee02c4..492c528 100644 (file)
@@ -790,6 +790,62 @@ _dbus_string_test (void)
     _dbus_string_free (&str);
     _dbus_string_free (&line);
   }
+
+  {
+    if (!_dbus_string_init (&str))
+      _dbus_assert_not_reached ("no memory");
+
+    for (i = 0; i < 10000; i++)
+      if (!_dbus_string_append (&str, "abcdefghijklmnopqrstuvwxyz"))
+        _dbus_assert_not_reached ("no memory");
+
+    if (!_dbus_string_set_length (&str, 10))
+      _dbus_assert_not_reached ("failed to set length");
+
+    /* actually compact */
+    if (!_dbus_string_compact (&str, 2048))
+      _dbus_assert_not_reached ("failed to compact after set_length");
+
+    /* peek inside to make sure it worked */
+    if (((DBusRealString *)&str)->allocated > 30)
+      _dbus_assert_not_reached ("compacting string didn't do anything");
+
+    if (!_dbus_string_equal_c_str (&str, "abcdefghij"))
+      _dbus_assert_not_reached ("unexpected content after compact");
+
+    /* compact nothing */
+    if (!_dbus_string_compact (&str, 2048))
+      _dbus_assert_not_reached ("failed to compact 2nd time");
+
+    if (!_dbus_string_equal_c_str (&str, "abcdefghij"))
+      _dbus_assert_not_reached ("unexpected content after 2nd compact");
+
+    /* and make sure it still works...*/
+    if (!_dbus_string_append (&str, "123456"))
+      _dbus_assert_not_reached ("failed to append after compact");
+
+    if (!_dbus_string_equal_c_str (&str, "abcdefghij123456"))
+      _dbus_assert_not_reached ("unexpected content after append");
+
+    /* after growing automatically, this should do nothing */
+    if (!_dbus_string_compact (&str, 20000))
+      _dbus_assert_not_reached ("failed to compact after grow");
+
+    /* but this one will do something */
+    if (!_dbus_string_compact (&str, 0))
+      _dbus_assert_not_reached ("failed to compact after grow");
+
+    if (!_dbus_string_equal_c_str (&str, "abcdefghij123456"))
+      _dbus_assert_not_reached ("unexpected content");
+
+    if (!_dbus_string_append (&str, "!@#$%"))
+      _dbus_assert_not_reached ("failed to append after compact");
+
+    if (!_dbus_string_equal_c_str (&str, "abcdefghij123456!@#$%"))
+      _dbus_assert_not_reached ("unexpected content");
+
+    _dbus_string_free (&str);
+  }
   
   return TRUE;
 }
index 62ac8c3..000b4f6 100644 (file)
@@ -271,6 +271,32 @@ _dbus_string_free (DBusString *str)
   real->invalid = TRUE;
 }
 
+static dbus_bool_t
+compact (DBusRealString *real,
+         int             max_waste)
+{
+  unsigned char *new_str;
+  int new_allocated;
+  int waste;
+
+  waste = real->allocated - (real->len + _DBUS_STRING_ALLOCATION_PADDING);
+
+  if (waste <= max_waste)
+    return TRUE;
+
+  new_allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING;
+
+  new_str = dbus_realloc (real->str - real->align_offset, new_allocated);
+  if (_DBUS_UNLIKELY (new_str == NULL))
+    return FALSE;
+
+  real->str = new_str + real->align_offset;
+  real->allocated = new_allocated;
+  fixup_alignment (real);
+
+  return TRUE;
+}
+
 #ifdef DBUS_BUILD_TESTS
 /* Not using this feature at the moment,
  * so marked DBUS_BUILD_TESTS-only
@@ -295,22 +321,7 @@ _dbus_string_lock (DBusString *str)
    * we know we won't change the string further
    */
 #define MAX_WASTE 48
-  if (real->allocated - MAX_WASTE > real->len)
-    {
-      unsigned char *new_str;
-      int new_allocated;
-
-      new_allocated = real->len + _DBUS_STRING_ALLOCATION_PADDING;
-
-      new_str = dbus_realloc (real->str - real->align_offset,
-                              new_allocated);
-      if (new_str != NULL)
-        {
-          real->str = new_str + real->align_offset;
-          real->allocated = new_allocated;
-          fixup_alignment (real);
-        }
-    }
+  compact (real, MAX_WASTE);
 }
 #endif /* DBUS_BUILD_TESTS */
 
@@ -361,6 +372,26 @@ reallocate_for_length (DBusRealString *real,
   return TRUE;
 }
 
+/**
+ * Compacts the string to avoid wasted memory.  Wasted memory is
+ * memory that is allocated but not actually required to store the
+ * current length of the string.  The compact is only done if more
+ * than the given amount of memory is being wasted (otherwise the
+ * waste is ignored and the call does nothing).
+ *
+ * @param str the string
+ * @param max_waste the maximum amount of waste to ignore
+ * @returns #FALSE if the compact failed due to realloc failure
+ */
+dbus_bool_t
+_dbus_string_compact (DBusString *str,
+                      int         max_waste)
+{
+  DBUS_STRING_PREAMBLE (str);
+
+  return compact (real, max_waste);
+}
+
 static dbus_bool_t
 set_length (DBusRealString *real,
             int             new_length)
index 076fed6..b0100f3 100644 (file)
@@ -73,6 +73,8 @@ dbus_bool_t   _dbus_string_init_preallocated     (DBusString        *str,
                                                   int                allocate_size);
 void          _dbus_string_free                  (DBusString        *str);
 void          _dbus_string_lock                  (DBusString        *str);
+dbus_bool_t   _dbus_string_compact               (DBusString        *str,
+                                                  int                max_waste);
 #ifndef _dbus_string_get_data
 char*         _dbus_string_get_data              (DBusString        *str);
 #endif /* _dbus_string_get_data */
index a31c159..f6d0e9c 100644 (file)
@@ -642,6 +642,7 @@ do_writing (DBusTransport *transport)
             {
               socket_transport->message_bytes_written = 0;
               _dbus_string_set_length (&socket_transport->encoded_outgoing, 0);
+              _dbus_string_compact (&socket_transport->encoded_outgoing, 2048);
 
               _dbus_connection_message_sent (transport->connection,
                                              message);
@@ -733,6 +734,7 @@ do_reading (DBusTransport *transport)
                                               _dbus_string_get_length (buffer) - orig_len);
 
           _dbus_string_set_length (&socket_transport->encoded_incoming, 0);
+          _dbus_string_compact (&socket_transport->encoded_incoming, 2048);
         }
     }
   else