MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
test_varpage.cpp
1 /*
2  Copyright (C) 2005, 2006 MySQL AB
3  All rights reserved. Use is subject to license terms.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #include <ndb_global.h>
20 #include "tuppage.hpp"
21 #include <Vector.hpp>
22 
23 struct Record
24 {
25  Uint32 idx;
26  Uint32 size;
27  Uint32* data;
28 };
29 
30 NdbOut&
31 operator <<(NdbOut& out, const Record& rec)
32 {
33  out << "[ idx: " << rec.idx << " sz: " << rec.size << " ]";
34  return out;
35 }
36 
37 #define TRACE(x) x
38 
39 static
40 bool
41 cmp(const Uint32 *p1, const Uint32 *p2, Uint32 words)
42 {
43  if(memcmp(p1, p2, 4*words) == 0)
44  return true;
45 
46  for(Uint32 i = 0; i<words; i++)
47  printf(" %.8x", p1[i]);
48  printf("\n");
49 
50  for(Uint32 i = 0; i<words; i++)
51  printf(" %.8x", p2[i]);
52  printf("\n");
53 
54  return false;
55 }
56 
57 static
58 void
59 do_test(int loops, int dist[5])
60 {
61  fprintf(stderr, "do_test(%d, [ %d %d %d %d %d ])\n",
62  loops,
63  dist[0],
64  dist[1],
65  dist[2],
66  dist[3],
67  dist[4]);
68  int allocated= 0;
69  Record records[8192];
70 
72  page.init();
73 
74  for(int i = 0; i<loops; i++)
75  {
76  assert(page.high_index + page.insert_pos <= page.DATA_WORDS);
77 
78  for(int j = 0; j<allocated; j++)
79  {
80  Record rec= records[j];
81  Uint32* ptr= page.get_ptr(rec.idx);
82  Uint32 pos = page.get_ptr(rec.idx) - page.m_data;
83  if (page.get_entry_len(rec.idx) != rec.size)
84  {
85  ndbout << "INVALID LEN " << j << " " << rec << " pos: " << pos << endl;
86  ndbout << page << endl;
87  abort();
88  }
89 
90  if(!cmp(ptr, rec.data, rec.size))
91  {
92  ndbout << "FAILED " << j << " " << rec << " pos: " << pos << endl;
93  ndbout << page << endl;
94  abort();
95  }
96  }
97 
98 loop:
99  int op;
100  int rnd= rand() % 100;
101  for(op= 0; op<5; op++)
102  if(rnd < dist[op])
103  break;
104 
105  if(allocated == 0)
106  op= 0;
107  if(page.free_space <= 2 && op == 0) goto loop;
108 
109  switch(op){
110  case 0: // Alloc
111  {
112  Record rec;
113  rec.size= 1 + (rand() % (page.free_space-1));
114  rec.data = new Uint32[rec.size];
115  for(Uint32 i= 0; i<rec.size; i++)
116  {
117  rec.data[i] = rand();
118  }
119  ndbout << "Alloc hi: " << page.high_index << " (" <<
120  ((rnd < 30) ? "any" :
121  (rnd < 60) ? "dir" :
122  (rnd < 80) ? "exp" : "fail") << ") ";
123  ndbout << rec.size << flush;
124  if (rnd < 30)
125  {
126  rec.idx= page.alloc_record(rec.size, &tmp, 0);
127  }
128  else if (rnd < 60)
129  {
130  // Alloc with id, from directory
131  Vector<Uint32> free;
132  for(Uint32 i = page.high_index - 1; i > 0; i--)
133  {
134  if (page.get_index_word(i) & page.FREE)
135  {
136  free.push_back(i);
137  if (free.size() > 100)
138  break;
139  }
140  }
141  if (free.size())
142  {
143  rec.idx = free[rand() % free.size()];
144  if (page.alloc_record(rec.idx, rec.size, &tmp) != rec.idx)
145  {
146  abort();
147  }
148  }
149  else
150  {
151  rec.idx = page.high_index;
152  if (page.alloc_record(rec.idx, rec.size, &tmp) != rec.idx)
153  {
154  if (rec.size + 1 != page.free_space)
155  abort();
156  delete [] rec.data;
157  ndbout_c(" FAIL");
158  break;
159  }
160  }
161  }
162  else if(rnd < 80)
163  {
164  // Alloc with id, outside of directory
165  rec.idx = page.high_index + (rand() % (page.free_space - rec.size));
166  if (page.alloc_record(rec.idx, rec.size, &tmp) != rec.idx)
167  {
168  abort();
169  }
170  }
171  else
172  {
173  rec.idx = page.high_index + (page.free_space - rec.size) + 1;
174  if (page.alloc_record(rec.idx, rec.size, &tmp) == rec.idx)
175  {
176  abort();
177  }
178  delete [] rec.data;
179  ndbout_c(" FAIL");
180  break;
181  }
182 
183  Uint32 pos = page.get_ptr(rec.idx) - page.m_data;
184  ndbout << " -> " << rec.idx
185  << " pos: " << pos << endl;
186  Uint32* ptr= page.get_ptr(rec.idx);
187  memcpy(ptr, rec.data, 4*rec.size);
188  records[allocated++] = rec;
189  break;
190  }
191  case 1: // Free
192  {
193  int no= rand() % allocated;
194  Record rec= records[no];
195  Uint32 pos = page.get_ptr(rec.idx) - page.m_data;
196  ndbout << "Free hi: " << page.high_index << " no: " << no << " idx: " << rec.idx << " pos: " << pos << endl;
197  Uint32* ptr= page.get_ptr(rec.idx);
198  assert(page.get_entry_len(rec.idx) == rec.size);
199  cmp(ptr, rec.data, rec.size);
200  delete[] rec.data;
201  page.free_record(rec.idx, 0);
202 
203  for (unsigned k = no; k + 1 < allocated; k++)
204  records[k] = records[k+1];
205  allocated--;
206 
207  break;
208  }
209  case 2: // Reorg
210  ndbout << "Reorg" << endl;
211  page.reorg(&tmp);
212  break;
213  case 3:
214  {
215  Uint32 free = page.free_space;
216  if (free <= 2)
217  {
218  goto shrink;
219  }
220  free /= 2;
221  int no = rand() % allocated;
222  Record rec= records[no];
223  ndbout << "Expand no: " << no << " idx: " << rec.idx
224  << " add: " << free << " reorg: "
225  << !page.is_space_behind_entry(rec.idx, free)
226  << endl;
227  if (!page.is_space_behind_entry(rec.idx, free))
228  {
229  Uint32 buffer[8192];
230  Uint32 len = page.get_entry_len(rec.idx);
231  memcpy(buffer, page.get_ptr(rec.idx), 4*len);
232  page.set_entry_len(rec.idx, 0);
233  page.free_space += len;
234  page.reorg(&tmp);
235  memcpy(page.get_free_space_ptr(), buffer, 4*len);
236  page.set_entry_offset(rec.idx, page.insert_pos);
237  free += len;
238  records[no].size = 0;
239  }
240 
241  page.grow_entry(rec.idx, free);
242  records[no].size += free;
243  Uint32 *ptr = page.get_ptr(rec.idx);
244  Uint32 *new_data = new Uint32[records[no].size];
245  for(Uint32 i= 0; i<records[no].size; i++)
246  {
247  ptr[i] = new_data[i] = rand();
248  }
249  delete []rec.data;
250  records[no].data = new_data;
251  break;
252  }
253  case 4:
254  {
255  shrink:
256  int no = rand() % allocated;
257  Record rec = records[no];
258  Uint32 sz = rec.size / 2 + 1;
259  ndbout << "Shrink no: " << no << " idx: " << rec.idx << " remove: "
260  << (rec.size - sz) << endl;
261  page.shrink_entry(rec.idx, sz);
262  records[no].size = sz;
263  break;
264  }
265  }
266 
267  }
268  ndbout << page << endl;
269 }
270 
271 int
272 main(int argc, char **argv)
273 {
274  ndb_init();
275 
276  if (argc > 1)
277  {
278  time_t seed = time(0);
279  srand(seed);
280  fprintf(stderr, "srand(%d)\n", seed);
281  }
282  // alloc, free, reorg, grow, shrink
283 
284  int t1[] = { 10, 60, 70, 85, 100 };
285  int t2[] = { 30, 60, 70, 85, 100 };
286  int t3[] = { 50, 60, 70, 85, 100 };
287 
288  do_test(10000, t1);
289  do_test(10000, t2);
290  do_test(10000, t3);
291 
292  return 0;
293 }
294 
295 template class Vector<Record>;
296 
297 // hp3750
298 struct Signal { Signal(); int foo; };
299 Signal::Signal(){}