From: Tor Didriksen Date: March 3 2011 9:18am Subject: bzr commit into mysql-trunk branch (tor.didriksen:3722) WL#5774 List-Archive: http://lists.mysql.com/commits/132349 Message-Id: <20110303091815.74CE037E3@atum07.norway.sun.com> MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="===============0623901077414728121==" --===============0623901077414728121== MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline #At file:///export/home/didrik/repo/trunk-dynarray/ based on revid:anitha.gopi@stripped 3722 Tor Didriksen 2011-03-03 WL #5774 Decrease number of malloc's for normal DML queries One of the malloc's was due to DYNAMIC_ARRAY keyuse; Here's an experiment to use an array allocated in thd->mem_root instead. added: sql/mem_root_array.h unittest/gunit/dynarray-t.cc modified: sql/sql_select.cc sql/sql_select.h sql/sql_test.cc sql/sql_test.h unittest/gunit/CMakeLists.txt === added file 'sql/mem_root_array.h' --- a/sql/mem_root_array.h 1970-01-01 00:00:00 +0000 +++ b/sql/mem_root_array.h 2011-03-03 09:18:10 +0000 @@ -0,0 +1,139 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + + +#ifndef MEM_ROOT_ARRAY_INCLUDED +#define MEM_ROOT_ARRAY_INCLUDED + +#include + +/** + A typesafe replacement for DYNAMIC_ARRAY. + We use MEM_ROOT for allocating storage, rather than the C++ heap. + The interface is chosen to be similar to std::vector. + + Note that MEM_ROOT has no facility for reusing free space, + so don't use this if multiple re-expansions are likely to happen. +*/ +template +class Mem_root_array +{ +public: + Mem_root_array() + : m_root(NULL), m_array(NULL), m_size(0), m_capacity(0) + {} + + Mem_root_array(MEM_ROOT *root) + : m_root(root), m_array(NULL), m_size(0), m_capacity(0) + {} + + ~Mem_root_array() + { + clear(); + } + + void set_mem_root(MEM_ROOT *root) { m_root= root; } + + Element_type &at(size_t n) + { + DBUG_ASSERT(n < size()); + return m_array[n]; + } + + const Element_type &at(size_t n) const + { + DBUG_ASSERT(n < size()); + return m_array[n]; + } + + // Returns a pointer to the first element in the array. + Element_type *begin() { return &m_array[0]; } + + // Returns an pointer to the past-the-end element in the array. + Element_type *end() { return &m_array[size()]; } + + // Clear array contents. + void clear() + { + chop(0); + } + + // Chops the tail off the array. + void chop(size_t pos) + { + if (pos >= m_size) + return; + for (size_t ix= pos; pos < m_size; ++pos) + { + Element_type *p= &m_array[ix]; + p->~Element_type(); // Delete discarded element. + } + m_size= pos; + } + + // Reserves space for array elements. + // Copies over existing elements, in case we are re-expanding the array. + bool reserve(size_t n) + { + if (n <= m_capacity) + return false; + + void *mem= alloc_root(m_root, n * element_size()); + if (!mem) + return true; + Element_type *array= static_cast(mem); + + // Copy all the existing elements into the new array. + for (size_t ix= 0; ix < m_size; ++ix) + { + Element_type *new_p= &array[ix]; + Element_type *old_p= &m_array[ix]; + new (new_p) Element_type(*old_p); // Copy into new location. + old_p->~Element_type(); // Delete the old element. + } + + // Forget the old array. + m_array= array; + m_capacity= n; + return false; + } + + // Adds a new element at the end of the array, after its current last + // element. The content of this new element is initialized to a copy of + // the input argument. + bool push_back(const Element_type &element) + { + if (0 == m_capacity && reserve(10)) + return true; + if (m_size == m_capacity && reserve(m_capacity * 2)) + return true; + Element_type *p= &m_array[m_size++]; + new (p) Element_type(element); + return false; + } + + size_t element_size() const { return sizeof(Element_type); } + size_t size() const { return m_size; } + size_t capacity() const { return m_capacity; } + +private: + MEM_ROOT *m_root; + Element_type *m_array; + size_t m_size; + size_t m_capacity; +}; + + +#endif // MEM_ROOT_ARRAY_INCLUDED === modified file 'sql/sql_select.cc' --- a/sql/sql_select.cc 2011-03-01 14:47:01 +0000 +++ b/sql/sql_select.cc 2011-03-03 09:18:10 +0000 @@ -63,11 +63,11 @@ const char *join_type_str[]={ "UNKNOWN", struct st_sargable_param; -static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array); +static void optimize_keyuse(JOIN *join, Key_use_array *keyuse_array); static bool make_join_statistics(JOIN *join, TABLE_LIST *leaves, Item *conds, - DYNAMIC_ARRAY *keyuse); + Key_use_array *keyuse); static bool optimize_semijoin_nests(JOIN *join, table_map all_table_map); -static bool update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse, +static bool update_ref_and_keys(THD *thd, Key_use_array *keyuse, JOIN_TAB *join_tab, uint tables, Item *conds, COND_EQUAL *cond_equal, @@ -3441,7 +3441,7 @@ JOIN::destroy() while ((sj_nest= sj_list_it++)) sj_nest->sj_mat_exec= NULL; - delete_dynamic(&keyuse); + keyuse.clear(); delete procedure; DBUG_RETURN(error); } @@ -4598,7 +4598,7 @@ static uint get_tmp_table_rec_length(Lis static bool make_join_statistics(JOIN *join, TABLE_LIST *tables_arg, Item *conds, - DYNAMIC_ARRAY *keyuse_array) + Key_use_array *keyuse_array) { int error; TABLE *table; @@ -5985,7 +5985,7 @@ max_part_bit(key_part_map bits) */ static bool -add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) +add_key_part(Key_use_array *keyuse_array,KEY_FIELD *key_field) { Field *field=key_field->field; TABLE *form= field->table; @@ -6015,7 +6015,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array key_field->null_rejecting, key_field->cond_guard, key_field->sj_pred_no); - if (insert_dynamic(keyuse_array, &keyuse)) + if (keyuse_array->push_back(keyuse)) return TRUE; } } @@ -6028,7 +6028,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array #define FT_KEYPART (MAX_REF_PARTS+10) static bool -add_ft_keys(DYNAMIC_ARRAY *keyuse_array, +add_ft_keys(Key_use_array *keyuse_array, JOIN_TAB *stat,Item *cond,table_map usable_tables) { Item_func_match *cond_func=NULL; @@ -6090,7 +6090,7 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array, false, // null_rejecting NULL, // cond_guard UINT_MAX); // sj_pred_no - return insert_dynamic(keyuse_array, &keyuse); + return keyuse_array->push_back(keyuse); } @@ -6206,7 +6206,7 @@ static void add_key_fields_for_nj(JOIN * */ static bool -update_ref_and_keys(THD *thd, DYNAMIC_ARRAY *keyuse,JOIN_TAB *join_tab, +update_ref_and_keys(THD *thd, Key_use_array *keyuse,JOIN_TAB *join_tab, uint tables, Item *cond, COND_EQUAL *cond_equal, table_map normal_tables, SELECT_LEX *select_lex, SARGABLE_PARAM **sargables) @@ -6249,7 +6249,8 @@ update_ref_and_keys(THD *thd, DYNAMIC_AR /* set a barrier for the array of SARGABLE_PARAM */ (*sargables)[0].field= 0; - if (my_init_dynamic_array(keyuse, sizeof(Key_use), 20, 64)) + keyuse->set_mem_root(thd->mem_root); + if (keyuse->reserve(20)) return TRUE; if (cond) { @@ -6324,21 +6325,21 @@ update_ref_and_keys(THD *thd, DYNAMIC_AR used in the query, we drop the partial key parts from consideration). Special treatment for ft-keys. */ - if (keyuse->elements) + if (keyuse->size()) { Key_use *save_pos, *use; - my_qsort(keyuse->buffer, keyuse->elements, sizeof(Key_use), + my_qsort(keyuse->begin(), keyuse->size(), keyuse->element_size(), reinterpret_cast(sort_keyuse)); const Key_use key_end(NULL, NULL, 0, 0, 0, 0, 0, 0, false, NULL, 0); - if (insert_dynamic(keyuse, &key_end)) // added for easy testing + if (keyuse->push_back(key_end)) // added for easy testing return TRUE; - use= save_pos= dynamic_element(keyuse, 0, Key_use *); + use= save_pos= keyuse->begin(); const Key_use *prev= &key_end; found_eq_constant=0; - for (i=0 ; i < keyuse->elements-1 ; i++,use++) + for (i=0 ; i < keyuse->size()-1 ; i++,use++) { if (!use->used_tables && use->optimize != KEY_OPTIMIZE_REF_OR_NULL) use->table->const_key_parts[use->key]|= use->keypart_map; @@ -6371,9 +6372,9 @@ update_ref_and_keys(THD *thd, DYNAMIC_AR use->table->reginfo.join_tab->checked_keys.set_bit(use->key); save_pos++; } - i= (uint) (save_pos - (Key_use *)keyuse->buffer); - (void) set_dynamic(keyuse, &key_end, i); - keyuse->elements=i; + i= (uint) (save_pos - keyuse->begin()); + keyuse->at(i) = key_end; + keyuse->chop(i); } DBUG_EXECUTE("opt", print_keyuse_array(keyuse);); return FALSE; @@ -6383,12 +6384,11 @@ update_ref_and_keys(THD *thd, DYNAMIC_AR Update some values in keyuse for faster choose_plan() loop. */ -static void optimize_keyuse(JOIN *join, DYNAMIC_ARRAY *keyuse_array) +static void optimize_keyuse(JOIN *join, Key_use_array *keyuse_array) { - Key_use *end, *keyuse= dynamic_element(keyuse_array, 0, Key_use *); - - for (end= keyuse+ keyuse_array->elements ; keyuse < end ; keyuse++) + for (size_t ix= 0; ix < keyuse_array->size(); ++ix) { + Key_use *keyuse= &keyuse_array->at(ix); table_map map; /* If we find a ref, assume this table matches a proportional === modified file 'sql/sql_select.h' --- a/sql/sql_select.h 2011-02-08 15:49:51 +0000 +++ b/sql/sql_select.h 2011-03-03 09:18:10 +0000 @@ -34,6 +34,7 @@ #include "records.h" /* READ_RECORD */ #include "opt_range.h" /* SQL_SELECT, QUICK_SELECT_I */ +#include "mem_root_array.h" /* Values in optimize */ #define KEY_OPTIMIZE_EXISTS 1 @@ -47,6 +48,8 @@ */ class Key_use { public: + Key_use() { memset(this, 0, sizeof(*this)); } + Key_use(TABLE *table_arg, Item *val_arg, table_map used_tables_arg, uint key_arg, uint keypart_arg, uint optimize_arg, key_part_map keypart_map_arg, ha_rows ref_table_rows_arg, @@ -97,6 +100,10 @@ public: uint sj_pred_no; }; + +typedef Mem_root_array Key_use_array; +void print_keyuse_array(Key_use_array *keyuse_array); + class store_key; typedef struct st_table_ref : public Sql_alloc @@ -1772,7 +1779,10 @@ public: bool skip_sort_order; bool need_tmp, hidden_group_fields; - DYNAMIC_ARRAY keyuse; + + // DYNAMIC_ARRAY keyuse; + Key_use_array keyuse; + List all_fields; ///< to store all fields that used in query ///Above list changed to use temporary table List tmp_all_fields1, tmp_all_fields2, tmp_all_fields3; === modified file 'sql/sql_test.cc' --- a/sql/sql_test.cc 2010-11-05 22:19:41 +0000 +++ b/sql/sql_test.cc 2011-03-03 09:18:10 +0000 @@ -239,7 +239,7 @@ TEST_join(JOIN *join) #define FT_KEYPART (MAX_REF_PARTS+10) -void print_keyuse(Key_use *keyuse) +void print_keyuse(const Key_use *keyuse) { char buff[256]; char buf2[64]; @@ -276,6 +276,16 @@ void print_keyuse_array(DYNAMIC_ARRAY *k (dynamic_array_ptr(keyuse_array, i))); } +void print_keyuse_array(Key_use_array *keyuse_array) +{ + DBUG_LOCK_FILE; + fprintf(DBUG_FILE, "Key_use array (%d elements)\n", + (int) keyuse_array->size()); + DBUG_UNLOCK_FILE; + for(uint i=0; i < keyuse_array->size(); i++) + print_keyuse(&keyuse_array->at(i)); +} + /* Print the current state during query optimization. === modified file 'sql/sql_test.h' --- a/sql/sql_test.h 2010-08-19 07:10:58 +0000 +++ b/sql/sql_test.h 2011-03-03 09:18:10 +0000 @@ -20,6 +20,7 @@ class JOIN; struct TABLE_LIST; +class Key_use; typedef class st_select_lex SELECT_LEX; typedef struct st_sort_field SORT_FIELD; @@ -32,6 +33,7 @@ void print_plan(JOIN* join,uint idx, dou void dump_TABLE_LIST_graph(SELECT_LEX *select_lex, TABLE_LIST* tl); void print_sjm(TABLE_LIST *emb_sj_nest); void print_keyuse_array(DYNAMIC_ARRAY *keyuse_array); +void print_keyuse(const Key_use *keyuse); #endif void mysql_print_status(); === modified file 'unittest/gunit/CMakeLists.txt' --- a/unittest/gunit/CMakeLists.txt 2011-02-17 14:39:47 +0000 +++ b/unittest/gunit/CMakeLists.txt 2011-03-03 09:18:10 +0000 @@ -210,6 +210,7 @@ ENDIF() SET(TESTS bounded_queue dbug + dynarray mdl mdl_mytap my_bitmap === added file 'unittest/gunit/dynarray-t.cc' --- a/unittest/gunit/dynarray-t.cc 1970-01-01 00:00:00 +0000 +++ b/unittest/gunit/dynarray-t.cc 2011-03-03 09:18:10 +0000 @@ -0,0 +1,313 @@ +/* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +// First include (the generated) my_config.h, to get correct platform defines, +// then gtest.h (before any other MySQL headers), to avoid min() macros etc ... +#include "my_config.h" +#include + +#include +#include +#include + +#include "sql_select.h" +#include "mem_root_array.h" +/** + WL #5774 Decrease number of malloc's for normal DML queries + One of the malloc's was due to DYNAMIC_ARRAY keyuse; + Here's an experiment to use an array allocated in thd->mem_root instead. + + This is the interface we need to support: + struct XX_DYNAMIC_ARRAY + { + .... + }; + + void delete_dynamic(XX_DYNAMIC_ARRAY*); + dynamic_element(array,array_index,type); + bool init_dynamic_array2(XX_DYNAMIC_ARRAY*, uint, void*, uint, uint); + bool insert_dynamic(XX_DYNAMIC_ARRAY*, const Key_use*); + bool set_dynamic(XX_DYNAMIC_ARRAY*, const void*, uint); + void print_keyuse_array(XX_DYNAMIC_ARRAY*); +*/ + +pthread_key(MEM_ROOT**, THR_MALLOC); +pthread_key(THD*, THR_THD); + +extern "C" void sql_alloc_error_handler(void) +{ + ADD_FAILURE(); +} + +// Cut'n paste this function from sql_select.cc, +// to avoid linking in the entire server for this unit test. +inline int sort_keyuse(Key_use *a, Key_use *b) +{ + int res; + if (a->table->tablenr != b->table->tablenr) + return (int) (a->table->tablenr - b->table->tablenr); + if (a->key != b->key) + return (int) (a->key - b->key); + if (a->keypart != b->keypart) + return (int) (a->keypart - b->keypart); + // Place const values before other ones + if ((res= test((a->used_tables & ~OUTER_REF_TABLE_BIT)) - + test((b->used_tables & ~OUTER_REF_TABLE_BIT)))) + return res; + /* Place rows that are not 'OPTIMIZE_REF_OR_NULL' first */ + return (int) ((a->optimize & KEY_OPTIMIZE_REF_OR_NULL) - + (b->optimize & KEY_OPTIMIZE_REF_OR_NULL)); +} + +// Rewrite of sort_keyuse() to comparison operator for use by std::less<> +inline bool operator<(const Key_use &a, const Key_use &b) +{ + if (a.table->tablenr != b.table->tablenr) + return a.table->tablenr < b.table->tablenr; + if (a.key != b.key) + return a.key < b.key; + if (a.keypart != b.keypart) + return a.keypart < b.keypart; + const bool atab = test((a.used_tables & ~OUTER_REF_TABLE_BIT)); + const bool btab = test((b.used_tables & ~OUTER_REF_TABLE_BIT)); + if (atab != btab) + return atab < btab; + return + ((a.optimize & KEY_OPTIMIZE_REF_OR_NULL) < + (b.optimize & KEY_OPTIMIZE_REF_OR_NULL)); +} + +namespace { + +// Play around with these constants to see std::sort speedup vs. my_qsort. +const int num_elements= 200; +const int num_iterations= 1; + +// We generate some random data at startup, for testing of sorting. +Key_use test_data[num_elements]; +TABLE table_list[num_elements]; + + +class DynArrayTest : public ::testing::Test +{ +public: + static void SetUpTestCase() + { + int ix; + for (ix= 0; ix < num_elements; ++ix) + { + table_list[ix].tablenr= ix % 3; + test_data[ix]= + Key_use(&table_list[ix], + NULL, // Item *val + 0, // table_map used_tables + ix % 4, // uint key + ix % 2, // uint keypart + 0, // uint optimize + 0, // keypart_map + 0, // ha_rows ref_table_rows + true, // bool null_rejecting + NULL, // bool *cond_guard + 0 // uint sj_pred_no + ); + } + std::random_shuffle(&test_data[0], &test_data[num_elements]); + } + + virtual void SetUp() + { + my_init_dynamic_array(&m_keyuse_dyn, sizeof(Key_use), num_elements, 64); + m_keyuse_vec.reserve(num_elements); + } + + void insert_and_sort_dynamic() + { + reset_dynamic(&m_keyuse_dyn); + for (int ix= 0; ix < num_elements; ++ix) + { + insert_dynamic(&m_keyuse_dyn, &test_data[ix]); + } + my_qsort(m_keyuse_dyn.buffer, m_keyuse_dyn.elements, sizeof(Key_use), + reinterpret_cast(sort_keyuse)); + } + + void insert_and_sort_vector() + { + m_keyuse_vec.clear(); + for (int ix= 0; ix < num_elements; ++ix) + { + m_keyuse_vec.push_back(test_data[ix]); + } + std::sort(m_keyuse_vec.begin(), m_keyuse_vec.end(), std::less()); + } + + DYNAMIC_ARRAY m_keyuse_dyn; + std::vector m_keyuse_vec; +}; + + +void print_key(uint ix, Key_use *key) +{ + fprintf(stdout, "ix %d table %d key %d\n", ix, key->table->tablenr, key->key); + fflush(stdout); +} + +void print_array(std::vector *arr) +{ + for (uint ix= 0; ix < arr->size(); ++ix) + { + Key_use &key_use = (*arr)[ix]; + print_key(ix, &key_use); + } +} + +void print_array(DYNAMIC_ARRAY *arr) +{ + for (uint ix= 0; ix < arr->elements; ++ix) + { + Key_use key_use; + void *p = &key_use; + get_dynamic(arr, static_cast(p), ix); + print_key(ix, &key_use); + } +} + +void print_array(Mem_root_array *arr) +{ + for (uint ix= 0; ix < arr->size(); ++ix) + { + Key_use &key_use= arr->at(ix); + print_key(ix, &key_use); + } +} + + +// Test insert_dynamic() and my_qsort(). +TEST_F(DynArrayTest, DynArray) +{ + for (int ix= 0; ix < num_iterations; ++ix) + insert_and_sort_dynamic(); + // print_array(&m_keyuse_dyn); +} + + +// Test vector::push_back() and std::sort() +TEST_F(DynArrayTest, Vector) +{ + for (int ix= 0; ix < num_iterations; ++ix) + insert_and_sort_vector(); + // print_array(&m_keyuse_vec); +} + + +class MemRootTest : public ::testing::Test +{ +protected: + MemRootTest() + : m_mem_root_p(&m_mem_root), m_array(m_mem_root_p) + {} + + virtual void SetUp() + { + init_sql_alloc(&m_mem_root, 1024, 0); + ASSERT_EQ(0, my_pthread_setspecific_ptr(THR_MALLOC, &m_mem_root_p)); + MEM_ROOT *root= *my_pthread_getspecific_ptr(MEM_ROOT**, THR_MALLOC); + ASSERT_EQ(root, m_mem_root_p); + + m_array.reserve(num_elements); + } + + virtual void TearDown() + { + free_root(&m_mem_root, MYF(0)); + } + + static void SetUpTestCase() + { + ASSERT_EQ(0, pthread_key_create(&THR_THD, NULL)); + ASSERT_EQ(0, pthread_key_create(&THR_MALLOC, NULL)); + } + + static void TearDownTestCase() + { + pthread_key_delete(THR_THD); + pthread_key_delete(THR_MALLOC); + } + + void insert_and_sort_mysys() + { + m_array.clear(); + for (int ix= 0; ix < num_elements; ++ix) + { + m_array.push_back(test_data[ix]); + } + my_qsort(m_array.begin(), m_array.size(), m_array.element_size(), + reinterpret_cast(sort_keyuse)); + } + + void insert_and_sort_std() + { + m_array.clear(); + for (int ix= 0; ix < num_elements; ++ix) + { + m_array.push_back(test_data[ix]); + } + std::sort(m_array.begin(), m_array.end(), std::less()); + } + + MEM_ROOT m_mem_root; + MEM_ROOT *m_mem_root_p; + Mem_root_array m_array; +}; + + +// Test Mem_root_array::push_back() and my_qsort() +TEST_F(MemRootTest, KeyUseMysys) +{ + for (int ix= 0; ix < num_iterations; ++ix) + insert_and_sort_mysys(); + // print_array(&m_array); +} + + +// Test Mem_root_array::push_back() and std::sort() +TEST_F(MemRootTest, KeyUseStd) +{ + for (int ix= 0; ix < num_iterations; ++ix) + insert_and_sort_std(); + // print_array(&m_array); +} + + +// Test that Mem_root_array re-expanding works. +TEST_F(MemRootTest, Reserve) +{ + Mem_root_array intarr; + intarr.set_mem_root(m_mem_root_p); + intarr.reserve(2); + for (uint ix=0; ix < 20; ++ix) + { + EXPECT_EQ(ix, intarr.size()); + EXPECT_FALSE(intarr.push_back(ix)); + EXPECT_EQ(ix, intarr.at(ix)); + } + for (uint ix=0; ix < 20; ++ix) + { + EXPECT_EQ(ix, intarr.at(ix)); + } +} + + +} --===============0623901077414728121== MIME-Version: 1.0 Content-Type: text/bzr-bundle; charset="us-ascii"; name="bzr/tor.didriksen@stripped" Content-Transfer-Encoding: 7bit Content-Disposition: inline # Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: tor.didriksen@stripped\ # ppodne0mefr89yrp # target_branch: file:///export/home/didrik/repo/trunk-dynarray/ # testament_sha1: eba3c70bb0960728857a2ab95aaa2a32a3ebce34 # timestamp: 2011-03-03 10:18:15 +0100 # base_revision_id: anitha.gopi@stripped\ # 6l24ru1tu4kumsgx # # Begin bundle IyBCYXphYXIgcmV2aXNpb24gYnVuZGxlIHY0CiMKQlpoOTFBWSZTWYiANTMADnN/gH90iph7//// f////r////tgHb9332+8V54nN3pwCi4bOw7mpu97vapJSgFCthwRthVjWxux0Ohe9u9PszrR72aP e1aaO2+jzvuaC5ht7tI+hgvfd2xna4SUhQ9GmkaYAJpiaDJkADTQABoAAAAAEoIAIITQCNJk1Nom T0jRiMgA0BoAA0BoaBKBEyKQ/VGnqepo/VAaNHqNDIMjQAAAaaA9QDQAEmpCBKZqZU/JpP0im9U2 NNSPU/VHqegCD1GgNDQxAABoaBEokExTwIaamo8NQYkxo0EaaZMRk0aaZGjagZGmnqGQSJBAIAJk GiaGmkyekyGqeUfioeFPTKD1G1NoQNGgeo4dV+tdgwSAhZJkEjl8XY/0BsY222WoqxnTQUEKnMOe r0/rSQsm+QzK8u1Kfyt7scJ3UyQrC8dayEa3G0/x7vYdPDX09St6nFkmY160cB7IY26Z5CQYmzSV UO+2ehq9VMA0JllazpWVFgyblIjBhCSsiSJYMhq0GVBXWEHbDotjqpuvfl3f1/M8N/8p71AwfIco nFkJMxIklSgv12Iw/d1M6UVlTLBjaRMoR1O9zgcUoSkbHMIa4SUaIRDJxBbKOmIK2N3OTVw0cMWk iYkS8jLfHZI8cois/JypViNpas9zceL4VO3Mz35ZnNO0qgQ3dKkhEO+w+DWZdYaC6q+INHL+tacV lSwzwjN6VaE6zzi8k5roxdkt1IYMvroQtnO5b2DZY4GHeAhGTSQKWIgaIIHonxXtPtsQL5WFGbkv 27DHEamyhjqobUF8UB3IJ9JkoBBiQiRykHbGBYYySIkFBDrqFILJBYEXvb/mqq7e3eeUPiPnlOlB 0hRXawylU5sbTbky6KySlVD/GDigaB6tYJ8452m5hrtpzm2XT4yg+Q/LTpQ1GRZzOrgqUhVtG4gY i5gxa3t2VLcHhWqaUgSSSBIISLoNa0Yxf7ROj0dPDYOK/8Nb9aLQ9Ppq1q19qr19MMyC89T6PxS5 Hulyyi6sMrF3bR37iJuu6wV9MTGbXeW60hjgLBVJXZosSXKwWizWzsqU6tm7NcUq5019A5yr8nXD hlw7OXC9LA4LcDfnd9hjKz9x0HWeHpN5ZJHIdT1D9pLVyIItxruRUvLpmUoSIEFPgIpUjyAxUUUh belARo4CvJkyLIi7wkUuh1gZODKhCZ4G4t2XkbBVgLD0BQJog8pRG+oFPAzEijhnNaaDpVYLevzs 4VNCSdgMYFdmWU/XSFyo3pywSU/1WfHYl8CqqrdVVXgZ3KGxdU65VrAyS/6UzC644U4ilWdjjulq ++WkjllLcuVJspxfq+GC5uWkNXYwqYgifGrCEvM91KluFyn/IMRM4ahl9Wxg9/9Mz6gbYELuQJ7K SMsN2TlAIQUKQmML5XNqNzCbuTHOKduQC0FVAMMQn3s9F7mx4k590S9r9thN6GBxWYfn8LqfZYlc nj1TBPHEIRrA9RtUv7yJY8nT3rghgrqhZQWB0JIbtcoe6axJ9zFOLxOorKs9kR6V2btfgeMMIF4t JvIM/Ixo87WI3h3llp08RjWrUBQ0XvmiW3mHx1F0NtVGinXJdXevg0kzTgpOZpLsVnbnFKJVq8OA iK8Msaii3LGqI5lpvwkwZrIhKrQsS+CJNiDmsdrd7bWpOgxgonosFQgU0poVjtAY7B0kdw3CTGa6 X+rOYl5QlsMB2EFLkkagsUKbFFUIqJOAMnx84ex7Pm9z273fI+z949ro3u4X3M1Zjokt7vH0b9c/ l6jxQm3NSyMRYChE9IRnOyd4SUIRUYICieu8vA7gbXLTxl1TdWVzFe2ynK/rVppfq5cr320mlvYu lao6VKZ5xjKqONOsFS0aOfamiYX0Ng/ZA0+RGSUYjOijl8st8VTkyY60eEmdeAa2NjblbL65/a5L X4Xqw0UQvw1RZQMlqU5qcAy1lGS2+0goOTxpbIIo8KlM/Fck6LmzcRslsY3TWfs7YqwRD0Zm48s5 UJc6pdbhNBks9HA8vFfO6a4ss30B9CRdDw0O8b1tCQarNbqypTOr+NuycmvwndUICk41JGHN5EaM QwMlBXIsSU240jBVraUPu2z51TeqMfbqT1gfKfmU+1iLKVCRno6meO+zhbibuWXCqYhY3j0zYxhx Hrm8Lnb7sftZtj1DBzXOA5n1F03WDZnwsIdjLMBt1Tnz6B1QE0g3ctdPbBw/kJ7uHLp7CnUHm6ux a+vK/GvwIuJVGfC7pJhPqw+UlmOtRvvkduWK3b+UpCIdzNERBg56yinondFSmS3b3CaddmbY3OwM kDAMecUgMAvadKPafOjz6tRshDzHZNwM6FEUmNNjoOZMiCA77m/iPYuTCCYBevi/GR2iBnVD54jT 8N44F7yRIxt6IxIqNWX1e2EqqvmHHXtKJ3+jc2TJLNRDaBeulmIyBlIGLYrhM6e7VLSFDfGDgInl m70cmzMw0EGhejvnoaIIhyTcKbDB0PND6+u8tiRWMWUJcgSVPQV/Gxdw15tBAz6uheDym92byJ5m kHc0Q0e/57bLZHhKFV3BUhSmIHdcKSsR0nUfcmO0xOsjmRJI7nixmWhuE1PR+LivJDWCCiTLDBc9 ouKcyHlFvf231iWNDBk0gDIujLoDkRMQVGLOCwVbDatIl/yaihqN5tJEitR2iIChQ6PxDIgYVNFZ QJ7rqkHhyL0k7BS8LVO23dv1iCojfaKv4wJExSCM8ek1Z/RQqWCioIim5skiFSlZOLI7DiUM1tDo vrXsnztnPMpsGThIVbmyA40Yuni4e5CXOz4OOl0zu+8CSERR8CZ6sUg+O3G3ZsFfzozkbUqHPYx7 UZy3jIWP6ljbgDZiXuVc95OlKMmVLOyOl9oRMJMGMErjY5IdJE5mIDp3jg/I1kSNO65T6YRHHr2w qo5E70yaHcKdBbNWVixo/zXhLucQyOdtCQcTwl4fpVHOTywZNxnviM+XUcCC4SKjQlEXQSLmtkO6 hXqibZMUIUFsCjqUCLuKZ1LsdB4VJk0kptg7OkqUltSp1s8YJViDpsQ1KMMhEgfSrzgb0bkbRm05 Y7bIN+Z6IJyNFK0KkaC4kLgwndOu5CNGkvPjg8RM2HsaD1IlSxEfE4kIyl0j66Hd5CRCQDdRQ4sQ LHaQO5BU+Y0ThwMpvXMSGW3YY4RXY3TyPGeONsj2fe2yEyL5LivxYnrcx/ErW3O5IokRNDcgUh3d 1PF0Gxktt7h0HbHnOasu5eLpOMYXjc2DsFSJGzhlRDYVAc6C/EhnROTlHZlZhOVkC2A1NRUuSvMk QImDvTQkKh46BadSjZtwmzok9TURp19cUJKkDgG6fkQnB63OQvhoyHzilvHI9UhY0L9yjGeDcDJE KeU5luvqQNiJU4lzeci73HOcx4jMadePDFzx2Mnrpqlmno2zEFI4kzd0mItWpzwNI00XoNomDXrE DZuqpMrFxTJxPFEsSwHqdW2seTPrV+jVdCGrIEZxm5BxVIqSVEDn0chzahEkc/JeNMr0nbcSXIiQ JFyIlzUZThscKv0mCTWXBGRUzxMkDpqQ20KuIHm5Qwaewm5uVuweItXR0OBWDW8qt20HGzTsnLEs U5AVhA5BZxeQEENBCrFWrGCftOP1vfdh2wziIoqHk9V3VduWtFTDMMLTu1YQ60nqWfM2nviY6NrS vBpfdWK4QOUJKN0VaBnRAVCrRQkRLhOce4kAUuPcWFl5mwnO8QsndWVU5E/nSY3QdkVlboikKO6u wSuM9l370sbq+w+77bLb8IlZacClFAwbfBxCbQMHsSecuLDL0nf70au+DDS1mYfA2mHpAuaSRN/s ZJlUMr7D0mo+MCfbYk/MH1nGWjyHIe5XkIdgLattwhx5zeSLGShcCJ5k6dw2+RpC8QxtloPaLtNw CrkyjjPDaOV6mhilkaJMUTnELDUx6KQhm1gutpDHsI31hdHQGqRMYciYA/5MTZH8mnvKmTn062FS gbCEANdIPpMIBQhpBdYfWcZo6i9OYdhU1lqLlnP9CAxGGonAR1vs/jOgzYk1+bkNjMj92JkC2G3T 0pgyQLciiOjdLWq4gdjKIZmNcKBosBVR1kskK6DKM6WUhtmdIRnSb9wf7JxzQTWfGYNMckn/J4oP t1A2yJzjdR3jMF4fcGoWkqjrrvVMRaQJmvASGTQEhjC9FUQEK1Hgi4sNFhIX0Wlwmi0RzMqi0axN YQZdB44CoQjeSG6lsm/4REXGxFAuL1NdCehEXB9h6dUkRDT+U8JpUvFtXai4kC0zzlhmFiGJJBtB 6kcBb1gNdZBhzeYDdsYF0108t+BgO/VrGVlK9fth3J4JT1wHElWk+YFpXeZw2CkC1Pz0+YhR1iID zItRIM6OxYFW33NWeYzobykDwwKEOApKUShEElQQtRVmgQPTIMC9hTMEBMSVBYWuEuU8J72RkLBD hgzhkYBgomBAsSVCUsoglk/0yhqsYPko1EljueDUk1RgBjLqqBdglUYNA0oAaoCxzTRUmCBuhIZS VOqH3fNg8YHFHCovxG8/IYAP1HMLDyHKxHd4fKXfuLrgygYP6oPnJiIK63Xz0lCjSiRNI6kC46j8 BiPac0H37OYwNRrOVqxhiNC8uY/UyYv1rsy+z7zCwPpUCzq+8VyEY0RnONJAWiPZzFKGZStkWYm2 8RbHl4wKTNVPMFqZggIfPHcHkoOOTI5eW6QQZCLhktYlEBQMnypPiilkQrU0qaGfcTZCjgsOE0Jn 5T94pqVCXoQOFhuvOFlTIpzk4u0gUqNk0sy6jAkkrWISPfHEG8/NFQ0MbBsf5Ejvg1G/xH5Ev2nk O8ZsPjRU/Emfnl4GY7UjlkaD02HebFse3sLk+Rp6ziXiS7gcl5TfjsX6F0I6ekAlReW5eMKki5TW tLvkKjKm49RGXI6DaVIJVLygVGYlzRex8DqKVPiNR0JsXkiAtDrNwjIwM3FBwMTScdRTUBYcjSeB zUt/r69hgYJIr0BCBT1BZcI/X7N5RIXXZ2zIOsbGsBn4/wgDOVM3zmqaRnGBX0agJHlZUxa3zNDC 4WS8YRKsFeHy1HLKsXsdsOyGVG6B1G/dQ2ePLyXnWdubDuyQeB7TFBkT7aGRBgadYKuIBttumxRB XapyAki438QPWUD4gsX29AjoxrhsP344joryCI7UgjID0EDpcMxPl3FaiBlNptBGdzpoKl+YQflL r8/mj1dNx4ztM4dFAltFS7SiDDlLQtfLTQohfk1O6FijHotlBJrw1eRcyWIiykepxLFImSsgorOR MghbWrjMdoePJZSqXfYgMP1jGsyFSpEcwqbCiohYVBTilpgS9gq9UBZirZz2Tz2hNIHFtLSQkqGg QfRZ6j2Gn1nmusp3S76owDt9gXF+3OtQ2wzQhlJZUpIuhdaq6LsG3KdewULMa3TWEoHMTLJUBVS7 6FDEDgrEvrJHiZrNu8ySmaT7CLgMffU/RpZHiONQ16e8lYPDYjNBVpS/tPk4dXyV3FODjU2ZUUoI dTo2GCURBeFYsjiT7pKGQ42GyhZaJkIDSHD2+1VLnWpaJJSUSsDnGq67t67p7yUEiRIMHn60QG1v lmO5zSmvFCbOPt5TIdnvj0jUxCaAMyOjTCIYNJiRjnUATYiaDvC6NNSvIkbiRh3SLp9YDRtPxINH gTJI2W5FUijBYcjag1tlfU3zTHHaT4EXl2jwgaAkSDECkOg2Gb0BaQSa0G69E50QLAdBiKGcCdkq HQwvq9DACeMgEEkWMIxQgqGH5XKIPIQQmg4sLWn6RewmfEQErEQfMefsJraaIGripUqfMF9APE8r ipmA5WDw6kfMUOznPrS5krEsjEg4yNCLtBd/QiwG2MQWm+D4MzExAyRXTfiJEnHbuPA0MoIp7fjd KnSYBLF17NdZlwcaSlSCQiqmruKJ61GhQ4Vonogg3gKS/LTEm2JR3ApEiaROigAzRjE3JFIISR5W IbSMpFhhNKjYMXItVT6osKHuGB0hLsQgsJo9igpI5jsnwr3VrlK8tjrGBgHE86AwowuT4wI+E0AM t6Su9niSCci60xxrnzNpNn8YUKQG49cFxcFpfAI8Dya6oR42X7ihYXG9pZJF3BLas4TaOQjdloHz 3hhWDUNWXa3daVkTbbb/OA1ik1zgJYKClhyQCxZDeJ4C5RfxdW7um+KogSQd83imY8ey306pIBI5 tUsExUfmLA5lS4drBo2li5kdSmpQRRdPJWtLEs5j9lj74AP7gDZSkZGKSL6lL6aFAhAcECZTwVv9 3tvVpBan9Jd3YoZ1VP/Pf6tURxFEZQTJTDZKkvgiTsszVV/7kQz0oqmdmtmmhWS14yal7hck7RiM PDyYdRnBHtTNPxDAfQNSagbcl2nzi6A+hdQFk5jGVgkxL/ENN/SGvzBMp0kjMZjGF6LDULy0zWIW Kli4iLVOxYN0U84hBCwTFo8SkjQavXoIxDFWiPlzmviOZzrEsuGfeR690JD5ki6R9thCnTaIlvv6 Xw6aBEhiFBHySgWK7DsO0kfMRHjcUCBso197nnQFApOkpUnZETTIMzTojqqoO7OoiFYOns1ZKLsa DBzGTJ37XVfqEPVysXQLwSPVe7KDysqaCJhiCYObYUBlPjhLijR70UCuwnaBcrTYjtGSxV305436 4UJ/pqKgPdtDEmZJLxZMMkoZBssI5IZUJI6f4nrSAuX4KZIZDLI0pyPWXWTmgqkEBbyJ3OlUvLYg P2mVgjEskNkQEBIRFshEw4silIR3yX7j1CDG6wB08u+gbeapUQxhZ82Sksk4+whcL9BhY8MNSHRJ glAXkNfeLkCxLixkiiiCRQYIDIkEkGShApGLeKMO1hNRdhi8RcfMGcuzi8C26UR3k4Tqg0LGWIIr 6AiAy2Dw4J41kAaidI6Q6Tr5lCBXSFGEG5RKDWMwYKnwvg1mYoKQI7UjBJH4IaSPgb0XEuS98+Xy /Q3YUMEzz9xySD7qkLb84QBQkEcPEqUUrpJ4dOXqWaSOPaU0xWXmOCJu/It7RAxgB+yuoltPzLSm kIO0u7rvwLFePxjO87vVIDw/eWKDwbap7yPTdal1cEiiwJGBNVEZvqXuhJoK70XNEzImBJIzjAuG 8eMpl44+tKA3nZdgz0suEEhmUbPuhS09wg0lqJ6CqXtTbR2n0wLbGmZZIoVJUSZImMqn8XoTXKxG 0bRMxQ4trlj2OAoAdQ0JmPjMo/OZCt47xiMIhBDwvSlDFIyqKjVFUoL5irXK3SnFXtC6VUgUFTt9 Y6SBjLKpTmPviQDQmhPazc9xQk0oQIVpzDC1MbiZRSO0D1BIs2wekM4bjr/9IsvQFi8r6+yIGrcC AhLzshjG4B6u2ANJrMOyXEM8HmLD4wRIySC3tV8pQl0IodzYC+xDMbBb8kHoN0A2s0oAVN/GM0yu zUIMJ3C2gviggxgOXHaDabEsSRIwlQKFVQpJSWlvTOUmAmJ5iu8xQtPph3+/mdoYndClxSY6EKRa TcRyB7YzYawvQqK+KSWyhegZ7JnukuYkXZwmKNKlKU4Bz482E7DakmOqK5RFGMgFCcSREh9gQCZp wA38TSDTxuSMBFr3ODxdt9FgCtS+RzS0FpGEV3FBGNaO/CJEoHJo/nkATDWk0e7cuhi4BeUDDeeh RRZsXNiiV8EPsqrXO7h5oc2dsm5Qijm8A0B4qOZKkRKKoVQSFkggzjjAtp5WImwz12I8ammRnoM4 GXIQuFKnwIzxOVN008QXDQcx7JF5sMqIwp2nhqQesSvcqrlwsbCVkMMCAsYzSqXW+uVa4Ln0sShn n3brQ1hRnqS0LSh1bF5KjKrIcoolxNDQtdmVV0V3BE4yqWIbg8RnsLcEvpaWh3AqYAsXBFRkLli4 FVBNxiQ73MYxpzTKixSmDSrMkIGWgvA0PZ19jbbH9vxzK0QUhEsjOYJNBDP6WJZEtpGWidJkyQzR EEykFR6/q6sDYzsxRBmMoLiR42aF7Gmbets3RRchiXnvL8RTF4DLmJDaS6ntKwlSlV0gfQitk4A6 uYyLEuHBqtYJSQ2jPnzIGyLMF8B1nWAybe7fDMpDSbigp+Haaccx5BgW2CYYhtlrzNgVUdodLaC2 RfgV/SO7lw5weVTJgFNTEV2lSklsTArPvXwhsGgsDb8ufBiBRAYX95wNhzR6oSC35F1KhVFyoaNO yfC0kkLs50jEVH6tKwEYh4aAKiD9dIFQBSRywX40S5qRRmjV6bTBsLRGRiSjMKd0Vn6mfSJwDCOg 76s8VhU1mSwlYP3EKgjI4EkLEZ1ANeNlR3h6+s2hQDrFUJM+gpCWcfaWQSXnLyDUIFTsIQlF6ZUO c5ySLzJQAd9NUqHSSkqkNIUerULd+1rFTfbLk6rSZRDRisRRKopEQFg6UQORCnm2KmEyVgvyssIH Y0WlKQCIp0TgLOBfAEQPv5ZcEvCl8sENBNPRZissCqADactQ56jiCSoV8pzs7DnNYDurugFBIkhS iHvgSLKhSNRotGVRiP8XckU4UJCIgDUz --===============0623901077414728121==--