112
by Laurynas Biveinis
Port the dynamic VARCHAR/HEAP support in MEMORY storage engine from |
1 |
diff -ruN a/include/heap.h b/include/heap.h
|
2 |
--- a/include/heap.h 2011-04-11 13:44:02.000000000 +0300
|
|
3 |
+++ b/include/heap.h 2011-06-02 15:28:13.294917001 +0300
|
|
4 |
@@ -33,7 +33,17 @@
|
|
5 |
#include "my_compare.h" |
|
6 |
#include "my_tree.h" |
|
7 |
||
8 |
- /* defines used by heap-funktions */
|
|
9 |
+/* Define index limits to be identical to MyISAM ones for compatibility. */
|
|
10 |
+
|
|
11 |
+#if MAX_INDEXES > HA_MAX_POSSIBLE_KEY
|
|
12 |
+#define HP_MAX_KEY HA_MAX_POSSIBLE_KEY /* Max allowed keys */
|
|
13 |
+#else
|
|
14 |
+#define HP_MAX_KEY MAX_INDEXES /* Max allowed keys */
|
|
15 |
+#endif
|
|
16 |
+
|
|
17 |
+#define HP_MAX_KEY_LENGTH 1000 /* Max length in bytes */
|
|
18 |
+
|
|
19 |
+/* defines used by heap-funktions */
|
|
20 |
||
21 |
#define HP_MAX_LEVELS 4 /* 128^5 records is enough */ |
|
22 |
#define HP_PTRS_IN_NOD 128 |
|
23 |
@@ -129,22 +139,58 @@
|
|
24 |
uint (*get_key_length)(struct st_hp_keydef *keydef, const uchar *key); |
|
25 |
} HP_KEYDEF; |
|
26 |
||
27 |
-typedef struct st_heap_share
|
|
28 |
+typedef struct st_heap_columndef /* column information */
|
|
29 |
+{
|
|
30 |
+ int16 type; /* en_fieldtype */
|
|
31 |
+ uint32 length; /* length of field */
|
|
32 |
+ uint32 offset; /* Offset to position in row */
|
|
33 |
+ uint8 null_bit; /* If column may be 0 */
|
|
34 |
+ uint16 null_pos; /* position for null marker */
|
|
35 |
+ uint8 length_bytes; /* length of the size, 1 o 2 bytes */
|
|
36 |
+} HP_COLUMNDEF;
|
|
37 |
+
|
|
38 |
+typedef struct st_heap_dataspace /* control data for data space */
|
|
39 |
{ |
|
40 |
HP_BLOCK block; |
|
41 |
+ /* Total chunks ever allocated in this dataspace */
|
|
42 |
+ uint chunk_count;
|
|
43 |
+ uint del_chunk_count; /* Deleted chunks count */
|
|
44 |
+ uchar *del_link; /* Link to last deleted chunk */
|
|
45 |
+ uint chunk_length; /* Total length of one chunk */
|
|
46 |
+ /* Length of payload that will be placed into one chunk */
|
|
47 |
+ uint chunk_dataspace_length;
|
|
48 |
+ /* Offset of the status flag relative to the chunk start */
|
|
49 |
+ uint offset_status;
|
|
50 |
+ /* Offset of the linking pointer relative to the chunk start */
|
|
51 |
+ uint offset_link;
|
|
52 |
+ /* Test whether records have variable size and so "next" pointer */
|
|
53 |
+ uint is_variable_size;
|
|
54 |
+ /* Total size allocated within this data space */
|
|
55 |
+ ulonglong total_data_length;
|
|
56 |
+} HP_DATASPACE;
|
|
57 |
+
|
|
58 |
+typedef struct st_heap_share
|
|
59 |
+{
|
|
60 |
HP_KEYDEF *keydef; |
|
61 |
+ HP_COLUMNDEF *column_defs;
|
|
62 |
+ /* Describes "block", which contains actual records */
|
|
63 |
+ HP_DATASPACE recordspace;
|
|
64 |
ulong min_records,max_records; /* Params to open */ |
|
65 |
- ulonglong data_length,index_length,max_table_size;
|
|
66 |
+ ulonglong index_length, max_table_size;
|
|
67 |
uint key_stat_version; /* version to indicate insert/delete */ |
|
68 |
- uint records; /* records */
|
|
69 |
- uint blength; /* records rounded up to 2^n */
|
|
70 |
- uint deleted; /* Deleted records in database */
|
|
71 |
- uint reclength; /* Length of one record */
|
|
72 |
+ uint records; /* Actual record (row) count */
|
|
73 |
+ uint blength; /* used_chunk_count rounded up to 2^n */
|
|
74 |
+ /*
|
|
75 |
+ Length of record's fixed part, which contains keys and always fits into the
|
|
76 |
+ first chunk.
|
|
77 |
+ */
|
|
78 |
+ uint fixed_data_length;
|
|
79 |
+ uint fixed_column_count; /* Number of columns stored in fixed_data_length */
|
|
80 |
uint changed; |
|
81 |
uint keys,max_key_length; |
|
82 |
+ uint column_count;
|
|
83 |
uint currently_disabled_keys; /* saved value from "keys" when disabled */ |
|
84 |
uint open_count; |
|
85 |
- uchar *del_link; /* Link to next block with del. rec */
|
|
86 |
char * name; /* Name of "memory-file" */ |
|
87 |
THR_LOCK lock; |
|
88 |
mysql_mutex_t intern_lock; /* Locking for use with _locking */ |
|
89 |
@@ -153,6 +199,7 @@
|
|
90 |
uint auto_key; |
|
91 |
uint auto_key_type; /* real type of the auto key segment */ |
|
92 |
ulonglong auto_increment; |
|
93 |
+ uint blobs; /* Number of blobs in table */
|
|
94 |
} HP_SHARE; |
|
95 |
||
96 |
struct st_hp_hash_info; |
|
97 |
@@ -162,7 +209,7 @@
|
|
98 |
HP_SHARE *s; |
|
99 |
uchar *current_ptr; |
|
100 |
struct st_hp_hash_info *current_hash_ptr; |
|
101 |
- ulong current_record,next_block;
|
|
102 |
+ ulong current_record;
|
|
103 |
int lastinx,errkey; |
|
104 |
int mode; /* Mode of file (READONLY..) */ |
|
105 |
uint opt_flag,update; |
|
106 |
@@ -175,6 +222,9 @@
|
|
107 |
my_bool implicit_emptied; |
|
108 |
THR_LOCK_DATA lock; |
|
109 |
LIST open_list; |
|
110 |
+ uchar *blob_buffer; /* Temporary buffer used to return BLOB values */
|
|
111 |
+ uint blob_size; /* Current blob_buffer size */
|
|
112 |
+ uint blob_offset; /* Current offset in blob_buffer */
|
|
113 |
} HP_INFO; |
|
114 |
||
115 |
||
116 |
@@ -196,6 +246,14 @@
|
|
117 |
open_count to 1. Is only looked at if not internal_table. |
|
118 |
*/ |
|
119 |
my_bool pin_share; |
|
120 |
+ uint columns;
|
|
121 |
+ HP_COLUMNDEF *columndef;
|
|
122 |
+ uint fixed_key_fieldnr;
|
|
123 |
+ uint fixed_data_size;
|
|
124 |
+ uint keys_memory_size;
|
|
125 |
+ uint max_chunk_size;
|
|
126 |
+ uint is_dynamic;
|
|
127 |
+ uint blobs;
|
|
128 |
} HP_CREATE_INFO; |
|
129 |
||
130 |
/* Prototypes for heap-functions */ |
|
131 |
@@ -212,9 +270,8 @@
|
|
132 |
extern int heap_scan(register HP_INFO *info, uchar *record); |
|
133 |
extern int heap_delete(HP_INFO *info,const uchar *buff); |
|
134 |
extern int heap_info(HP_INFO *info,HEAPINFO *x,int flag); |
|
135 |
-extern int heap_create(const char *name,
|
|
136 |
- HP_CREATE_INFO *create_info, HP_SHARE **share,
|
|
137 |
- my_bool *created_new_share);
|
|
138 |
+extern int heap_create(const char *name, HP_CREATE_INFO *create_info,
|
|
139 |
+ HP_SHARE **res, my_bool *created_new_share);
|
|
140 |
extern int heap_delete_table(const char *name); |
|
141 |
extern void heap_drop_table(HP_INFO *info); |
|
142 |
extern int heap_extra(HP_INFO *info,enum ha_extra_function function); |
|
143 |
diff -ruN a/mysql-test/r/create.result b/mysql-test/r/create.result
|
|
144 |
--- a/mysql-test/r/create.result 2011-06-02 11:38:04.000000000 +0300
|
|
145 |
+++ b/mysql-test/r/create.result 2011-06-02 15:56:29.224917005 +0300
|
|
146 |
@@ -33,10 +33,7 @@
|
|
147 |
create table t1 (b char(0) not null, index(b)); |
|
148 |
ERROR 42000: The used storage engine can't index column 'b' |
|
149 |
create table t1 (a int not null,b text) engine=heap; |
|
150 |
-ERROR 42000: The used table type doesn't support BLOB/TEXT columns
|
|
151 |
drop table if exists t1; |
|
152 |
-Warnings:
|
|
153 |
-Note 1051 Unknown table 't1'
|
|
154 |
create table t1 (ordid int(8) not null auto_increment, ord varchar(50) not null, primary key (ord,ordid)) engine=heap; |
|
155 |
ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key |
|
156 |
create table not_existing_database.test (a int); |
|
157 |
diff -ruN a/mysql-test/r/ctype_utf8mb4_heap.result b/mysql-test/r/ctype_utf8mb4_heap.result
|
|
158 |
--- a/mysql-test/r/ctype_utf8mb4_heap.result 2011-04-11 13:44:02.000000000 +0300
|
|
159 |
+++ b/mysql-test/r/ctype_utf8mb4_heap.result 2011-06-02 15:31:07.794917003 +0300
|
|
160 |
@@ -1124,6 +1124,8 @@
|
|
161 |
a varchar(255) NOT NULL default '', |
|
162 |
KEY a (a) |
|
163 |
) ENGINE=heap DEFAULT CHARSET=utf8mb4 COLLATE utf8mb4_general_ci; |
|
164 |
+Warnings:
|
|
165 |
+Warning 1071 Specified key was too long; max key length is 1000 bytes
|
|
166 |
insert into t1 values (_utf8mb4 0xe880bd); |
|
167 |
insert into t1 values (_utf8mb4 0x5b); |
|
168 |
select hex(a) from t1; |
|
169 |
@@ -1162,6 +1164,8 @@
|
|
170 |
Warnings: |
|
171 |
Note 1051 Unknown table 't1' |
|
172 |
CREATE TABLE t1(a VARCHAR(255), KEY(a)) ENGINE=heap DEFAULT CHARSET=utf8mb4; |
|
173 |
+Warnings:
|
|
174 |
+Warning 1071 Specified key was too long; max key length is 1000 bytes
|
|
175 |
INSERT INTO t1 VALUES('uuABCDEFGHIGKLMNOPRSTUVWXYZ̀ˆbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb'); |
|
176 |
INSERT INTO t1 VALUES('uu'); |
|
177 |
check table t1; |
|
178 |
diff -ruN a/mysql-test/t/create.test b/mysql-test/t/create.test
|
|
179 |
--- a/mysql-test/t/create.test 2011-04-11 13:44:01.000000000 +0300
|
|
180 |
+++ b/mysql-test/t/create.test 2011-06-02 15:32:49.614917004 +0300
|
|
181 |
@@ -33,7 +33,7 @@
|
|
182 |
drop table if exists t1,t2; |
|
183 |
--error 1167 |
|
184 |
create table t1 (b char(0) not null, index(b)); |
|
185 |
---error 1163
|
|
186 |
+# BLOB/TEXT fields are now supported by HEAP
|
|
187 |
create table t1 (a int not null,b text) engine=heap; |
|
188 |
drop table if exists t1; |
|
189 |
||
190 |
diff -ruN a/storage/heap/CMakeLists.txt b/storage/heap/CMakeLists.txt
|
|
191 |
--- a/storage/heap/CMakeLists.txt 2011-04-11 13:44:03.000000000 +0300
|
|
192 |
+++ b/storage/heap/CMakeLists.txt 2011-06-02 15:37:43.744917005 +0300
|
|
193 |
@@ -20,6 +20,7 @@
|
|
194 |
ha_heap.cc |
|
195 |
hp_delete.c hp_extra.c hp_hash.c hp_info.c hp_open.c hp_panic.c |
|
196 |
hp_rename.c hp_rfirst.c hp_rkey.c hp_rlast.c hp_rnext.c hp_rprev.c |
|
197 |
+ hp_dspace.c hp_record.c
|
|
198 |
hp_rrnd.c hp_rsame.c hp_scan.c hp_static.c hp_update.c hp_write.c) |
|
199 |
||
200 |
MYSQL_ADD_PLUGIN(heap ${HEAP_SOURCES} STORAGE_ENGINE MANDATORY RECOMPILE_FOR_EMBEDDED) |
|
201 |
diff -ruN a/storage/heap/_check.c b/storage/heap/_check.c
|
|
202 |
--- a/storage/heap/_check.c 2011-04-11 13:44:03.000000000 +0300
|
|
203 |
+++ b/storage/heap/_check.c 2011-06-02 15:37:43.744917005 +0300
|
|
204 |
@@ -43,7 +43,7 @@
|
|
205 |
{ |
|
206 |
int error; |
|
207 |
uint key; |
|
208 |
- ulong records=0, deleted=0, pos, next_block;
|
|
209 |
+ ulong records= 0, deleted= 0, chunk_count= 0, pos, next_block;
|
|
210 |
HP_SHARE *share=info->s; |
|
211 |
HP_INFO save_info= *info; /* Needed because scan_init */ |
|
212 |
DBUG_ENTER("heap_check_heap"); |
|
213 |
@@ -64,31 +64,55 @@
|
|
214 |
{ |
|
215 |
if (pos < next_block) |
|
216 |
{ |
|
217 |
- info->current_ptr+= share->block.recbuffer;
|
|
218 |
+ info->current_ptr+= share->recordspace.block.recbuffer;
|
|
219 |
} |
|
220 |
else |
|
221 |
{ |
|
222 |
- next_block+= share->block.records_in_block;
|
|
223 |
- if (next_block >= share->records+share->deleted)
|
|
224 |
+ next_block+= share->recordspace.block.records_in_block;
|
|
225 |
+ if (next_block >= share->recordspace.chunk_count)
|
|
226 |
{ |
|
227 |
- next_block= share->records+share->deleted;
|
|
228 |
- if (pos >= next_block)
|
|
229 |
- break; /* End of file */
|
|
230 |
+ next_block= share->recordspace.chunk_count;
|
|
231 |
+ if (pos >= next_block)
|
|
232 |
+ break; /* End of file */
|
|
233 |
} |
|
234 |
} |
|
235 |
hp_find_record(info,pos); |
|
236 |
||
237 |
- if (!info->current_ptr[share->reclength])
|
|
238 |
+ switch (get_chunk_status(&share->recordspace, info->current_ptr)) {
|
|
239 |
+ case CHUNK_STATUS_DELETED:
|
|
240 |
deleted++; |
|
241 |
- else
|
|
242 |
+ chunk_count++;
|
|
243 |
+ break;
|
|
244 |
+ case CHUNK_STATUS_ACTIVE:
|
|
245 |
records++; |
|
246 |
+ chunk_count++;
|
|
247 |
+ break;
|
|
248 |
+ case CHUNK_STATUS_LINKED:
|
|
249 |
+ chunk_count++;
|
|
250 |
+ break;
|
|
251 |
+ default:
|
|
252 |
+ DBUG_PRINT("error",
|
|
253 |
+ ("Unknown record status: Record: 0x%lx Status %lu",
|
|
254 |
+ (long) info->current_ptr,
|
|
255 |
+ (ulong) get_chunk_status(&share->recordspace,
|
|
256 |
+ info->current_ptr)));
|
|
257 |
+ error|= 1;
|
|
258 |
+ break;
|
|
259 |
+ }
|
|
260 |
} |
|
261 |
||
262 |
- if (records != share->records || deleted != share->deleted)
|
|
263 |
- {
|
|
264 |
- DBUG_PRINT("error",("Found rows: %lu (%lu) deleted %lu (%lu)",
|
|
265 |
- records, (ulong) share->records,
|
|
266 |
- deleted, (ulong) share->deleted));
|
|
267 |
+ /* TODO: verify linked chunks (no orphans, no cycles, no bad links) */
|
|
268 |
+
|
|
269 |
+ if (records != share->records ||
|
|
270 |
+ chunk_count != share->recordspace.chunk_count ||
|
|
271 |
+ deleted != share->recordspace.del_chunk_count)
|
|
272 |
+ {
|
|
273 |
+ DBUG_PRINT("error",
|
|
274 |
+ ("Found rows: %lu (%lu) total chunks %lu (%lu) deleted chunks "
|
|
275 |
+ "%lu (%lu)",
|
|
276 |
+ records, (ulong) share->records,
|
|
277 |
+ chunk_count, (ulong) share->recordspace.chunk_count,
|
|
278 |
+ deleted, (ulong) share->recordspace.del_chunk_count));
|
|
279 |
error= 1; |
|
280 |
} |
|
281 |
*info= save_info; |
|
282 |
@@ -177,7 +201,7 @@
|
|
283 |
do |
|
284 |
{ |
|
285 |
memcpy(&recpos, key + (*keydef->get_key_length)(keydef,key), sizeof(uchar*)); |
|
286 |
- key_length= hp_rb_make_key(keydef, info->recbuf, recpos, 0);
|
|
287 |
+ key_length= hp_rb_make_key(keydef, info->recbuf, recpos, 0, TRUE);
|
|
288 |
if (ha_key_cmp(keydef->seg, (uchar*) info->recbuf, (uchar*) key, |
|
289 |
key_length, SEARCH_FIND | SEARCH_SAME, not_used)) |
|
290 |
{ |
|
291 |
diff -ruN a/storage/heap/_rectest.c b/storage/heap/_rectest.c
|
|
292 |
--- a/storage/heap/_rectest.c 2011-04-11 13:44:03.000000000 +0300
|
|
293 |
+++ b/storage/heap/_rectest.c 2011-06-02 15:38:02.774917002 +0300
|
|
294 |
@@ -22,7 +22,9 @@
|
|
295 |
{ |
|
296 |
DBUG_ENTER("hp_rectest"); |
|
297 |
||
298 |
- if (memcmp(info->current_ptr,old,(size_t) info->s->reclength))
|
|
299 |
+ if (hp_process_record_data_to_chunkset(info->s, old,
|
|
300 |
+ info->current_ptr,
|
|
301 |
+ 1))
|
|
302 |
{ |
|
303 |
DBUG_RETURN((my_errno=HA_ERR_RECORD_CHANGED)); /* Record have changed */ |
|
304 |
} |
|
305 |
diff -ruN a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc
|
|
306 |
--- a/storage/heap/ha_heap.cc 2011-04-11 13:44:03.000000000 +0300
|
|
307 |
+++ b/storage/heap/ha_heap.cc 2011-06-02 15:37:43.744917005 +0300
|
|
308 |
@@ -113,6 +113,7 @@
|
|
309 |
||
310 |
rc= heap_create(name, &create_info, &internal_share, &created_new_share); |
|
311 |
my_free(create_info.keydef); |
|
312 |
+ my_free(create_info.columndef);
|
|
313 |
if (rc) |
|
314 |
goto end; |
|
315 |
||
316 |
@@ -194,6 +195,12 @@
|
|
317 |
{ |
|
318 |
if (table->key_info[i].algorithm == HA_KEY_ALG_BTREE) |
|
319 |
btree_keys.set_bit(i); |
|
320 |
+ /*
|
|
321 |
+ Reset per-key block size specification so they are not shown
|
|
322 |
+ in SHOW CREATE TABLE.
|
|
323 |
+ */
|
|
324 |
+ table->key_info[i].block_size= 0;
|
|
325 |
+ table->key_info[i].flags&= ~HA_USES_BLOCK_SIZE;
|
|
326 |
} |
|
327 |
} |
|
328 |
||
329 |
@@ -427,6 +434,13 @@
|
|
330 |
return 0; |
|
331 |
} |
|
332 |
||
333 |
+enum row_type ha_heap::get_row_type() const
|
|
334 |
+{
|
|
335 |
+ if (file->s->recordspace.is_variable_size)
|
|
336 |
+ return ROW_TYPE_DYNAMIC;
|
|
337 |
+
|
|
338 |
+ return ROW_TYPE_FIXED;
|
|
339 |
+}
|
|
340 |
||
341 |
int ha_heap::extra(enum ha_extra_function operation) |
|
342 |
{ |
|
343 |
@@ -644,23 +658,70 @@
|
|
344 |
heap_prepare_hp_create_info(TABLE *table_arg, bool internal_table, |
|
345 |
HP_CREATE_INFO *hp_create_info) |
|
346 |
{ |
|
347 |
- uint key, parts, mem_per_row= 0, keys= table_arg->s->keys;
|
|
348 |
+ uint key, parts, mem_per_row_keys= 0, keys= table_arg->s->keys;
|
|
349 |
uint auto_key= 0, auto_key_type= 0; |
|
350 |
- ha_rows max_rows;
|
|
351 |
+ uint fixed_key_fieldnr = 0, fixed_data_size = 0, next_field_pos = 0;
|
|
352 |
+ uint column_idx, column_count= table_arg->s->fields;
|
|
353 |
+ HP_COLUMNDEF *columndef;
|
|
354 |
HP_KEYDEF *keydef; |
|
355 |
HA_KEYSEG *seg; |
|
356 |
TABLE_SHARE *share= table_arg->s; |
|
357 |
bool found_real_auto_increment= 0; |
|
358 |
+ uint blobs= 0;
|
|
359 |
||
360 |
bzero(hp_create_info, sizeof(*hp_create_info)); |
|
361 |
||
362 |
+ if (!(columndef= (HP_COLUMNDEF*) my_malloc(column_count *
|
|
363 |
+ sizeof(HP_COLUMNDEF),
|
|
364 |
+ MYF(MY_WME))))
|
|
365 |
+ return my_errno;
|
|
366 |
+
|
|
367 |
+ for (column_idx= 0; column_idx < column_count; column_idx++)
|
|
368 |
+ {
|
|
369 |
+ Field* field= *(table_arg->field + column_idx);
|
|
370 |
+ HP_COLUMNDEF* column= columndef + column_idx;
|
|
371 |
+ column->type= (uint16) field->type();
|
|
372 |
+ column->length= field->pack_length();
|
|
373 |
+ column->offset= field->offset(table_arg->record[0]);
|
|
374 |
+
|
|
375 |
+ if (field->null_bit)
|
|
376 |
+ {
|
|
377 |
+ column->null_bit= field->null_bit;
|
|
378 |
+ column->null_pos= (uint) (field->null_ptr -
|
|
379 |
+ (uchar*) table_arg->record[0]);
|
|
380 |
+ }
|
|
381 |
+ else
|
|
382 |
+ {
|
|
383 |
+ column->null_bit= 0;
|
|
384 |
+ column->null_pos= 0;
|
|
385 |
+ }
|
|
386 |
+
|
|
387 |
+ if (field->type() == MYSQL_TYPE_VARCHAR)
|
|
388 |
+ {
|
|
389 |
+ column->length_bytes= (uint8) (((Field_varstring *) field)->length_bytes);
|
|
390 |
+ }
|
|
391 |
+ else if (field->type() == MYSQL_TYPE_BLOB)
|
|
392 |
+ {
|
|
393 |
+ blobs++;
|
|
394 |
+ column->length_bytes= (uint8)
|
|
395 |
+ (((Field_blob *) field)->pack_length_no_ptr());
|
|
396 |
+ }
|
|
397 |
+ else
|
|
398 |
+ {
|
|
399 |
+ column->length_bytes= 0;
|
|
400 |
+ }
|
|
401 |
+ }
|
|
402 |
+
|
|
403 |
for (key= parts= 0; key < keys; key++) |
|
404 |
parts+= table_arg->key_info[key].key_parts; |
|
405 |
||
406 |
if (!(keydef= (HP_KEYDEF*) my_malloc(keys * sizeof(HP_KEYDEF) + |
|
407 |
parts * sizeof(HA_KEYSEG), |
|
408 |
MYF(MY_WME)))) |
|
409 |
+ {
|
|
410 |
+ my_free((uchar *) columndef);
|
|
411 |
return my_errno; |
|
412 |
+ }
|
|
413 |
seg= reinterpret_cast<HA_KEYSEG*>(keydef + keys); |
|
414 |
for (key= 0; key < keys; key++) |
|
415 |
{ |
|
416 |
@@ -676,11 +737,11 @@
|
|
417 |
case HA_KEY_ALG_UNDEF: |
|
418 |
case HA_KEY_ALG_HASH: |
|
419 |
keydef[key].algorithm= HA_KEY_ALG_HASH; |
|
420 |
- mem_per_row+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
|
|
421 |
+ mem_per_row_keys+= sizeof(char*) * 2; // = sizeof(HASH_INFO)
|
|
422 |
break; |
|
423 |
case HA_KEY_ALG_BTREE: |
|
424 |
keydef[key].algorithm= HA_KEY_ALG_BTREE; |
|
425 |
- mem_per_row+=sizeof(TREE_ELEMENT)+pos->key_length+sizeof(char*);
|
|
426 |
+ mem_per_row_keys+=sizeof(TREE_ELEMENT)+pos->key_length+sizeof(char*);
|
|
427 |
break; |
|
428 |
default: |
|
429 |
DBUG_ASSERT(0); // cannot happen |
|
430 |
@@ -705,6 +766,16 @@
|
|
431 |
seg->length= (uint) key_part->length; |
|
432 |
seg->flag= key_part->key_part_flag; |
|
433 |
||
434 |
+ next_field_pos= seg->start;
|
|
435 |
+ if (field->type() == MYSQL_TYPE_VARCHAR)
|
|
436 |
+ {
|
|
437 |
+ Field *orig_field= *(table_arg->field + key_part->field->field_index);
|
|
438 |
+ next_field_pos+= orig_field->pack_length();
|
|
439 |
+ }
|
|
440 |
+ else
|
|
441 |
+ {
|
|
442 |
+ next_field_pos+= seg->length;
|
|
443 |
+ }
|
|
444 |
if (field->flags & (ENUM_FLAG | SET_FLAG)) |
|
445 |
seg->charset= &my_charset_bin; |
|
446 |
else |
|
447 |
@@ -730,9 +801,75 @@
|
|
448 |
auto_key= key+ 1; |
|
449 |
auto_key_type= field->key_type(); |
|
450 |
} |
|
451 |
+
|
|
452 |
+ switch (seg->type) {
|
|
453 |
+ case HA_KEYTYPE_SHORT_INT:
|
|
454 |
+ case HA_KEYTYPE_LONG_INT:
|
|
455 |
+ case HA_KEYTYPE_FLOAT:
|
|
456 |
+ case HA_KEYTYPE_DOUBLE:
|
|
457 |
+ case HA_KEYTYPE_USHORT_INT:
|
|
458 |
+ case HA_KEYTYPE_ULONG_INT:
|
|
459 |
+ case HA_KEYTYPE_LONGLONG:
|
|
460 |
+ case HA_KEYTYPE_ULONGLONG:
|
|
461 |
+ case HA_KEYTYPE_INT24:
|
|
462 |
+ case HA_KEYTYPE_UINT24:
|
|
463 |
+ case HA_KEYTYPE_INT8:
|
|
464 |
+ seg->flag|= HA_SWAP_KEY;
|
|
465 |
+ break;
|
|
466 |
+ case HA_KEYTYPE_VARBINARY1:
|
|
467 |
+ /* Case-insensitiveness is handled in coll->hash_sort */
|
|
468 |
+ seg->type= HA_KEYTYPE_VARTEXT1;
|
|
469 |
+ /* fall through */
|
|
470 |
+ case HA_KEYTYPE_VARTEXT1:
|
|
471 |
+ keydef[key].flag|= HA_VAR_LENGTH_KEY;
|
|
472 |
+ /* Save number of bytes used to store length */
|
|
473 |
+ if (seg->flag & HA_BLOB_PART)
|
|
474 |
+ seg->bit_start= field->pack_length() - share->blob_ptr_size;
|
|
475 |
+ else
|
|
476 |
+ seg->bit_start= 1;
|
|
477 |
+ break;
|
|
478 |
+ case HA_KEYTYPE_VARBINARY2:
|
|
479 |
+ /* Case-insensitiveness is handled in coll->hash_sort */
|
|
480 |
+ /* fall_through */
|
|
481 |
+ case HA_KEYTYPE_VARTEXT2:
|
|
482 |
+ keydef[key].flag|= HA_VAR_LENGTH_KEY;
|
|
483 |
+ /* Save number of bytes used to store length */
|
|
484 |
+ if (seg->flag & HA_BLOB_PART)
|
|
485 |
+ seg->bit_start= field->pack_length() - share->blob_ptr_size;
|
|
486 |
+ else
|
|
487 |
+ seg->bit_start= 2;
|
|
488 |
+ /*
|
|
489 |
+ Make future comparison simpler by only having to check for
|
|
490 |
+ one type
|
|
491 |
+ */
|
|
492 |
+ seg->type= HA_KEYTYPE_VARTEXT1;
|
|
493 |
+ break;
|
|
494 |
+ default:
|
|
495 |
+ break;
|
|
496 |
+ }
|
|
497 |
+
|
|
498 |
+ if (next_field_pos > fixed_data_size)
|
|
499 |
+ {
|
|
500 |
+ fixed_data_size= next_field_pos;
|
|
501 |
+ }
|
|
502 |
+
|
|
503 |
+
|
|
504 |
+ if (field->field_index >= fixed_key_fieldnr)
|
|
505 |
+ {
|
|
506 |
+ /*
|
|
507 |
+ Do not use seg->fieldnr as it's not reliable in case of temp tables
|
|
508 |
+ */
|
|
509 |
+ fixed_key_fieldnr= field->field_index + 1;
|
|
510 |
+ }
|
|
511 |
} |
|
512 |
} |
|
513 |
- mem_per_row+= MY_ALIGN(share->reclength + 1, sizeof(char*));
|
|
514 |
+
|
|
515 |
+ if (fixed_data_size < share->null_bytes)
|
|
516 |
+ {
|
|
517 |
+ /* Make sure to include null fields regardless of the presense of keys */
|
|
518 |
+ fixed_data_size = share->null_bytes;
|
|
519 |
+ }
|
|
520 |
+
|
|
521 |
if (table_arg->found_next_number_field) |
|
522 |
{ |
|
523 |
keydef[share->next_number_index].flag|= HA_AUTO_KEY; |
|
524 |
@@ -743,16 +880,19 @@
|
|
525 |
hp_create_info->max_table_size=current_thd->variables.max_heap_table_size; |
|
526 |
hp_create_info->with_auto_increment= found_real_auto_increment; |
|
527 |
hp_create_info->internal_table= internal_table; |
|
528 |
-
|
|
529 |
- max_rows= (ha_rows) (hp_create_info->max_table_size / mem_per_row);
|
|
530 |
- if (share->max_rows && share->max_rows < max_rows)
|
|
531 |
- max_rows= share->max_rows;
|
|
532 |
-
|
|
533 |
- hp_create_info->max_records= (ulong) max_rows;
|
|
534 |
+ hp_create_info->max_chunk_size= share->key_block_size;
|
|
535 |
+ hp_create_info->is_dynamic= (share->row_type == ROW_TYPE_DYNAMIC);
|
|
536 |
+ hp_create_info->columns= column_count;
|
|
537 |
+ hp_create_info->columndef= columndef;
|
|
538 |
+ hp_create_info->fixed_key_fieldnr= fixed_key_fieldnr;
|
|
539 |
+ hp_create_info->fixed_data_size= fixed_data_size;
|
|
540 |
+ hp_create_info->max_records= (ulong) share->max_rows;
|
|
541 |
hp_create_info->min_records= (ulong) share->min_rows; |
|
542 |
hp_create_info->keys= share->keys; |
|
543 |
hp_create_info->reclength= share->reclength; |
|
544 |
+ hp_create_info->keys_memory_size= mem_per_row_keys;
|
|
545 |
hp_create_info->keydef= keydef; |
|
546 |
+ hp_create_info->blobs= blobs;
|
|
547 |
return 0; |
|
548 |
} |
|
549 |
||
550 |
@@ -772,6 +912,7 @@
|
|
551 |
create_info->auto_increment_value - 1 : 0); |
|
552 |
error= heap_create(name, &hp_create_info, &internal_share, &created); |
|
553 |
my_free(hp_create_info.keydef); |
|
554 |
+ my_free(hp_create_info.columndef);
|
|
555 |
DBUG_ASSERT(file == 0); |
|
556 |
return (error); |
|
557 |
} |
|
558 |
@@ -782,6 +923,13 @@
|
|
559 |
table->file->info(HA_STATUS_AUTO); |
|
560 |
if (!(create_info->used_fields & HA_CREATE_USED_AUTO)) |
|
561 |
create_info->auto_increment_value= stats.auto_increment_value; |
|
562 |
+ if (!(create_info->used_fields & HA_CREATE_USED_KEY_BLOCK_SIZE))
|
|
563 |
+ {
|
|
564 |
+ if (file->s->recordspace.is_variable_size)
|
|
565 |
+ create_info->key_block_size= file->s->recordspace.chunk_length;
|
|
566 |
+ else
|
|
567 |
+ create_info->key_block_size= 0;
|
|
568 |
+ }
|
|
569 |
} |
|
570 |
||
571 |
void ha_heap::get_auto_increment(ulonglong offset, ulonglong increment, |
|
572 |
diff -ruN a/storage/heap/ha_heap.h b/storage/heap/ha_heap.h
|
|
573 |
--- a/storage/heap/ha_heap.h 2011-04-11 13:44:03.000000000 +0300
|
|
574 |
+++ b/storage/heap/ha_heap.h 2011-06-02 15:37:43.744917005 +0300
|
|
575 |
@@ -46,12 +46,11 @@
|
|
576 |
return ((table_share->key_info[inx].algorithm == HA_KEY_ALG_BTREE) ? |
|
577 |
"BTREE" : "HASH"); |
|
578 |
} |
|
579 |
- /* Rows also use a fixed-size format */
|
|
580 |
- enum row_type get_row_type() const { return ROW_TYPE_FIXED; }
|
|
581 |
+ enum row_type get_row_type() const;
|
|
582 |
const char **bas_ext() const; |
|
583 |
ulonglong table_flags() const |
|
584 |
{ |
|
585 |
- return (HA_FAST_KEY_READ | HA_NO_BLOBS | HA_NULL_IN_KEY |
|
|
586 |
+ return (HA_FAST_KEY_READ | HA_NULL_IN_KEY |
|
|
587 |
HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE | |
|
588 |
HA_REC_NOT_IN_SEQ | HA_CAN_INSERT_DELAYED | HA_NO_TRANSACTIONS | |
|
589 |
HA_HAS_RECORDS | HA_STATS_RECORDS_IS_EXACT); |
|
590 |
@@ -63,8 +62,9 @@
|
|
591 |
HA_ONLY_WHOLE_INDEX | HA_KEY_SCAN_NOT_ROR); |
|
592 |
} |
|
593 |
const key_map *keys_to_use_for_scanning() { return &btree_keys; } |
|
594 |
- uint max_supported_keys() const { return MAX_KEY; }
|
|
595 |
- uint max_supported_key_part_length() const { return MAX_KEY_LENGTH; }
|
|
596 |
+ uint max_supported_keys() const { return HP_MAX_KEY; }
|
|
597 |
+ uint max_supported_key_length() const { return HP_MAX_KEY_LENGTH; }
|
|
598 |
+ uint max_supported_key_part_length() const { return HP_MAX_KEY_LENGTH; }
|
|
599 |
double scan_time() |
|
600 |
{ return (double) (stats.records+stats.deleted) / 20.0+10; } |
|
601 |
double read_time(uint index, uint ranges, ha_rows rows) |
|
602 |
diff -ruN a/storage/heap/heapdef.h b/storage/heap/heapdef.h
|
|
603 |
--- a/storage/heap/heapdef.h 2011-04-11 13:44:03.000000000 +0300
|
|
604 |
+++ b/storage/heap/heapdef.h 2011-06-02 15:37:43.754916999 +0300
|
|
605 |
@@ -32,6 +32,13 @@
|
|
606 |
#define HP_MIN_RECORDS_IN_BLOCK 16 |
|
607 |
#define HP_MAX_RECORDS_IN_BLOCK 8192 |
|
608 |
||
609 |
+/* this chunk has been deleted and can be reused */
|
|
610 |
+#define CHUNK_STATUS_DELETED 0
|
|
611 |
+/* this chunk represents the first part of a live record */
|
|
612 |
+#define CHUNK_STATUS_ACTIVE 1
|
|
613 |
+/* this chunk is a continuation from another chunk (part of chunkset) */
|
|
614 |
+#define CHUNK_STATUS_LINKED 2
|
|
615 |
+
|
|
616 |
/* Some extern variables */ |
|
617 |
||
618 |
extern LIST *heap_open_list,*heap_share_list; |
|
619 |
@@ -42,7 +49,14 @@
|
|
620 |
#define hp_find_hash(A,B) ((HASH_INFO*) hp_find_block((A),(B))) |
|
621 |
||
622 |
/* Find pos for record and update it in info->current_ptr */ |
|
623 |
-#define hp_find_record(info,pos) (info)->current_ptr= hp_find_block(&(info)->s->block,pos)
|
|
624 |
+#define hp_find_record(info,pos) \
|
|
625 |
+ (info)->current_ptr= hp_find_block(&(info)->s->recordspace.block,pos)
|
|
626 |
+
|
|
627 |
+#define get_chunk_status(info,ptr) (ptr[(info)->offset_status])
|
|
628 |
+
|
|
629 |
+#define get_chunk_count(info,rec_length) \
|
|
630 |
+ ((rec_length + (info)->chunk_dataspace_length - 1) / \
|
|
631 |
+ (info)->chunk_dataspace_length)
|
|
632 |
||
633 |
typedef struct st_hp_hash_info |
|
634 |
{ |
|
635 |
@@ -90,7 +104,7 @@
|
|
636 |
const uchar *key); |
|
637 |
extern void hp_make_key(HP_KEYDEF *keydef,uchar *key,const uchar *rec); |
|
638 |
extern uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key, |
|
639 |
- const uchar *rec, uchar *recpos);
|
|
640 |
+ const uchar *rec, uchar *recpos, my_bool packed);
|
|
641 |
extern uint hp_rb_key_length(HP_KEYDEF *keydef, const uchar *key); |
|
642 |
extern uint hp_rb_null_key_length(HP_KEYDEF *keydef, const uchar *key); |
|
643 |
extern uint hp_rb_var_key_length(HP_KEYDEF *keydef, const uchar *key); |
|
644 |
@@ -100,6 +114,23 @@
|
|
645 |
extern void hp_clear_keys(HP_SHARE *info); |
|
646 |
extern uint hp_rb_pack_key(HP_KEYDEF *keydef, uchar *key, const uchar *old, |
|
647 |
key_part_map keypart_map); |
|
648 |
+extern uint hp_calc_blob_length(uint length, const uchar *pos);
|
|
649 |
+
|
|
650 |
+/* Chunkset management (alloc/free/encode/decode) functions */
|
|
651 |
+extern uchar *hp_allocate_chunkset(HP_DATASPACE *info, uint chunk_count);
|
|
652 |
+extern int hp_reallocate_chunkset(HP_DATASPACE *info, uint chunk_count,
|
|
653 |
+ uchar *pos);
|
|
654 |
+extern void hp_free_chunks(HP_DATASPACE *info, uchar *pos);
|
|
655 |
+extern void hp_clear_dataspace(HP_DATASPACE *info);
|
|
656 |
+
|
|
657 |
+extern uint hp_get_encoded_data_length(HP_SHARE *info, const uchar *record,
|
|
658 |
+ uint *chunk_count);
|
|
659 |
+extern void hp_copy_record_data_to_chunkset(HP_SHARE *info, const uchar *record,
|
|
660 |
+ uchar *pos);
|
|
661 |
+extern int hp_extract_record(HP_INFO *info, uchar *record, const uchar *pos);
|
|
662 |
+extern uint hp_process_record_data_to_chunkset(HP_SHARE *info,
|
|
663 |
+ const uchar *record, uchar *pos,
|
|
664 |
+ uint is_compare);
|
|
665 |
||
666 |
extern mysql_mutex_t THR_LOCK_heap; |
|
667 |
||
668 |
diff -ruN a/storage/heap/hp_clear.c b/storage/heap/hp_clear.c
|
|
669 |
--- a/storage/heap/hp_clear.c 2011-04-11 13:44:03.000000000 +0300
|
|
670 |
+++ b/storage/heap/hp_clear.c 2011-06-02 15:37:43.754916999 +0300
|
|
671 |
@@ -30,16 +30,11 @@
|
|
672 |
{ |
|
673 |
DBUG_ENTER("hp_clear"); |
|
674 |
||
675 |
- if (info->block.levels)
|
|
676 |
- (void) hp_free_level(&info->block,info->block.levels,info->block.root,
|
|
677 |
- (uchar*) 0);
|
|
678 |
- info->block.levels=0;
|
|
679 |
+ hp_clear_dataspace(&info->recordspace);
|
|
680 |
hp_clear_keys(info); |
|
681 |
- info->records= info->deleted= 0;
|
|
682 |
- info->data_length= 0;
|
|
683 |
+ info->records= 0;
|
|
684 |
info->blength=1; |
|
685 |
info->changed=0; |
|
686 |
- info->del_link=0;
|
|
687 |
DBUG_VOID_RETURN; |
|
688 |
} |
|
689 |
||
690 |
@@ -157,7 +152,7 @@
|
|
691 |
int error= 0; |
|
692 |
HP_SHARE *share= info->s; |
|
693 |
||
694 |
- if (share->data_length || share->index_length)
|
|
695 |
+ if (share->recordspace.total_data_length || share->index_length)
|
|
696 |
error= HA_ERR_CRASHED; |
|
697 |
else |
|
698 |
if (share->currently_disabled_keys) |
|
699 |
diff -ruN a/storage/heap/hp_close.c b/storage/heap/hp_close.c
|
|
700 |
--- a/storage/heap/hp_close.c 2011-04-11 13:44:03.000000000 +0300
|
|
701 |
+++ b/storage/heap/hp_close.c 2011-06-02 15:37:43.754916999 +0300
|
|
702 |
@@ -46,6 +46,10 @@
|
|
703 |
heap_open_list=list_delete(heap_open_list,&info->open_list); |
|
704 |
if (!--info->s->open_count && info->s->delete_on_close) |
|
705 |
hp_free(info->s); /* Table was deleted */ |
|
706 |
+ if (info->blob_buffer)
|
|
707 |
+ {
|
|
708 |
+ my_free(info->blob_buffer);
|
|
709 |
+ }
|
|
710 |
my_free(info); |
|
711 |
DBUG_RETURN(error); |
|
712 |
} |
|
713 |
diff -ruN a/storage/heap/hp_create.c b/storage/heap/hp_create.c
|
|
714 |
--- a/storage/heap/hp_create.c 2011-04-11 13:44:03.000000000 +0300
|
|
715 |
+++ b/storage/heap/hp_create.c 2011-06-02 15:37:43.754916999 +0300
|
|
716 |
@@ -14,11 +14,21 @@
|
|
717 |
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ |
|
718 |
||
719 |
#include "heapdef.h" |
|
720 |
+#include <mysql_com.h>
|
|
721 |
+#include <mysqld_error.h>
|
|
722 |
||
723 |
static int keys_compare(heap_rb_param *param, uchar *key1, uchar *key2); |
|
724 |
-static void init_block(HP_BLOCK *block,uint reclength,ulong min_records,
|
|
725 |
+static void init_block(HP_BLOCK *block,uint chunk_length, ulong min_records,
|
|
726 |
ulong max_records); |
|
727 |
||
728 |
+#define FIXED_REC_OVERHEAD (sizeof(uchar))
|
|
729 |
+#define VARIABLE_REC_OVERHEAD (sizeof(uchar **) + sizeof(uchar))
|
|
730 |
+
|
|
731 |
+/* Minimum size that a chunk can take, 12 bytes on 32bit, 24 bytes on 64bit */
|
|
732 |
+#define VARIABLE_MIN_CHUNK_SIZE \
|
|
733 |
+ ((sizeof(uchar **) + VARIABLE_REC_OVERHEAD + sizeof(uchar **) - 1) & \
|
|
734 |
+ ~(sizeof(uchar **) - 1))
|
|
735 |
+
|
|
736 |
/* Create a heap table */ |
|
737 |
||
738 |
int heap_create(const char *name, HP_CREATE_INFO *create_info, |
|
739 |
@@ -32,6 +42,7 @@
|
|
740 |
uint keys= create_info->keys; |
|
741 |
ulong min_records= create_info->min_records; |
|
742 |
ulong max_records= create_info->max_records; |
|
743 |
+ ulong max_rows_for_stated_memory;
|
|
744 |
DBUG_ENTER("heap_create"); |
|
745 |
||
746 |
if (!create_info->internal_table) |
|
747 |
@@ -48,15 +59,147 @@
|
|
748 |
||
749 |
if (!share) |
|
750 |
{ |
|
751 |
+ uint chunk_dataspace_length, chunk_length, is_variable_size;
|
|
752 |
+ uint fixed_data_length, fixed_column_count;
|
|
753 |
HP_KEYDEF *keyinfo; |
|
754 |
DBUG_PRINT("info",("Initializing new table")); |
|
755 |
-
|
|
756 |
+
|
|
757 |
+ if (create_info->max_chunk_size)
|
|
758 |
+ {
|
|
759 |
+ uint configured_chunk_size= create_info->max_chunk_size;
|
|
760 |
+
|
|
761 |
+ /* User requested variable-size records, let's see if they're possible */
|
|
762 |
+
|
|
763 |
+ if (configured_chunk_size < create_info->fixed_data_size)
|
|
764 |
+ {
|
|
765 |
+ /*
|
|
766 |
+ The resulting chunk_size cannot be smaller than fixed data part
|
|
767 |
+ at the start of the first chunk which allows faster copying
|
|
768 |
+ with a single memcpy().
|
|
769 |
+ */
|
|
770 |
+ my_error(ER_CANT_USE_OPTION_HERE, MYF(0), "key_block_size");
|
|
771 |
+ goto err;
|
|
772 |
+ }
|
|
773 |
+
|
|
774 |
+ if (reclength > configured_chunk_size + VARIABLE_REC_OVERHEAD ||
|
|
775 |
+ create_info->blobs > 0)
|
|
776 |
+ {
|
|
777 |
+ /*
|
|
778 |
+ Allow variable size only if we're saving some space, i.e.
|
|
779 |
+ if a fixed-size record would take more space than variable-size
|
|
780 |
+ one plus the variable-size overhead.
|
|
781 |
+ There has to be at least one field after indexed fields.
|
|
782 |
+ Note that NULL bits are already included in key_part_size.
|
|
783 |
+ */
|
|
784 |
+ is_variable_size= 1;
|
|
785 |
+ chunk_dataspace_length= configured_chunk_size;
|
|
786 |
+ }
|
|
787 |
+ else
|
|
788 |
+ {
|
|
789 |
+ /* max_chunk_size is near the full reclength, let's use fixed size */
|
|
790 |
+ is_variable_size= 0;
|
|
791 |
+ chunk_dataspace_length= reclength;
|
|
792 |
+ }
|
|
793 |
+ }
|
|
794 |
+ else if ((create_info->is_dynamic && reclength >
|
|
795 |
+ 256 + VARIABLE_REC_OVERHEAD)
|
|
796 |
+ || create_info->blobs > 0)
|
|
797 |
+ {
|
|
798 |
+ /*
|
|
799 |
+ User asked for dynamic records - use 256 as the chunk size, if that
|
|
800 |
+ will may save some memory. Otherwise revert to fixed size format.
|
|
801 |
+ */
|
|
802 |
+ if ((create_info->fixed_data_size + VARIABLE_REC_OVERHEAD) > 256)
|
|
803 |
+ chunk_dataspace_length= create_info->fixed_data_size;
|
|
804 |
+ else
|
|
805 |
+ chunk_dataspace_length= 256 - VARIABLE_REC_OVERHEAD;
|
|
806 |
+
|
|
807 |
+ is_variable_size= 1;
|
|
808 |
+ }
|
|
809 |
+ else
|
|
810 |
+ {
|
|
811 |
+ /*
|
|
812 |
+ If max_chunk_size is not specified, put the whole record in one chunk
|
|
813 |
+ */
|
|
814 |
+ is_variable_size= 0;
|
|
815 |
+ chunk_dataspace_length= reclength;
|
|
816 |
+ }
|
|
817 |
+
|
|
818 |
+ if (is_variable_size)
|
|
819 |
+ {
|
|
820 |
+ /* Check whether we have any variable size records past key data */
|
|
821 |
+ uint has_variable_fields= 0;
|
|
822 |
+
|
|
823 |
+ fixed_data_length= create_info->fixed_data_size;
|
|
824 |
+ fixed_column_count= create_info->fixed_key_fieldnr;
|
|
825 |
+
|
|
826 |
+ for (i= create_info->fixed_key_fieldnr; i < create_info->columns; i++)
|
|
827 |
+ {
|
|
828 |
+ HP_COLUMNDEF *column= create_info->columndef + i;
|
|
829 |
+ if ((column->type == MYSQL_TYPE_VARCHAR &&
|
|
830 |
+ (column->length - column->length_bytes) >= 32) ||
|
|
831 |
+ column->type == MYSQL_TYPE_BLOB)
|
|
832 |
+ {
|
|
833 |
+ /*
|
|
834 |
+ The field has to be either blob or >= 5.0.3 true VARCHAR
|
|
835 |
+ and have substantial length.
|
|
836 |
+ TODO: do we want to calculate minimum length?
|
|
837 |
+ */
|
|
838 |
+ has_variable_fields= 1;
|
|
839 |
+ break;
|
|
840 |
+ }
|
|
841 |
+
|
|
842 |
+ if (has_variable_fields)
|
|
843 |
+ {
|
|
844 |
+ break;
|
|
845 |
+ }
|
|
846 |
+
|
|
847 |
+ if ((column->offset + column->length) <= chunk_dataspace_length)
|
|
848 |
+ {
|
|
849 |
+ /* Still no variable-size columns, add one fixed-length */
|
|
850 |
+ fixed_column_count= i + 1;
|
|
851 |
+ fixed_data_length= column->offset + column->length;
|
|
852 |
+ }
|
|
853 |
+ }
|
|
854 |
+
|
|
855 |
+ if (!has_variable_fields && create_info->blobs == 0)
|
|
856 |
+ {
|
|
857 |
+ /*
|
|
858 |
+ There is no need to use variable-size records without variable-size
|
|
859 |
+ columns.
|
|
860 |
+ Reset sizes if it's not variable size anymore.
|
|
861 |
+ */
|
|
862 |
+ is_variable_size= 0;
|
|
863 |
+ chunk_dataspace_length= reclength;
|
|
864 |
+ fixed_data_length= reclength;
|
|
865 |
+ fixed_column_count= create_info->columns;
|
|
866 |
+ }
|
|
867 |
+ }
|
|
868 |
+ else
|
|
869 |
+ {
|
|
870 |
+ fixed_data_length= reclength;
|
|
871 |
+ fixed_column_count= create_info->columns;
|
|
872 |
+ }
|
|
873 |
+
|
|
874 |
/* |
|
875 |
- We have to store sometimes uchar* del_link in records,
|
|
876 |
- so the record length should be at least sizeof(uchar*)
|
|
877 |
+ We store uchar* del_link inside the data area of deleted records,
|
|
878 |
+ so the data length should be at least sizeof(uchar*)
|
|
879 |
*/ |
|
880 |
- set_if_bigger(reclength, sizeof (uchar*));
|
|
881 |
-
|
|
882 |
+ set_if_bigger(chunk_dataspace_length, sizeof (uchar **));
|
|
883 |
+
|
|
884 |
+ if (is_variable_size)
|
|
885 |
+ {
|
|
886 |
+ chunk_length= chunk_dataspace_length + VARIABLE_REC_OVERHEAD;
|
|
887 |
+ }
|
|
888 |
+ else
|
|
889 |
+ {
|
|
890 |
+ chunk_length= chunk_dataspace_length + FIXED_REC_OVERHEAD;
|
|
891 |
+ }
|
|
892 |
+
|
|
893 |
+ /* Align chunk length to the next pointer */
|
|
894 |
+ chunk_length= (uint) (chunk_length + sizeof(uchar **) - 1) &
|
|
895 |
+ ~(sizeof(uchar **) - 1);
|
|
896 |
+
|
|
897 |
for (i= key_segs= max_length= 0, keyinfo= keydef; i < keys; i++, keyinfo++) |
|
898 |
{ |
|
899 |
bzero((char*) &keyinfo->block,sizeof(keyinfo->block)); |
|
900 |
@@ -73,42 +216,11 @@
|
|
901 |
keyinfo->rb_tree.size_of_element++; |
|
902 |
} |
|
903 |
switch (keyinfo->seg[j].type) { |
|
904 |
- case HA_KEYTYPE_SHORT_INT:
|
|
905 |
- case HA_KEYTYPE_LONG_INT:
|
|
906 |
- case HA_KEYTYPE_FLOAT:
|
|
907 |
- case HA_KEYTYPE_DOUBLE:
|
|
908 |
- case HA_KEYTYPE_USHORT_INT:
|
|
909 |
- case HA_KEYTYPE_ULONG_INT:
|
|
910 |
- case HA_KEYTYPE_LONGLONG:
|
|
911 |
- case HA_KEYTYPE_ULONGLONG:
|
|
912 |
- case HA_KEYTYPE_INT24:
|
|
913 |
- case HA_KEYTYPE_UINT24:
|
|
914 |
- case HA_KEYTYPE_INT8:
|
|
915 |
- keyinfo->seg[j].flag|= HA_SWAP_KEY;
|
|
916 |
- break;
|
|
917 |
case HA_KEYTYPE_VARBINARY1: |
|
918 |
- /* Case-insensitiveness is handled in coll->hash_sort */
|
|
919 |
- keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
|
|
920 |
- /* fall_through */
|
|
921 |
case HA_KEYTYPE_VARTEXT1: |
|
922 |
- keyinfo->flag|= HA_VAR_LENGTH_KEY;
|
|
923 |
- length+= 2;
|
|
924 |
- /* Save number of bytes used to store length */
|
|
925 |
- keyinfo->seg[j].bit_start= 1;
|
|
926 |
- break;
|
|
927 |
case HA_KEYTYPE_VARBINARY2: |
|
928 |
- /* Case-insensitiveness is handled in coll->hash_sort */
|
|
929 |
- /* fall_through */
|
|
930 |
case HA_KEYTYPE_VARTEXT2: |
|
931 |
- keyinfo->flag|= HA_VAR_LENGTH_KEY;
|
|
932 |
length+= 2; |
|
933 |
- /* Save number of bytes used to store length */
|
|
934 |
- keyinfo->seg[j].bit_start= 2;
|
|
935 |
- /*
|
|
936 |
- Make future comparison simpler by only having to check for
|
|
937 |
- one type
|
|
938 |
- */
|
|
939 |
- keyinfo->seg[j].type= HA_KEYTYPE_VARTEXT1;
|
|
940 |
break; |
|
941 |
default: |
|
942 |
break; |
|
943 |
@@ -133,13 +245,34 @@
|
|
944 |
} |
|
945 |
if (!(share= (HP_SHARE*) my_malloc((uint) sizeof(HP_SHARE)+ |
|
946 |
keys*sizeof(HP_KEYDEF)+ |
|
947 |
+ (create_info->columns *
|
|
948 |
+ sizeof(HP_COLUMNDEF)) +
|
|
949 |
key_segs*sizeof(HA_KEYSEG), |
|
950 |
MYF(MY_ZEROFILL)))) |
|
951 |
goto err; |
|
952 |
- share->keydef= (HP_KEYDEF*) (share + 1);
|
|
953 |
+
|
|
954 |
+ /*
|
|
955 |
+ Max_records is used for estimating block sizes and for enforcement.
|
|
956 |
+ Calculate the very maximum number of rows (if everything was one chunk)
|
|
957 |
+ and then take either that value or configured max_records (pick smallest
|
|
958 |
+ one).
|
|
959 |
+ */
|
|
960 |
+ max_rows_for_stated_memory= (ha_rows) (create_info->max_table_size /
|
|
961 |
+ (create_info->keys_memory_size +
|
|
962 |
+ chunk_length));
|
|
963 |
+ max_records = ((max_records && max_records < max_rows_for_stated_memory) ?
|
|
964 |
+ max_records : max_rows_for_stated_memory);
|
|
965 |
+
|
|
966 |
+ share->column_defs= (HP_COLUMNDEF*) (share + 1);
|
|
967 |
+ memcpy(share->column_defs, create_info->columndef,
|
|
968 |
+ (size_t) (sizeof(create_info->columndef[0]) *
|
|
969 |
+ create_info->columns));
|
|
970 |
+
|
|
971 |
+ share->keydef= (HP_KEYDEF*) (share->column_defs + create_info->columns);
|
|
972 |
share->key_stat_version= 1; |
|
973 |
keyseg= (HA_KEYSEG*) (share->keydef + keys); |
|
974 |
- init_block(&share->block, reclength + 1, min_records, max_records);
|
|
975 |
+ init_block(&share->recordspace.block, chunk_length, min_records,
|
|
976 |
+ max_records);
|
|
977 |
/* Fix keys */ |
|
978 |
memcpy(share->keydef, keydef, (size_t) (sizeof(keydef[0]) * keys)); |
|
979 |
for (i= 0, keyinfo= share->keydef; i < keys; i++, keyinfo++) |
|
980 |
@@ -177,15 +310,35 @@
|
|
981 |
share->min_records= min_records; |
|
982 |
share->max_records= max_records; |
|
983 |
share->max_table_size= create_info->max_table_size; |
|
984 |
- share->data_length= share->index_length= 0;
|
|
985 |
- share->reclength= reclength;
|
|
986 |
+ share->index_length= 0;
|
|
987 |
share->blength= 1; |
|
988 |
share->keys= keys; |
|
989 |
share->max_key_length= max_length; |
|
990 |
+ share->column_count= create_info->columns;
|
|
991 |
share->changed= 0; |
|
992 |
share->auto_key= create_info->auto_key; |
|
993 |
share->auto_key_type= create_info->auto_key_type; |
|
994 |
share->auto_increment= create_info->auto_increment; |
|
995 |
+
|
|
996 |
+ share->fixed_data_length= fixed_data_length;
|
|
997 |
+ share->fixed_column_count= fixed_column_count;
|
|
998 |
+ share->blobs= create_info->blobs;
|
|
999 |
+
|
|
1000 |
+ share->recordspace.chunk_length= chunk_length;
|
|
1001 |
+ share->recordspace.chunk_dataspace_length= chunk_dataspace_length;
|
|
1002 |
+ share->recordspace.is_variable_size= is_variable_size;
|
|
1003 |
+ share->recordspace.total_data_length= 0;
|
|
1004 |
+
|
|
1005 |
+ if (is_variable_size) {
|
|
1006 |
+ share->recordspace.offset_link= chunk_dataspace_length;
|
|
1007 |
+ share->recordspace.offset_status= share->recordspace.offset_link +
|
|
1008 |
+ sizeof(uchar **);
|
|
1009 |
+ } else {
|
|
1010 |
+ /* Make it likely to fail if anyone uses this offset */
|
|
1011 |
+ share->recordspace.offset_link= 1 << 22;
|
|
1012 |
+ share->recordspace.offset_status= chunk_dataspace_length;
|
|
1013 |
+ }
|
|
1014 |
+
|
|
1015 |
/* Must be allocated separately for rename to work */ |
|
1016 |
if (!(share->name= my_strdup(name,MYF(0)))) |
|
1017 |
{ |
|
1018 |
@@ -227,7 +380,7 @@
|
|
1019 |
param->search_flag, not_used); |
|
1020 |
} |
|
1021 |
||
1022 |
-static void init_block(HP_BLOCK *block, uint reclength, ulong min_records,
|
|
1023 |
+static void init_block(HP_BLOCK *block, uint chunk_length, ulong min_records,
|
|
1024 |
ulong max_records) |
|
1025 |
{ |
|
1026 |
uint i,recbuffer,records_in_block; |
|
1027 |
@@ -235,7 +388,12 @@
|
|
1028 |
max_records= max(min_records,max_records); |
|
1029 |
if (!max_records) |
|
1030 |
max_records= 1000; /* As good as quess as anything */ |
|
1031 |
- recbuffer= (uint) (reclength + sizeof(uchar**) - 1) & ~(sizeof(uchar**) - 1);
|
|
1032 |
+ /*
|
|
1033 |
+ We want to start each chunk at 8 bytes boundary, round recbuffer to the
|
|
1034 |
+ next 8.
|
|
1035 |
+ */
|
|
1036 |
+ recbuffer= (uint) (chunk_length + sizeof(uchar**) - 1) &
|
|
1037 |
+ ~(sizeof(uchar**) - 1);
|
|
1038 |
records_in_block= max_records / 10; |
|
1039 |
if (records_in_block < 10 && max_records) |
|
1040 |
records_in_block= 10; |
|
1041 |
diff -ruN a/storage/heap/hp_delete.c b/storage/heap/hp_delete.c
|
|
1042 |
--- a/storage/heap/hp_delete.c 2011-04-11 13:44:03.000000000 +0300
|
|
1043 |
+++ b/storage/heap/hp_delete.c 2011-06-02 15:37:43.754916999 +0300
|
|
1044 |
@@ -22,6 +22,8 @@
|
|
1045 |
uchar *pos; |
|
1046 |
HP_SHARE *share=info->s; |
|
1047 |
HP_KEYDEF *keydef, *end, *p_lastinx; |
|
1048 |
+ uint rec_length, chunk_count;
|
|
1049 |
+
|
|
1050 |
DBUG_ENTER("heap_delete"); |
|
1051 |
DBUG_PRINT("enter",("info: 0x%lx record: 0x%lx", (long) info, (long) record)); |
|
1052 |
||
1053 |
@@ -31,6 +33,8 @@
|
|
1054 |
DBUG_RETURN(my_errno); /* Record changed */ |
|
1055 |
share->changed=1; |
|
1056 |
||
1057 |
+ rec_length = hp_get_encoded_data_length(share, record, &chunk_count);
|
|
1058 |
+
|
|
1059 |
if ( --(share->records) < share->blength >> 1) share->blength>>=1; |
|
1060 |
pos=info->current_ptr; |
|
1061 |
||
1062 |
@@ -43,10 +47,7 @@
|
|
1063 |
} |
|
1064 |
||
1065 |
info->update=HA_STATE_DELETED; |
|
1066 |
- *((uchar**) pos)=share->del_link;
|
|
1067 |
- share->del_link=pos;
|
|
1068 |
- pos[share->reclength]=0; /* Record deleted */
|
|
1069 |
- share->deleted++;
|
|
1070 |
+ hp_free_chunks(&share->recordspace, pos);
|
|
1071 |
info->current_hash_ptr=0; |
|
1072 |
#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG) |
|
1073 |
DBUG_EXECUTE("check_heap",heap_check_heap(info, 0);); |
|
1074 |
@@ -75,7 +76,8 @@
|
|
1075 |
info->last_pos= NULL; /* For heap_rnext/heap_rprev */ |
|
1076 |
||
1077 |
custom_arg.keyseg= keyinfo->seg; |
|
1078 |
- custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
|
|
1079 |
+ custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos,
|
|
1080 |
+ FALSE);
|
|
1081 |
custom_arg.search_flag= SEARCH_SAME; |
|
1082 |
old_allocated= keyinfo->rb_tree.allocated; |
|
1083 |
res= tree_delete(&keyinfo->rb_tree, info->recbuf, custom_arg.key_length, |
|
1084 |
@@ -112,6 +114,7 @@
|
|
1085 |
blength=share->blength; |
|
1086 |
if (share->records+1 == blength) |
|
1087 |
blength+= blength; |
|
1088 |
+
|
|
1089 |
lastpos=hp_find_hash(&keyinfo->block,share->records); |
|
1090 |
last_ptr=0; |
|
1091 |
||
1092 |
diff -ruN /dev/null b/storage/heap/hp_dspace.c
|
|
1093 |
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
1094 |
+++ b/storage/heap/hp_dspace.c 2011-06-02 15:40:14.104917001 +0300
|
|
1095 |
@@ -0,0 +1,440 @@
|
|
1096 |
+/* Copyright (C) 2000-2002 MySQL AB
|
|
1097 |
+ Copyright (C) 2008 eBay, Inc
|
|
1098 |
+
|
|
1099 |
+ This program is free software; you can redistribute it and/or modify
|
|
1100 |
+ it under the terms of the GNU General Public License as published by
|
|
1101 |
+ the Free Software Foundation; version 2 of the License.
|
|
1102 |
+
|
|
1103 |
+ This program is distributed in the hope that it will be useful,
|
|
1104 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
1105 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
1106 |
+ GNU General Public License for more details.
|
|
1107 |
+
|
|
1108 |
+ You should have received a copy of the GNU General Public License
|
|
1109 |
+ along with this program; if not, write to the Free Software
|
|
1110 |
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
1111 |
+
|
|
1112 |
+/*
|
|
1113 |
+ Implements various base dataspace-related functions - allocate, free, clear
|
|
1114 |
+*/
|
|
1115 |
+
|
|
1116 |
+#include "heapdef.h"
|
|
1117 |
+
|
|
1118 |
+
|
|
1119 |
+/*
|
|
1120 |
+ MySQL Heap tables keep data in arrays of fixed-size chunks.
|
|
1121 |
+ These chunks are organized into two groups of HP_BLOCK structures:
|
|
1122 |
+ - group1 contains indexes, with one HP_BLOCK per key
|
|
1123 |
+ (part of HP_KEYDEF)
|
|
1124 |
+ - group2 contains record data, with single HP_BLOCK
|
|
1125 |
+ for all records, referenced by HP_SHARE.recordspace.block
|
|
1126 |
+
|
|
1127 |
+ While columns used in index are usually small, other columns
|
|
1128 |
+ in the table may need to accomodate larger data. Typically,
|
|
1129 |
+ larger data is placed into VARCHAR or BLOB columns. With actual
|
|
1130 |
+ sizes varying, Heap Engine has to support variable-sized records
|
|
1131 |
+ in memory. Heap Engine implements the concept of dataspace
|
|
1132 |
+ (HP_DATASPACE), which incorporates HP_BLOCK for the record data,
|
|
1133 |
+ and adds more information for managing variable-sized records.
|
|
1134 |
+
|
|
1135 |
+ Variable-size records are stored in multiple "chunks",
|
|
1136 |
+ which means that a single record of data (database "row") can
|
|
1137 |
+ consist of multiple chunks organized into one "set". HP_BLOCK
|
|
1138 |
+ contains chunks. In variable-size format, one record
|
|
1139 |
+ is represented as one or many chunks, depending on the actual
|
|
1140 |
+ data, while in fixed-size mode, one record is always represented
|
|
1141 |
+ as one chunk. The index structures would always point to the first
|
|
1142 |
+ chunk in the chunkset.
|
|
1143 |
+
|
|
1144 |
+ At the time of table creation, Heap Engine attempts to find out if
|
|
1145 |
+ variable-size records are desired. A user can request
|
|
1146 |
+ variable-size records by providing either row_type=dynamic or
|
|
1147 |
+ key_block_size=NNN table create option. Heap Engine will check
|
|
1148 |
+ whether key_block_size provides enough space in the first chunk
|
|
1149 |
+ to keep all null bits and columns that are used in indexes.
|
|
1150 |
+ If key_block_size is too small, table creation will be aborted
|
|
1151 |
+ with an error. Heap Engine will revert to fixed-size allocation
|
|
1152 |
+ mode if key_block_size provides no memory benefits (if the
|
|
1153 |
+ fixed-size record would always be shorter then the first chunk
|
|
1154 |
+ in the chunkset with the specified key_block_size).
|
|
1155 |
+
|
|
1156 |
+ In order to improve index search performance, Heap Engine needs
|
|
1157 |
+ to keep all null flags and all columns used as keys inside
|
|
1158 |
+ the first chunk of a chunkset. In particular, this means that
|
|
1159 |
+ all columns used as keys should be defined first in the table
|
|
1160 |
+ creation SQL. The length of data used by null bits and key columns
|
|
1161 |
+ is stored as fixed_data_length inside HP_SHARE. fixed_data_length
|
|
1162 |
+ will extend past last key column if more fixed-length fields can
|
|
1163 |
+ fit into the first chunk.
|
|
1164 |
+
|
|
1165 |
+ Variable-size records are necessary only in the presence of
|
|
1166 |
+ variable-size columns. Heap Engine will be looking for BLOB
|
|
1167 |
+ columns or VARCHAR columns, which declare length of 32 or more. If
|
|
1168 |
+ no such columns are found, table will be switched to fixed-size
|
|
1169 |
+ format. You should always try to put such columns at the end of
|
|
1170 |
+ the table definition.
|
|
1171 |
+
|
|
1172 |
+ Whenever data is being inserted or updated in the table
|
|
1173 |
+ Heap Engine will calculate how many chunks are necessary.
|
|
1174 |
+ For insert operations, Heap Engine allocates new chunkset in
|
|
1175 |
+ the recordspace. For update operations it will modify length of
|
|
1176 |
+ the existing chunkset, unlinking unnecessary chunks at the end,
|
|
1177 |
+ or allocating and adding more if larger length is necessary.
|
|
1178 |
+
|
|
1179 |
+ When writing data to chunks or copying data back to record,
|
|
1180 |
+ fixed-size columns are copied in their full format. VARCHARs and
|
|
1181 |
+ BLOBs are copied based on their actual length. Any NULL values
|
|
1182 |
+ after fixed_data_length are skipped.
|
|
1183 |
+
|
|
1184 |
+ The allocation and contents of the actual chunks varies between
|
|
1185 |
+ fixed and variable-size modes. Total chunk length is always
|
|
1186 |
+ aligned to the next sizeof(uchar*). Here is the format of
|
|
1187 |
+ fixed-size chunk:
|
|
1188 |
+ uchar[] - sizeof=chunk_dataspace_length, but at least
|
|
1189 |
+ sizeof(uchar*) bytes. Keeps actual data or pointer
|
|
1190 |
+ to the next deleted chunk.
|
|
1191 |
+ chunk_dataspace_length equals to full record length
|
|
1192 |
+ uchar - status field (1 means "in use", 0 means "deleted")
|
|
1193 |
+
|
|
1194 |
+ Variable-size chunk uses different format:
|
|
1195 |
+ uchar[] - sizeof=chunk_dataspace_length, but at least
|
|
1196 |
+ sizeof(uchar*) bytes. Keeps actual data or pointer
|
|
1197 |
+ to the next deleted chunk.
|
|
1198 |
+ chunk_dataspace_length is set according to table
|
|
1199 |
+ setup (key_block_size)
|
|
1200 |
+ uchar* - pointer to the next chunk in this chunkset,
|
|
1201 |
+ or NULL for the last chunk
|
|
1202 |
+ uchar - status field (1 means "first", 0 means "deleted",
|
|
1203 |
+ 2 means "linked")
|
|
1204 |
+
|
|
1205 |
+ When allocating a new chunkset of N chunks, Heap Engine will try
|
|
1206 |
+ to allocate chunks one-by-one, linking them as they become
|
|
1207 |
+ allocated. Allocation of a single chunk will attempt to reuse
|
|
1208 |
+ a deleted (freed) chunk. If no free chunks are available,
|
|
1209 |
+ it will attempt to allocate a new area inside HP_BLOCK.
|
|
1210 |
+ Freeing chunks will place them at the front of free list
|
|
1211 |
+ referenced by del_link in HP_DATASPACE. The newly freed chunk
|
|
1212 |
+ will contain reference to the previously freed chunk in its first
|
|
1213 |
+ sizeof(uchar*) of the payload space.
|
|
1214 |
+
|
|
1215 |
+ Here is open issues:
|
|
1216 |
+ - It is not very nice to require people to keep key columns
|
|
1217 |
+ at the beginning of the table creation SQL. There are three
|
|
1218 |
+ proposed resolutions:
|
|
1219 |
+ a. Leave it as is. It's a reasonable limitation
|
|
1220 |
+ b. Add new HA_KEEP_KEY_COLUMNS_TO_FRONT flag to handler.h and
|
|
1221 |
+ make table.cpp align columns when it creates the table
|
|
1222 |
+ c. Make HeapEngine reorder columns in the chunk data, so that
|
|
1223 |
+ key columns go first. Add parallel HA_KEYSEG structures
|
|
1224 |
+ to distinguish positions in record vs. positions in
|
|
1225 |
+ the first chunk. Copy all data field-by-field rather than
|
|
1226 |
+ using single memcpy unless DBA kept key columns to
|
|
1227 |
+ the beginning.
|
|
1228 |
+ - heap_check_heap needs verify linked chunks, looking for
|
|
1229 |
+ issues such as orphans, cycles, and bad links. However,
|
|
1230 |
+ Heap Engine today does not do similar things even for
|
|
1231 |
+ free list.
|
|
1232 |
+ - In a more sophisticated implementation, some space can
|
|
1233 |
+ be saved even with all fixed-size columns if many of them
|
|
1234 |
+ have NULL value, as long as these columns are not used
|
|
1235 |
+ in indexes
|
|
1236 |
+ - In variable-size format status should be moved to lower
|
|
1237 |
+ bits of the "next" pointer. Pointer is always aligned
|
|
1238 |
+ to sizeof(byte*), which is at least 4, leaving 2 lower
|
|
1239 |
+ bits free. This will save 8 bytes per chunk
|
|
1240 |
+ on 64-bit platform.
|
|
1241 |
+ - As we do not want to modify FRM format or to add new SQL
|
|
1242 |
+ keywords, KEY_BLOCK_SIZE option of "CREATE TABLE" is reused
|
|
1243 |
+ to specify block size for Heap Engine tables.
|
|
1244 |
+ - since all key columns must fit in the first chunk, having keys
|
|
1245 |
+ on BLOB columns is currently impossible. This limitation is
|
|
1246 |
+ relatively easiy to remove in future.
|
|
1247 |
+*/
|
|
1248 |
+
|
|
1249 |
+static uchar *hp_allocate_one_chunk(HP_DATASPACE *info);
|
|
1250 |
+
|
|
1251 |
+
|
|
1252 |
+/**
|
|
1253 |
+ Clear a dataspace
|
|
1254 |
+
|
|
1255 |
+ Frees memory and zeros-out any relevant counters in the dataspace
|
|
1256 |
+
|
|
1257 |
+ @param info the dataspace to clear
|
|
1258 |
+*/
|
|
1259 |
+
|
|
1260 |
+void hp_clear_dataspace(HP_DATASPACE *info)
|
|
1261 |
+{
|
|
1262 |
+ if (info->block.levels)
|
|
1263 |
+ {
|
|
1264 |
+ hp_free_level(&info->block,info->block.levels,info->block.root,
|
|
1265 |
+ (uchar *) 0);
|
|
1266 |
+ }
|
|
1267 |
+ info->block.levels= 0;
|
|
1268 |
+ info->del_chunk_count= info->chunk_count= 0;
|
|
1269 |
+ info->del_link= 0;
|
|
1270 |
+ info->total_data_length= 0;
|
|
1271 |
+}
|
|
1272 |
+
|
|
1273 |
+
|
|
1274 |
+/**
|
|
1275 |
+ Allocate or reallocate a chunkset in the dataspace
|
|
1276 |
+
|
|
1277 |
+ Attempts to allocate a new chunkset or change the size of an existing chunkset
|
|
1278 |
+
|
|
1279 |
+ @param info the hosting dataspace
|
|
1280 |
+ @param chunk_count the number of chunks that we expect as the result
|
|
1281 |
+ @param existing_set non-null value asks function to resize existing
|
|
1282 |
+ chunkset, return value would point to this set
|
|
1283 |
+
|
|
1284 |
+ @return Pointer to the first chunk in the new or updated chunkset, or NULL
|
|
1285 |
+ if unsuccessful
|
|
1286 |
+*/
|
|
1287 |
+
|
|
1288 |
+static uchar *hp_allocate_variable_chunkset(HP_DATASPACE *info,
|
|
1289 |
+ uint chunk_count,
|
|
1290 |
+ uchar *existing_set)
|
|
1291 |
+{
|
|
1292 |
+ int alloc_count= chunk_count, i;
|
|
1293 |
+ uchar *first_chunk= 0, *curr_chunk= 0, *prev_chunk= 0;
|
|
1294 |
+ uchar *last_existing_chunk= 0;
|
|
1295 |
+
|
|
1296 |
+ DBUG_ASSERT(alloc_count);
|
|
1297 |
+
|
|
1298 |
+ if (existing_set)
|
|
1299 |
+ {
|
|
1300 |
+ first_chunk= existing_set;
|
|
1301 |
+
|
|
1302 |
+ curr_chunk= existing_set;
|
|
1303 |
+ while (curr_chunk && alloc_count)
|
|
1304 |
+ {
|
|
1305 |
+ prev_chunk= curr_chunk;
|
|
1306 |
+ curr_chunk= *((uchar **) (curr_chunk + info->offset_link));
|
|
1307 |
+ alloc_count--;
|
|
1308 |
+ }
|
|
1309 |
+
|
|
1310 |
+ if (!alloc_count)
|
|
1311 |
+ {
|
|
1312 |
+ if (curr_chunk)
|
|
1313 |
+ {
|
|
1314 |
+ /*
|
|
1315 |
+ We came through all chunks and there is more left, let's truncate the
|
|
1316 |
+ list.
|
|
1317 |
+ */
|
|
1318 |
+ *((uchar **) (prev_chunk + info->offset_link))= NULL;
|
|
1319 |
+ hp_free_chunks(info, curr_chunk);
|
|
1320 |
+ }
|
|
1321 |
+
|
|
1322 |
+ return first_chunk;
|
|
1323 |
+ }
|
|
1324 |
+
|
|
1325 |
+ last_existing_chunk= prev_chunk;
|
|
1326 |
+ }
|
|
1327 |
+
|
|
1328 |
+ /*
|
|
1329 |
+ We can reach this point only if we're allocating new chunkset or more chunks
|
|
1330 |
+ in existing set.
|
|
1331 |
+ */
|
|
1332 |
+
|
|
1333 |
+ for (i= 0; i < alloc_count; i++)
|
|
1334 |
+ {
|
|
1335 |
+ curr_chunk= hp_allocate_one_chunk(info);
|
|
1336 |
+ if (!curr_chunk)
|
|
1337 |
+ {
|
|
1338 |
+ /* no space in the current block */
|
|
1339 |
+
|
|
1340 |
+ if (last_existing_chunk)
|
|
1341 |
+ {
|
|
1342 |
+ /* Truncate whatever was added at the end of the existing chunkset */
|
|
1343 |
+ prev_chunk= last_existing_chunk;
|
|
1344 |
+ curr_chunk= *((uchar **)(prev_chunk + info->offset_link));
|
|
1345 |
+ *((uchar **)(prev_chunk + info->offset_link))= NULL;
|
|
1346 |
+ hp_free_chunks(info, curr_chunk);
|
|
1347 |
+ }
|
|
1348 |
+ else if (first_chunk)
|
|
1349 |
+ {
|
|
1350 |
+ /* free any chunks previously allocated */
|
|
1351 |
+ hp_free_chunks(info, first_chunk);
|
|
1352 |
+ }
|
|
1353 |
+
|
|
1354 |
+ return NULL;
|
|
1355 |
+ }
|
|
1356 |
+
|
|
1357 |
+ /* mark as if this chunk is last in the chunkset */
|
|
1358 |
+ *((uchar **) (curr_chunk + info->offset_link))= 0;
|
|
1359 |
+
|
|
1360 |
+ if (prev_chunk)
|
|
1361 |
+ {
|
|
1362 |
+ /* tie them into a linked list */
|
|
1363 |
+ *((uchar **) (prev_chunk + info->offset_link))= curr_chunk;
|
|
1364 |
+ /* Record linked from active */
|
|
1365 |
+ curr_chunk[info->offset_status]= CHUNK_STATUS_LINKED;
|
|
1366 |
+ }
|
|
1367 |
+ else
|
|
1368 |
+ {
|
|
1369 |
+ /* Record active */
|
|
1370 |
+ curr_chunk[info->offset_status]= CHUNK_STATUS_ACTIVE;
|
|
1371 |
+ }
|
|
1372 |
+
|
|
1373 |
+ if (!first_chunk)
|
|
1374 |
+ {
|
|
1375 |
+ first_chunk= curr_chunk;
|
|
1376 |
+ }
|
|
1377 |
+
|
|
1378 |
+ prev_chunk= curr_chunk;
|
|
1379 |
+}
|
|
1380 |
+
|
|
1381 |
+ return first_chunk;
|
|
1382 |
+}
|
|
1383 |
+
|
|
1384 |
+
|
|
1385 |
+/**
|
|
1386 |
+ Allocate a new chunkset in the dataspace
|
|
1387 |
+
|
|
1388 |
+ Attempts to allocate a new chunkset
|
|
1389 |
+
|
|
1390 |
+ @param info the hosting dataspace
|
|
1391 |
+ @param chunk_count the number of chunks that we expect as the result
|
|
1392 |
+
|
|
1393 |
+ @return Pointer to the first chunk in the new or updated chunkset, or NULL if
|
|
1394 |
+ unsuccessful
|
|
1395 |
+*/
|
|
1396 |
+
|
|
1397 |
+uchar *hp_allocate_chunkset(HP_DATASPACE *info, uint chunk_count)
|
|
1398 |
+{
|
|
1399 |
+ uchar *result;
|
|
1400 |
+
|
|
1401 |
+ DBUG_ENTER("hp_allocate_chunks");
|
|
1402 |
+
|
|
1403 |
+ if (info->is_variable_size)
|
|
1404 |
+ {
|
|
1405 |
+ result = hp_allocate_variable_chunkset(info, chunk_count, NULL);
|
|
1406 |
+ }
|
|
1407 |
+ else
|
|
1408 |
+ {
|
|
1409 |
+ result= hp_allocate_one_chunk(info);
|
|
1410 |
+ if (result)
|
|
1411 |
+ {
|
|
1412 |
+ result[info->offset_status]= CHUNK_STATUS_ACTIVE;
|
|
1413 |
+ }
|
|
1414 |
+
|
|
1415 |
+ DBUG_RETURN(result);
|
|
1416 |
+ }
|
|
1417 |
+
|
|
1418 |
+ DBUG_RETURN(result);
|
|
1419 |
+}
|
|
1420 |
+
|
|
1421 |
+
|
|
1422 |
+/**
|
|
1423 |
+ Reallocate an existing chunkset in the dataspace
|
|
1424 |
+
|
|
1425 |
+ Attempts to change the size of an existing chunkset
|
|
1426 |
+
|
|
1427 |
+ @param info the hosting dataspace
|
|
1428 |
+ @param chunk_count the number of chunks that we expect as the result
|
|
1429 |
+ @param pos pointer to the existing chunkset
|
|
1430 |
+
|
|
1431 |
+ @return Error code or zero if successful
|
|
1432 |
+*/
|
|
1433 |
+
|
|
1434 |
+int hp_reallocate_chunkset(HP_DATASPACE *info, uint chunk_count, uchar *pos)
|
|
1435 |
+{
|
|
1436 |
+ DBUG_ENTER("hp_reallocate_chunks");
|
|
1437 |
+
|
|
1438 |
+ if (!info->is_variable_size)
|
|
1439 |
+ {
|
|
1440 |
+ /* Update should never change chunk_count in fixed-size mode */
|
|
1441 |
+ my_errno= HA_ERR_WRONG_COMMAND;
|
|
1442 |
+ return my_errno;
|
|
1443 |
+ }
|
|
1444 |
+
|
|
1445 |
+ /* Reallocate never moves the first chunk */
|
|
1446 |
+ if (!hp_allocate_variable_chunkset(info, chunk_count, pos))
|
|
1447 |
+ DBUG_RETURN(my_errno);
|
|
1448 |
+
|
|
1449 |
+ DBUG_RETURN(0);
|
|
1450 |
+}
|
|
1451 |
+
|
|
1452 |
+
|
|
1453 |
+/**
|
|
1454 |
+ Allocate a single chunk in the dataspace
|
|
1455 |
+
|
|
1456 |
+ Attempts to allocate a new chunk or reuse one from deleted list
|
|
1457 |
+
|
|
1458 |
+ @param info the hosting dataspace
|
|
1459 |
+
|
|
1460 |
+ @return Pointer to the chunk, or NULL if unsuccessful
|
|
1461 |
+*/
|
|
1462 |
+
|
|
1463 |
+static uchar *hp_allocate_one_chunk(HP_DATASPACE *info)
|
|
1464 |
+{
|
|
1465 |
+ uchar *curr_chunk;
|
|
1466 |
+ size_t length;
|
|
1467 |
+ ulong block_pos;
|
|
1468 |
+
|
|
1469 |
+ if (info->del_link)
|
|
1470 |
+ {
|
|
1471 |
+ curr_chunk= info->del_link;
|
|
1472 |
+ info->del_link= *((uchar **) curr_chunk);
|
|
1473 |
+ info->del_chunk_count--;
|
|
1474 |
+
|
|
1475 |
+ DBUG_PRINT("hp_allocate_one_chunk",
|
|
1476 |
+ ("Used old position: 0x%lx",(long) curr_chunk));
|
|
1477 |
+ return curr_chunk;
|
|
1478 |
+ }
|
|
1479 |
+
|
|
1480 |
+ block_pos= (info->chunk_count % info->block.records_in_block);
|
|
1481 |
+ if (!block_pos)
|
|
1482 |
+ {
|
|
1483 |
+ if (hp_get_new_block(&info->block, &length))
|
|
1484 |
+ {
|
|
1485 |
+ /* no space in the current block */
|
|
1486 |
+ return NULL;
|
|
1487 |
+ }
|
|
1488 |
+
|
|
1489 |
+ info->total_data_length+= length;
|
|
1490 |
+ }
|
|
1491 |
+
|
|
1492 |
+ info->chunk_count++;
|
|
1493 |
+ curr_chunk= ((uchar *) info->block.level_info[0].last_blocks +
|
|
1494 |
+ block_pos * info->block.recbuffer);
|
|
1495 |
+
|
|
1496 |
+ DBUG_PRINT("hp_allocate_one_chunk",
|
|
1497 |
+ ("Used new position: 0x%lx", (long) curr_chunk));
|
|
1498 |
+
|
|
1499 |
+ return curr_chunk;
|
|
1500 |
+}
|
|
1501 |
+
|
|
1502 |
+
|
|
1503 |
+/**
|
|
1504 |
+ Free a list of chunks
|
|
1505 |
+
|
|
1506 |
+ Reclaims all chunks linked by the pointer,
|
|
1507 |
+ which could be the whole chunkset or a part of an existing chunkset
|
|
1508 |
+
|
|
1509 |
+ @param info the hosting dataspace
|
|
1510 |
+ @param pos pointer to the head of the chunkset
|
|
1511 |
+*/
|
|
1512 |
+
|
|
1513 |
+void hp_free_chunks(HP_DATASPACE *info, uchar *pos)
|
|
1514 |
+{
|
|
1515 |
+ uchar *curr_chunk= pos;
|
|
1516 |
+
|
|
1517 |
+ while (curr_chunk)
|
|
1518 |
+ {
|
|
1519 |
+ info->del_chunk_count++;
|
|
1520 |
+ *((uchar **) curr_chunk)= info->del_link;
|
|
1521 |
+ info->del_link= curr_chunk;
|
|
1522 |
+
|
|
1523 |
+ curr_chunk[info->offset_status]= CHUNK_STATUS_DELETED;
|
|
1524 |
+
|
|
1525 |
+ DBUG_PRINT("hp_free_chunks",("Freed position: 0x%lx", (long) curr_chunk));
|
|
1526 |
+
|
|
1527 |
+ if (!info->is_variable_size)
|
|
1528 |
+ {
|
|
1529 |
+ break;
|
|
1530 |
+ }
|
|
1531 |
+
|
|
1532 |
+ /* Delete next chunk in this chunkset */
|
|
1533 |
+ curr_chunk= *((uchar **)(curr_chunk + info->offset_link));
|
|
1534 |
+ }
|
|
1535 |
+}
|
|
1536 |
diff -ruN a/storage/heap/hp_extra.c b/storage/heap/hp_extra.c
|
|
1537 |
--- a/storage/heap/hp_extra.c 2011-04-11 13:44:03.000000000 +0300
|
|
1538 |
+++ b/storage/heap/hp_extra.c 2011-06-02 15:37:57.814917006 +0300
|
|
1539 |
@@ -56,7 +56,6 @@
|
|
1540 |
info->current_record= (ulong) ~0L; |
|
1541 |
info->current_hash_ptr=0; |
|
1542 |
info->update=0; |
|
1543 |
- info->next_block=0;
|
|
1544 |
return 0; |
|
1545 |
} |
|
1546 |
||
1547 |
diff -ruN a/storage/heap/hp_hash.c b/storage/heap/hp_hash.c
|
|
1548 |
--- a/storage/heap/hp_hash.c 2011-04-11 13:44:03.000000000 +0300
|
|
1549 |
+++ b/storage/heap/hp_hash.c 2011-06-02 15:37:57.824916999 +0300
|
|
1550 |
@@ -336,16 +336,26 @@
|
|
1551 |
{ |
|
1552 |
CHARSET_INFO *cs= seg->charset; |
|
1553 |
uint pack_length= seg->bit_start; |
|
1554 |
- uint length= (pack_length == 1 ? (uint) *(uchar*) pos : uint2korr(pos));
|
|
1555 |
+ uint length= hp_calc_blob_length(pack_length, pos);
|
|
1556 |
+
|
|
1557 |
+ if (seg->flag & HA_BLOB_PART)
|
|
1558 |
+ {
|
|
1559 |
+ memcpy(&pos, pos + pack_length, sizeof(char *));
|
|
1560 |
+ }
|
|
1561 |
+ else
|
|
1562 |
+ {
|
|
1563 |
+ pos+= pack_length;
|
|
1564 |
+ }
|
|
1565 |
+
|
|
1566 |
if (cs->mbmaxlen > 1) |
|
1567 |
{ |
|
1568 |
uint char_length; |
|
1569 |
- char_length= my_charpos(cs, pos + pack_length,
|
|
1570 |
- pos + pack_length + length,
|
|
1571 |
+ char_length= my_charpos(cs, pos,
|
|
1572 |
+ pos + length,
|
|
1573 |
seg->length/cs->mbmaxlen); |
|
1574 |
set_if_smaller(length, char_length); |
|
1575 |
} |
|
1576 |
- cs->coll->hash_sort(cs, pos+pack_length, length, &nr, &nr2);
|
|
1577 |
+ cs->coll->hash_sort(cs, pos, length, &nr, &nr2);
|
|
1578 |
} |
|
1579 |
else |
|
1580 |
{ |
|
1581 |
@@ -545,18 +555,18 @@
|
|
1582 |
uint char_length1, char_length2; |
|
1583 |
uint pack_length= seg->bit_start; |
|
1584 |
CHARSET_INFO *cs= seg->charset; |
|
1585 |
- if (pack_length == 1)
|
|
1586 |
- {
|
|
1587 |
- char_length1= (uint) *(uchar*) pos1++;
|
|
1588 |
- char_length2= (uint) *(uchar*) pos2++;
|
|
1589 |
- }
|
|
1590 |
- else
|
|
1591 |
+
|
|
1592 |
+ char_length1= hp_calc_blob_length(pack_length, pos1);
|
|
1593 |
+ char_length2= hp_calc_blob_length(pack_length, pos2);
|
|
1594 |
+ pos1+= pack_length;
|
|
1595 |
+ pos2+= pack_length;
|
|
1596 |
+
|
|
1597 |
+ if (seg->flag & HA_BLOB_PART)
|
|
1598 |
{ |
|
1599 |
- char_length1= uint2korr(pos1);
|
|
1600 |
- char_length2= uint2korr(pos2);
|
|
1601 |
- pos1+= 2;
|
|
1602 |
- pos2+= 2;
|
|
1603 |
+ memcpy(&pos1, pos1, sizeof(char *));
|
|
1604 |
+ memcpy(&pos2, pos2, sizeof(char *));
|
|
1605 |
} |
|
1606 |
+
|
|
1607 |
if (cs->mbmaxlen > 1) |
|
1608 |
{ |
|
1609 |
uint safe_length1= char_length1; |
|
1610 |
@@ -668,6 +678,34 @@
|
|
1611 |
} |
|
1612 |
||
1613 |
||
1614 |
+/**
|
|
1615 |
+ Returns a BLOB length stored in the specified number of bytes at the
|
|
1616 |
+ specified location.
|
|
1617 |
+
|
|
1618 |
+ @param length the number of bytes used to store length
|
|
1619 |
+ @param pos pointer to length bytes
|
|
1620 |
+
|
|
1621 |
+ @return Length of BLOB data.
|
|
1622 |
+*/
|
|
1623 |
+
|
|
1624 |
+uint hp_calc_blob_length(uint bytes, const uchar *pos)
|
|
1625 |
+{
|
|
1626 |
+ switch (bytes) {
|
|
1627 |
+ case 1:
|
|
1628 |
+ return (uint) *pos;
|
|
1629 |
+ case 2:
|
|
1630 |
+ return uint2korr(pos);
|
|
1631 |
+ case 3:
|
|
1632 |
+ return uint3korr(pos);
|
|
1633 |
+ case 4:
|
|
1634 |
+ return uint4korr(pos);
|
|
1635 |
+ default:
|
|
1636 |
+ break;
|
|
1637 |
+ }
|
|
1638 |
+
|
|
1639 |
+ return 0; /* Impossible */
|
|
1640 |
+}
|
|
1641 |
+
|
|
1642 |
/* Copy a key from a record to a keybuffer */ |
|
1643 |
||
1644 |
void hp_make_key(HP_KEYDEF *keydef, uchar *key, const uchar *rec) |
|
1645 |
@@ -678,18 +716,37 @@
|
|
1646 |
{ |
|
1647 |
CHARSET_INFO *cs= seg->charset; |
|
1648 |
uint char_length= seg->length; |
|
1649 |
- uchar *pos= (uchar*) rec + seg->start;
|
|
1650 |
+ const uchar *pos= rec + seg->start;
|
|
1651 |
if (seg->null_bit) |
|
1652 |
*key++= test(rec[seg->null_pos] & seg->null_bit); |
|
1653 |
- if (cs->mbmaxlen > 1)
|
|
1654 |
+
|
|
1655 |
+ if (seg->flag & HA_BLOB_PART)
|
|
1656 |
{ |
|
1657 |
- char_length= my_charpos(cs, pos, pos + seg->length,
|
|
1658 |
- char_length / cs->mbmaxlen);
|
|
1659 |
- set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
|
|
1660 |
- }
|
|
1661 |
- if (seg->type == HA_KEYTYPE_VARTEXT1)
|
|
1662 |
- char_length+= seg->bit_start; /* Copy also length */
|
|
1663 |
- memcpy(key,rec+seg->start,(size_t) char_length);
|
|
1664 |
+ uint tmp_length= hp_calc_blob_length(seg->bit_start, pos);
|
|
1665 |
+ uint length= min(seg->length, tmp_length);
|
|
1666 |
+
|
|
1667 |
+ memcpy(&pos, rec + seg->bit_start, sizeof(char *));
|
|
1668 |
+ if (cs->mbmaxlen > 1)
|
|
1669 |
+ {
|
|
1670 |
+ char_length= my_charpos(cs, pos, pos + seg->length,
|
|
1671 |
+ char_length / cs->mbmaxlen);
|
|
1672 |
+ set_if_smaller(char_length, length); /* QQ: ok to remove? */
|
|
1673 |
+ }
|
|
1674 |
+ store_key_length_inc(key, char_length);
|
|
1675 |
+ }
|
|
1676 |
+ else
|
|
1677 |
+ {
|
|
1678 |
+ if (cs->mbmaxlen > 1)
|
|
1679 |
+ {
|
|
1680 |
+ char_length= my_charpos(cs, pos, pos + seg->length,
|
|
1681 |
+ char_length / cs->mbmaxlen);
|
|
1682 |
+ set_if_smaller(char_length, seg->length); /* QQ: ok to remove? */
|
|
1683 |
+ }
|
|
1684 |
+ if (seg->type == HA_KEYTYPE_VARTEXT1)
|
|
1685 |
+ char_length+= seg->bit_start; /* Copy also length */
|
|
1686 |
+ }
|
|
1687 |
+
|
|
1688 |
+ memcpy(key, pos, (size_t) char_length);
|
|
1689 |
key+= char_length; |
|
1690 |
} |
|
1691 |
} |
|
1692 |
@@ -702,8 +759,8 @@
|
|
1693 |
} while(0) |
|
1694 |
||
1695 |
||
1696 |
-uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key,
|
|
1697 |
- const uchar *rec, uchar *recpos)
|
|
1698 |
+uint hp_rb_make_key(HP_KEYDEF *keydef, uchar *key,
|
|
1699 |
+ const uchar *rec, uchar *recpos, my_bool packed)
|
|
1700 |
{ |
|
1701 |
uchar *start_key= key; |
|
1702 |
HA_KEYSEG *seg, *endseg; |
|
1703 |
@@ -772,6 +829,29 @@
|
|
1704 |
key+= char_length; |
|
1705 |
continue; |
|
1706 |
} |
|
1707 |
+ else if (seg->flag & HA_BLOB_PART)
|
|
1708 |
+ {
|
|
1709 |
+ uchar *pos= (uchar*) rec + seg->start;
|
|
1710 |
+ uint tmp_length= hp_calc_blob_length(seg->bit_start, pos);
|
|
1711 |
+ uint length= min(seg->length, tmp_length);
|
|
1712 |
+ CHARSET_INFO *cs= seg->charset;
|
|
1713 |
+ char_length= seg->length / cs->mbmaxlen;
|
|
1714 |
+
|
|
1715 |
+ /* check_one_rb_key() calls hp_rb_make_key() for already packed records */
|
|
1716 |
+ if (!packed)
|
|
1717 |
+ {
|
|
1718 |
+ memcpy(&pos, pos + seg->bit_start, sizeof(char *));
|
|
1719 |
+ }
|
|
1720 |
+ else
|
|
1721 |
+ {
|
|
1722 |
+ pos+= seg->bit_start;
|
|
1723 |
+ }
|
|
1724 |
+ FIX_LENGTH(cs, pos, length, char_length);
|
|
1725 |
+ store_key_length_inc(key, char_length);
|
|
1726 |
+ memcpy(key, pos, (size_t) char_length);
|
|
1727 |
+ key+= char_length;
|
|
1728 |
+ continue;
|
|
1729 |
+ }
|
|
1730 |
||
1731 |
char_length= seg->length; |
|
1732 |
if (seg->charset->mbmaxlen > 1) |
|
1733 |
diff -ruN a/storage/heap/hp_info.c b/storage/heap/hp_info.c
|
|
1734 |
--- a/storage/heap/hp_info.c 2011-04-11 13:44:03.000000000 +0300
|
|
1735 |
+++ b/storage/heap/hp_info.c 2011-06-02 15:37:57.824916999 +0300
|
|
1736 |
@@ -47,9 +47,22 @@
|
|
1737 |
{ |
|
1738 |
DBUG_ENTER("heap_info"); |
|
1739 |
x->records = info->s->records; |
|
1740 |
- x->deleted = info->s->deleted;
|
|
1741 |
- x->reclength = info->s->reclength;
|
|
1742 |
- x->data_length = info->s->data_length;
|
|
1743 |
+ x->deleted = info->s->recordspace.del_chunk_count;
|
|
1744 |
+
|
|
1745 |
+ if (info->s->recordspace.is_variable_size)
|
|
1746 |
+ {
|
|
1747 |
+ if (info->s->records)
|
|
1748 |
+ x->reclength = (uint) (info->s->recordspace.total_data_length /
|
|
1749 |
+ (ulonglong) info->s->records);
|
|
1750 |
+ else
|
|
1751 |
+ x->reclength = info->s->recordspace.chunk_length;
|
|
1752 |
+ }
|
|
1753 |
+ else
|
|
1754 |
+ {
|
|
1755 |
+ x->reclength = info->s->recordspace.chunk_dataspace_length;
|
|
1756 |
+ }
|
|
1757 |
+
|
|
1758 |
+ x->data_length = info->s->recordspace.total_data_length;
|
|
1759 |
x->index_length = info->s->index_length; |
|
1760 |
x->max_records = info->s->max_records; |
|
1761 |
x->errkey = info->errkey; |
|
1762 |
diff -ruN a/storage/heap/hp_open.c b/storage/heap/hp_open.c
|
|
1763 |
--- a/storage/heap/hp_open.c 2011-04-11 13:44:03.000000000 +0300
|
|
1764 |
+++ b/storage/heap/hp_open.c 2011-06-02 15:37:57.824916999 +0300
|
|
1765 |
@@ -47,9 +47,9 @@
|
|
1766 |
#ifndef DBUG_OFF |
|
1767 |
info->opt_flag= READ_CHECK_USED; /* Check when changing */ |
|
1768 |
#endif |
|
1769 |
- DBUG_PRINT("exit",("heap: 0x%lx reclength: %d records_in_block: %d",
|
|
1770 |
- (long) info, share->reclength,
|
|
1771 |
- share->block.records_in_block));
|
|
1772 |
+ DBUG_PRINT("exit",("heap: 0x%lx chunk_length: %d records_in_block: %d",
|
|
1773 |
+ (long) info, share->recordspace.chunk_length,
|
|
1774 |
+ share->recordspace.block.records_in_block));
|
|
1775 |
DBUG_RETURN(info); |
|
1776 |
} |
|
1777 |
||
1778 |
diff -ruN /dev/null b/storage/heap/hp_record.c
|
|
1779 |
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
|
|
1780 |
+++ b/storage/heap/hp_record.c 2011-06-02 15:40:21.634916999 +0300
|
|
1781 |
@@ -0,0 +1,498 @@
|
|
1782 |
+/* Copyright (C) 2000-2002 MySQL AB
|
|
1783 |
+ Copyright (C) 2008 eBay, Inc
|
|
1784 |
+
|
|
1785 |
+ This program is free software; you can redistribute it and/or modify
|
|
1786 |
+ it under the terms of the GNU General Public License as published by
|
|
1787 |
+ the Free Software Foundation; version 2 of the License.
|
|
1788 |
+
|
|
1789 |
+ This program is distributed in the hope that it will be useful,
|
|
1790 |
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
1791 |
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
1792 |
+ GNU General Public License for more details.
|
|
1793 |
+
|
|
1794 |
+ You should have received a copy of the GNU General Public License
|
|
1795 |
+ along with this program; if not, write to the Free Software
|
|
1796 |
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
|
1797 |
+
|
|
1798 |
+/*
|
|
1799 |
+ Implements various base record-related functions, such as encode and decode
|
|
1800 |
+ into chunks.
|
|
1801 |
+*/
|
|
1802 |
+
|
|
1803 |
+#include "heapdef.h"
|
|
1804 |
+#include <mysql_com.h>
|
|
1805 |
+
|
|
1806 |
+/**
|
|
1807 |
+ Calculate size of the record for the purpose of storing in chunks
|
|
1808 |
+
|
|
1809 |
+ Walk through the fields of the record and calculates the exact space
|
|
1810 |
+ needed in chunks as well the the total chunk count
|
|
1811 |
+
|
|
1812 |
+ @param info the hosting table
|
|
1813 |
+ @param record the record in standard unpacked format
|
|
1814 |
+ @param[out] chunk_count the number of chunks needed for this record
|
|
1815 |
+
|
|
1816 |
+ @return The size of the required storage in bytes
|
|
1817 |
+*/
|
|
1818 |
+
|
|
1819 |
+uint hp_get_encoded_data_length(HP_SHARE *info, const uchar *record,
|
|
1820 |
+ uint *chunk_count)
|
|
1821 |
+{
|
|
1822 |
+ uint i, dst_offset;
|
|
1823 |
+
|
|
1824 |
+ dst_offset= info->fixed_data_length;
|
|
1825 |
+
|
|
1826 |
+ if (!info->recordspace.is_variable_size)
|
|
1827 |
+ {
|
|
1828 |
+ /* Nothing more to copy */
|
|
1829 |
+ *chunk_count= 1;
|
|
1830 |
+ return dst_offset;
|
|
1831 |
+ }
|
|
1832 |
+
|
|
1833 |
+ for (i= info->fixed_column_count; i < info->column_count; i++)
|
|
1834 |
+ {
|
|
1835 |
+ uint src_offset, length;
|
|
1836 |
+
|
|
1837 |
+ HP_COLUMNDEF *column= info->column_defs + i;
|
|
1838 |
+
|
|
1839 |
+ if (column->null_bit)
|
|
1840 |
+ {
|
|
1841 |
+ if (record[column->null_pos] & column->null_bit)
|
|
1842 |
+ {
|
|
1843 |
+ /* Skip all NULL values */
|
|
1844 |
+ continue;
|
|
1845 |
+ }
|
|
1846 |
+ }
|
|
1847 |
+
|
|
1848 |
+ src_offset= column->offset;
|
|
1849 |
+ if (column->type == MYSQL_TYPE_VARCHAR)
|
|
1850 |
+ {
|
|
1851 |
+ uint pack_length;
|
|
1852 |
+
|
|
1853 |
+ /* >= 5.0.3 true VARCHAR */
|
|
1854 |
+
|
|
1855 |
+ pack_length= column->length_bytes;
|
|
1856 |
+ length= pack_length + (pack_length == 1 ?
|
|
1857 |
+ (uint) *(uchar *) (record + src_offset) :
|
|
1858 |
+ uint2korr(record + src_offset));
|
|
1859 |
+ }
|
|
1860 |
+ else if (column->type == MYSQL_TYPE_BLOB)
|
|
1861 |
+ {
|
|
1862 |
+ uint pack_length= column->length_bytes;
|
|
1863 |
+
|
|
1864 |
+ length= pack_length + hp_calc_blob_length(pack_length,
|
|
1865 |
+ record + src_offset);
|
|
1866 |
+ }
|
|
1867 |
+ else
|
|
1868 |
+ {
|
|
1869 |
+ length= column->length;
|
|
1870 |
+ }
|
|
1871 |
+
|
|
1872 |
+ dst_offset+= length;
|
|
1873 |
+ }
|
|
1874 |
+
|
|
1875 |
+ *chunk_count= get_chunk_count(&info->recordspace, dst_offset);
|
|
1876 |
+
|
|
1877 |
+ return dst_offset;
|
|
1878 |
+}
|
|
1879 |
+
|
|
1880 |
+
|
|
1881 |
+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
|
|
1882 |
+static void dump_chunk(HP_SHARE *info, const uchar *curr_chunk)
|
|
1883 |
+{
|
|
1884 |
+ uint i;
|
|
1885 |
+ fprintf(stdout, "Chunk dump at 0x%lx: ", (long) curr_chunk);
|
|
1886 |
+ for (i= 0; i < info->recordspace.chunk_dataspace_length; i++)
|
|
1887 |
+ {
|
|
1888 |
+ uint b= *((uchar *)(curr_chunk + i));
|
|
1889 |
+ if (b < 0x10)
|
|
1890 |
+ {
|
|
1891 |
+ fprintf(stdout, "0");
|
|
1892 |
+ }
|
|
1893 |
+ fprintf(stdout, "%lx ", (long) b);
|
|
1894 |
+ }
|
|
1895 |
+ fprintf(stdout, ". Next = 0x%lx, Status = %d\n",
|
|
1896 |
+ (long) (*((uchar **) (curr_chunk + info->recordspace.offset_link))),
|
|
1897 |
+ (uint) (*((uchar *) (curr_chunk + info->recordspace.offset_status))));
|
|
1898 |
+}
|
|
1899 |
+#endif
|
|
1900 |
+
|
|
1901 |
+/**
|
|
1902 |
+ Stores data from packed field into the preallocated chunkset,
|
|
1903 |
+ or performs data comparison
|
|
1904 |
+
|
|
1905 |
+ @param info the hosting table
|
|
1906 |
+ @param data the field data in packed format
|
|
1907 |
+ @param length the field data length
|
|
1908 |
+ @param pos_ptr the target chunkset
|
|
1909 |
+ @param off_ptr the pointer to the offset within the current chunkset
|
|
1910 |
+ @param is_compare flag indicating whether we should compare data or store
|
|
1911 |
+ it
|
|
1912 |
+
|
|
1913 |
+ @return Status of comparison
|
|
1914 |
+ @retval non-zero if comparison found data differences
|
|
1915 |
+ @retval zero otherwise
|
|
1916 |
+*/
|
|
1917 |
+
|
|
1918 |
+static inline uint
|
|
1919 |
+hp_process_field_data_to_chunkset(HP_SHARE *info, const uchar *data,
|
|
1920 |
+ uint length, uchar **pos_ptr, uint *off_ptr,
|
|
1921 |
+ uint is_compare)
|
|
1922 |
+{
|
|
1923 |
+ uint to_copy;
|
|
1924 |
+ uchar *curr_chunk= *pos_ptr;
|
|
1925 |
+ uint dst_offset= *off_ptr;
|
|
1926 |
+ uint rc= 1;
|
|
1927 |
+
|
|
1928 |
+ while (length > 0)
|
|
1929 |
+ {
|
|
1930 |
+
|
|
1931 |
+ to_copy= info->recordspace.chunk_dataspace_length - dst_offset;
|
|
1932 |
+ if (to_copy == 0)
|
|
1933 |
+ {
|
|
1934 |
+ /* Jump to the next chunk */
|
|
1935 |
+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
|
|
1936 |
+ dump_chunk(info, curr_chunk);
|
|
1937 |
+#endif
|
|
1938 |
+ curr_chunk= *((uchar **) (curr_chunk + info->recordspace.offset_link));
|
|
1939 |
+ dst_offset= 0;
|
|
1940 |
+ continue;
|
|
1941 |
+ }
|
|
1942 |
+
|
|
1943 |
+ to_copy= min(length, to_copy);
|
|
1944 |
+
|
|
1945 |
+ if (is_compare)
|
|
1946 |
+ {
|
|
1947 |
+ if (memcmp(curr_chunk + dst_offset, data, (size_t) to_copy))
|
|
1948 |
+ {
|
|
1949 |
+ goto end;
|
|
1950 |
+ }
|
|
1951 |
+ }
|
|
1952 |
+ else
|
|
1953 |
+ {
|
|
1954 |
+ memcpy(curr_chunk + dst_offset, data, (size_t) to_copy);
|
|
1955 |
+ }
|
|
1956 |
+
|
|
1957 |
+ data+= to_copy;
|
|
1958 |
+ dst_offset+= to_copy;
|
|
1959 |
+ length-= to_copy;
|
|
1960 |
+ }
|
|
1961 |
+
|
|
1962 |
+ rc= 0;
|
|
1963 |
+
|
|
1964 |
+end:
|
|
1965 |
+ *pos_ptr= curr_chunk;
|
|
1966 |
+ *off_ptr= dst_offset;
|
|
1967 |
+
|
|
1968 |
+ return rc;
|
|
1969 |
+}
|
|
1970 |
+
|
|
1971 |
+/**
|
|
1972 |
+ Encodes or compares record
|
|
1973 |
+
|
|
1974 |
+ Copies data from original unpacked record into the preallocated chunkset,
|
|
1975 |
+ or performs data comparison
|
|
1976 |
+
|
|
1977 |
+ @param info the hosting table
|
|
1978 |
+ @param record the record in standard unpacked format
|
|
1979 |
+ @param pos the target chunkset
|
|
1980 |
+ @param is_compare flag indicating whether we should compare data or store
|
|
1981 |
+ it
|
|
1982 |
+
|
|
1983 |
+ @return Status of comparison
|
|
1984 |
+ @retval non-zero if comparison fond data differences
|
|
1985 |
+ @retval zero otherwise
|
|
1986 |
+*/
|
|
1987 |
+
|
|
1988 |
+uint hp_process_record_data_to_chunkset(HP_SHARE *info, const uchar *record,
|
|
1989 |
+ uchar *pos, uint is_compare)
|
|
1990 |
+{
|
|
1991 |
+ uint i, dst_offset;
|
|
1992 |
+ uchar *curr_chunk= pos;
|
|
1993 |
+
|
|
1994 |
+ if (is_compare)
|
|
1995 |
+ {
|
|
1996 |
+ if (memcmp(curr_chunk, record, (size_t) info->fixed_data_length))
|
|
1997 |
+ {
|
|
1998 |
+ return 1;
|
|
1999 |
+ }
|
|
2000 |
+ }
|
|
2001 |
+ else
|
|
2002 |
+ {
|
|
2003 |
+ memcpy(curr_chunk, record, (size_t) info->fixed_data_length);
|
|
2004 |
+ }
|
|
2005 |
+
|
|
2006 |
+ if (!info->recordspace.is_variable_size)
|
|
2007 |
+ {
|
|
2008 |
+ /* Nothing more to copy */
|
|
2009 |
+ return 0;
|
|
2010 |
+ }
|
|
2011 |
+
|
|
2012 |
+ dst_offset= info->fixed_data_length;
|
|
2013 |
+
|
|
2014 |
+ for (i= info->fixed_column_count; i < info->column_count; i++)
|
|
2015 |
+ {
|
|
2016 |
+ uint length;
|
|
2017 |
+ const uchar *data;
|
|
2018 |
+
|
|
2019 |
+ HP_COLUMNDEF *column= info->column_defs + i;
|
|
2020 |
+
|
|
2021 |
+ if (column->null_bit)
|
|
2022 |
+ {
|
|
2023 |
+ if (record[column->null_pos] & column->null_bit)
|
|
2024 |
+ {
|
|
2025 |
+ /* Skip all NULL values */
|
|
2026 |
+ continue;
|
|
2027 |
+ }
|
|
2028 |
+ }
|
|
2029 |
+
|
|
2030 |
+ data= record + column->offset;
|
|
2031 |
+ if (column->type == MYSQL_TYPE_VARCHAR)
|
|
2032 |
+ {
|
|
2033 |
+ uint pack_length;
|
|
2034 |
+
|
|
2035 |
+ /* >= 5.0.3 true VARCHAR */
|
|
2036 |
+
|
|
2037 |
+ /* Make sure to copy length indicator and actuals string bytes */
|
|
2038 |
+ pack_length= column->length_bytes;
|
|
2039 |
+ length= pack_length + (pack_length == 1 ? (uint) *data : uint2korr(data));
|
|
2040 |
+ }
|
|
2041 |
+ else if (column->type == MYSQL_TYPE_BLOB)
|
|
2042 |
+ {
|
|
2043 |
+ uint pack_length;
|
|
2044 |
+
|
|
2045 |
+ pack_length= column->length_bytes;
|
|
2046 |
+ /* Just want to store the length, so not interested in the return code */
|
|
2047 |
+ (void) hp_process_field_data_to_chunkset(info, data, pack_length,
|
|
2048 |
+ &curr_chunk, &dst_offset, 0);
|
|
2049 |
+ length= hp_calc_blob_length(pack_length, data);
|
|
2050 |
+ memcpy(&data, data + pack_length, sizeof(char *));
|
|
2051 |
+ }
|
|
2052 |
+ else
|
|
2053 |
+ {
|
|
2054 |
+ length= column->length;
|
|
2055 |
+ }
|
|
2056 |
+
|
|
2057 |
+ if (hp_process_field_data_to_chunkset(info, data, length, &curr_chunk,
|
|
2058 |
+ &dst_offset, is_compare))
|
|
2059 |
+ {
|
|
2060 |
+ return 1;
|
|
2061 |
+ }
|
|
2062 |
+ }
|
|
2063 |
+
|
|
2064 |
+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
|
|
2065 |
+ dump_chunk(info, curr_chunk);
|
|
2066 |
+#endif
|
|
2067 |
+
|
|
2068 |
+ return 0;
|
|
2069 |
+}
|
|
2070 |
+
|
|
2071 |
+
|
|
2072 |
+/**
|
|
2073 |
+ Stores record in the heap table chunks
|
|
2074 |
+
|
|
2075 |
+ Copies data from original unpacked record into the preallocated chunkset
|
|
2076 |
+
|
|
2077 |
+ @param info the hosting table
|
|
2078 |
+ @param record the record in standard unpacked format
|
|
2079 |
+ @param pos the target chunkset
|
|
2080 |
+*/
|
|
2081 |
+
|
|
2082 |
+void hp_copy_record_data_to_chunkset(HP_SHARE *info, const uchar *record,
|
|
2083 |
+ uchar *pos)
|
|
2084 |
+{
|
|
2085 |
+ DBUG_ENTER("hp_copy_record_data_to_chunks");
|
|
2086 |
+
|
|
2087 |
+ hp_process_record_data_to_chunkset(info, record, pos, 0);
|
|
2088 |
+
|
|
2089 |
+ DBUG_VOID_RETURN;
|
|
2090 |
+}
|
|
2091 |
+
|
|
2092 |
+
|
|
2093 |
+/*
|
|
2094 |
+ Macro to switch curr_chunk to the next chunk in the chunkset and reset
|
|
2095 |
+ src_offset.
|
|
2096 |
+*/
|
|
2097 |
+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
|
|
2098 |
+#define SWITCH_TO_NEXT_CHUNK_FOR_READ(share, curr_chunk, src_offset) \
|
|
2099 |
+ { \
|
|
2100 |
+ curr_chunk= *((uchar**) (curr_chunk + share->recordspace.offset_link)); \
|
|
2101 |
+ src_offset= 0; \
|
|
2102 |
+ dump_chunk(share, curr_chunk); \
|
|
2103 |
+ }
|
|
2104 |
+#else
|
|
2105 |
+#define SWITCH_TO_NEXT_CHUNK_FOR_READ(share, curr_chunk, src_offset) \
|
|
2106 |
+ { \
|
|
2107 |
+ curr_chunk= *((uchar**) (curr_chunk + share->recordspace.offset_link)); \
|
|
2108 |
+ src_offset= 0; \
|
|
2109 |
+ }
|
|
2110 |
+#endif
|
|
2111 |
+
|
|
2112 |
+/**
|
|
2113 |
+ Copies record data from storage to unpacked record format
|
|
2114 |
+
|
|
2115 |
+ Copies data from chunkset into its original unpacked record
|
|
2116 |
+
|
|
2117 |
+ @param info the hosting table
|
|
2118 |
+ @param[out] record the target record in standard unpacked format
|
|
2119 |
+ @param pos the source chunkset
|
|
2120 |
+
|
|
2121 |
+ @return Status of conversion
|
|
2122 |
+ @retval 0 success
|
|
2123 |
+ @retval 1 out of memory
|
|
2124 |
+*/
|
|
2125 |
+
|
|
2126 |
+int hp_extract_record(HP_INFO *info, uchar *record, const uchar *pos)
|
|
2127 |
+{
|
|
2128 |
+ uint i, src_offset;
|
|
2129 |
+ const uchar *curr_chunk= pos;
|
|
2130 |
+ HP_SHARE *share= info->s;
|
|
2131 |
+ uint *rec_offsets;
|
|
2132 |
+ uint *buf_offsets;
|
|
2133 |
+ uint nblobs= 0;
|
|
2134 |
+ uint init_offset= share->blobs * sizeof(uint) * 2;
|
|
2135 |
+
|
|
2136 |
+ DBUG_ENTER("hp_extract_record");
|
|
2137 |
+
|
|
2138 |
+#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG)
|
|
2139 |
+ if (share->recordspace.is_variable_size)
|
|
2140 |
+ {
|
|
2141 |
+ dump_chunk(share, curr_chunk);
|
|
2142 |
+ }
|
|
2143 |
+#endif
|
|
2144 |
+
|
|
2145 |
+ memcpy(record, curr_chunk, (size_t) share->fixed_data_length);
|
|
2146 |
+
|
|
2147 |
+ if (!share->recordspace.is_variable_size)
|
|
2148 |
+ {
|
|
2149 |
+ /* Nothing more to copy */
|
|
2150 |
+ DBUG_RETURN(0);
|
|
2151 |
+ }
|
|
2152 |
+
|
|
2153 |
+ /* Reserve space for rec_offsets and buf_offsets.*/
|
|
2154 |
+ info->blob_offset= init_offset;
|
|
2155 |
+ src_offset= share->fixed_data_length;
|
|
2156 |
+
|
|
2157 |
+ for (i= share->fixed_column_count; i < share->column_count; i++)
|
|
2158 |
+ {
|
|
2159 |
+ uint length, is_null= 0;
|
|
2160 |
+ uchar *to;
|
|
2161 |
+
|
|
2162 |
+ HP_COLUMNDEF *column= share->column_defs + i;
|
|
2163 |
+
|
|
2164 |
+ if (column->null_bit)
|
|
2165 |
+ {
|
|
2166 |
+ if (record[column->null_pos] & column->null_bit)
|
|
2167 |
+ {
|
|
2168 |
+ is_null= 1;
|
|
2169 |
+ }
|
|
2170 |
+ }
|
|
2171 |
+
|
|
2172 |
+ if (is_null)
|
|
2173 |
+ {
|
|
2174 |
+ /* TODO: is memset really needed? */
|
|
2175 |
+ memset(record + column->offset, 0, column->length);
|
|
2176 |
+ continue;
|
|
2177 |
+ }
|
|
2178 |
+
|
|
2179 |
+ to= record + column->offset;
|
|
2180 |
+ if (column->type == MYSQL_TYPE_VARCHAR || column->type == MYSQL_TYPE_BLOB)
|
|
2181 |
+ {
|
|
2182 |
+ uint pack_length, i;
|
|
2183 |
+ uchar *tmp= to;
|
|
2184 |
+
|
|
2185 |
+ pack_length= column->length_bytes;
|
|
2186 |
+
|
|
2187 |
+ for (i= 0; i < pack_length; i++)
|
|
2188 |
+ {
|
|
2189 |
+ if (src_offset == share->recordspace.chunk_dataspace_length)
|
|
2190 |
+ {
|
|
2191 |
+ SWITCH_TO_NEXT_CHUNK_FOR_READ(share, curr_chunk, src_offset);
|
|
2192 |
+ }
|
|
2193 |
+ *to++= curr_chunk[src_offset++];
|
|
2194 |
+ }
|
|
2195 |
+ /*
|
|
2196 |
+ We copy byte-by-byte and then use hp_calc_blob_length to combine bytes
|
|
2197 |
+ in the right order.
|
|
2198 |
+ */
|
|
2199 |
+ length= hp_calc_blob_length(pack_length, tmp);
|
|
2200 |
+
|
|
2201 |
+ if (column->type == MYSQL_TYPE_BLOB && length == 0)
|
|
2202 |
+ {
|
|
2203 |
+ /*
|
|
2204 |
+ Store a zero pointer for zero-length BLOBs because the server
|
|
2205 |
+ relies on that (see Field_blob::val_*().
|
|
2206 |
+ */
|
|
2207 |
+ *(uchar **) to= 0;
|
|
2208 |
+ }
|
|
2209 |
+ else if (column->type == MYSQL_TYPE_BLOB && length > 0)
|
|
2210 |
+ {
|
|
2211 |
+ uint newsize= info->blob_offset + length;
|
|
2212 |
+
|
|
2213 |
+ DBUG_ASSERT(share->blobs > 0);
|
|
2214 |
+ /*
|
|
2215 |
+ Make sure we have enough space in blob_buffer and store the pointer
|
|
2216 |
+ to this blob in record.
|
|
2217 |
+ */
|
|
2218 |
+ if (info->blob_size < newsize)
|
|
2219 |
+ {
|
|
2220 |
+ uchar *ptr;
|
|
2221 |
+ ptr= my_realloc(info->blob_buffer, newsize, MYF(MY_ALLOW_ZERO_PTR));
|
|
2222 |
+ if (ptr == NULL)
|
|
2223 |
+ {
|
|
2224 |
+ DBUG_RETURN(1);
|
|
2225 |
+ }
|
|
2226 |
+
|
|
2227 |
+ if (info->blob_buffer == NULL)
|
|
2228 |
+ {
|
|
2229 |
+ memset(ptr, 0, init_offset);
|
|
2230 |
+ }
|
|
2231 |
+ info->blob_buffer= ptr;
|
|
2232 |
+ info->blob_size= newsize;
|
|
2233 |
+ }
|
|
2234 |
+
|
|
2235 |
+ rec_offsets= (uint *) info->blob_buffer;
|
|
2236 |
+ buf_offsets= rec_offsets + share->blobs;
|
|
2237 |
+
|
|
2238 |
+ rec_offsets[nblobs]= (uint) (to - record);
|
|
2239 |
+ buf_offsets[nblobs]= info->blob_offset;
|
|
2240 |
+ nblobs++;
|
|
2241 |
+
|
|
2242 |
+ /* Change 'to' so blob data is copied into blob_buffer */
|
|
2243 |
+ to= info->blob_buffer + info->blob_offset;
|
|
2244 |
+ info->blob_offset= newsize;
|
|
2245 |
+ }
|
|
2246 |
+ }
|
|
2247 |
+ else
|
|
2248 |
+ {
|
|
2249 |
+ length= column->length;
|
|
2250 |
+ }
|
|
2251 |
+
|
|
2252 |
+ while (length > 0)
|
|
2253 |
+ {
|
|
2254 |
+ uint to_copy;
|
|
2255 |
+
|
|
2256 |
+ to_copy= share->recordspace.chunk_dataspace_length - src_offset;
|
|
2257 |
+ if (to_copy == 0)
|
|
2258 |
+ {
|
|
2259 |
+ SWITCH_TO_NEXT_CHUNK_FOR_READ(share, curr_chunk, src_offset);
|
|
2260 |
+ to_copy= share->recordspace.chunk_dataspace_length;
|
|
2261 |
+ }
|
|
2262 |
+
|
|
2263 |
+ to_copy= min(length, to_copy);
|
|
2264 |
+
|
|
2265 |
+ memcpy(to, curr_chunk + src_offset, (size_t) to_copy);
|
|
2266 |
+ src_offset+= to_copy;
|
|
2267 |
+ to+= to_copy;
|
|
2268 |
+ length-= to_copy;
|
|
2269 |
+ }
|
|
2270 |
+ }
|
|
2271 |
+
|
|
2272 |
+ /* Store pointers to blob data in record */
|
|
2273 |
+ for (i= 0; i < nblobs; i++)
|
|
2274 |
+ {
|
|
2275 |
+ *(uchar **) (record + rec_offsets[i]) = info->blob_buffer + buf_offsets[i];
|
|
2276 |
+ }
|
|
2277 |
+
|
|
2278 |
+ DBUG_RETURN(0);
|
|
2279 |
+}
|
|
2280 |
diff -ruN a/storage/heap/hp_rfirst.c b/storage/heap/hp_rfirst.c
|
|
2281 |
--- a/storage/heap/hp_rfirst.c 2011-04-11 13:44:03.000000000 +0300
|
|
2282 |
+++ b/storage/heap/hp_rfirst.c 2011-06-02 15:38:02.764917001 +0300
|
|
2283 |
@@ -34,7 +34,10 @@
|
|
2284 |
memcpy(&pos, pos + (*keyinfo->get_key_length)(keyinfo, pos), |
|
2285 |
sizeof(uchar*)); |
|
2286 |
info->current_ptr = pos; |
|
2287 |
- memcpy(record, pos, (size_t)share->reclength);
|
|
2288 |
+ if (hp_extract_record(info, record, pos))
|
|
2289 |
+ {
|
|
2290 |
+ DBUG_RETURN(my_errno);
|
|
2291 |
+ }
|
|
2292 |
/* |
|
2293 |
If we're performing index_first on a table that was taken from |
|
2294 |
table cache, info->lastkey_len is initialized to previous query. |
|
2295 |
diff -ruN a/storage/heap/hp_rkey.c b/storage/heap/hp_rkey.c
|
|
2296 |
--- a/storage/heap/hp_rkey.c 2011-04-11 13:44:03.000000000 +0300
|
|
2297 |
+++ b/storage/heap/hp_rkey.c 2011-06-02 15:38:02.764917001 +0300
|
|
2298 |
@@ -66,7 +66,10 @@
|
|
2299 |
if (!(keyinfo->flag & HA_NOSAME)) |
|
2300 |
memcpy(info->lastkey, key, (size_t) keyinfo->length); |
|
2301 |
} |
|
2302 |
- memcpy(record, pos, (size_t) share->reclength);
|
|
2303 |
+ if (hp_extract_record(info, record, pos))
|
|
2304 |
+ {
|
|
2305 |
+ DBUG_RETURN(my_errno);
|
|
2306 |
+ }
|
|
2307 |
info->update= HA_STATE_AKTIV; |
|
2308 |
DBUG_RETURN(0); |
|
2309 |
} |
|
2310 |
diff -ruN a/storage/heap/hp_rlast.c b/storage/heap/hp_rlast.c
|
|
2311 |
--- a/storage/heap/hp_rlast.c 2011-04-11 13:44:03.000000000 +0300
|
|
2312 |
+++ b/storage/heap/hp_rlast.c 2011-06-02 15:38:02.764917001 +0300
|
|
2313 |
@@ -35,7 +35,10 @@
|
|
2314 |
memcpy(&pos, pos + (*keyinfo->get_key_length)(keyinfo, pos), |
|
2315 |
sizeof(uchar*)); |
|
2316 |
info->current_ptr = pos; |
|
2317 |
- memcpy(record, pos, (size_t)share->reclength);
|
|
2318 |
+ if (hp_extract_record(info, record, pos))
|
|
2319 |
+ {
|
|
2320 |
+ DBUG_RETURN(my_errno);
|
|
2321 |
+ }
|
|
2322 |
info->update = HA_STATE_AKTIV; |
|
2323 |
} |
|
2324 |
else |
|
2325 |
diff -ruN a/storage/heap/hp_rnext.c b/storage/heap/hp_rnext.c
|
|
2326 |
--- a/storage/heap/hp_rnext.c 2011-04-11 13:44:03.000000000 +0300
|
|
2327 |
+++ b/storage/heap/hp_rnext.c 2011-06-02 15:38:02.764917001 +0300
|
|
2328 |
@@ -109,7 +109,10 @@
|
|
2329 |
my_errno=HA_ERR_END_OF_FILE; |
|
2330 |
DBUG_RETURN(my_errno); |
|
2331 |
} |
|
2332 |
- memcpy(record,pos,(size_t) share->reclength);
|
|
2333 |
+ if (hp_extract_record(info, record, pos))
|
|
2334 |
+ {
|
|
2335 |
+ DBUG_RETURN(my_errno);
|
|
2336 |
+ }
|
|
2337 |
info->update=HA_STATE_AKTIV | HA_STATE_NEXT_FOUND; |
|
2338 |
DBUG_RETURN(0); |
|
2339 |
} |
|
2340 |
diff -ruN a/storage/heap/hp_rprev.c b/storage/heap/hp_rprev.c
|
|
2341 |
--- a/storage/heap/hp_rprev.c 2011-04-11 13:44:03.000000000 +0300
|
|
2342 |
+++ b/storage/heap/hp_rprev.c 2011-06-02 15:38:02.764917001 +0300
|
|
2343 |
@@ -77,7 +77,10 @@
|
|
2344 |
my_errno=HA_ERR_END_OF_FILE; |
|
2345 |
DBUG_RETURN(my_errno); |
|
2346 |
} |
|
2347 |
- memcpy(record,pos,(size_t) share->reclength);
|
|
2348 |
+ if (hp_extract_record(info, record, pos))
|
|
2349 |
+ {
|
|
2350 |
+ DBUG_RETURN(my_errno);
|
|
2351 |
+ }
|
|
2352 |
info->update=HA_STATE_AKTIV | HA_STATE_PREV_FOUND; |
|
2353 |
DBUG_RETURN(0); |
|
2354 |
} |
|
2355 |
diff -ruN a/storage/heap/hp_rrnd.c b/storage/heap/hp_rrnd.c
|
|
2356 |
--- a/storage/heap/hp_rrnd.c 2011-04-11 13:44:03.000000000 +0300
|
|
2357 |
+++ b/storage/heap/hp_rrnd.c 2011-06-02 15:38:02.764917001 +0300
|
|
2358 |
@@ -36,13 +36,18 @@
|
|
2359 |
info->update= 0; |
|
2360 |
DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE); |
|
2361 |
} |
|
2362 |
- if (!info->current_ptr[share->reclength])
|
|
2363 |
+ if (get_chunk_status(&share->recordspace, info->current_ptr) !=
|
|
2364 |
+ CHUNK_STATUS_ACTIVE)
|
|
2365 |
{ |
|
2366 |
+ /* treat deleted and linked chunks as deleted */
|
|
2367 |
info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND; |
|
2368 |
DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED); |
|
2369 |
} |
|
2370 |
info->update=HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV; |
|
2371 |
- memcpy(record,info->current_ptr,(size_t) share->reclength);
|
|
2372 |
+ if (hp_extract_record(info, record, info->current_ptr))
|
|
2373 |
+ {
|
|
2374 |
+ DBUG_RETURN(my_errno);
|
|
2375 |
+ }
|
|
2376 |
DBUG_PRINT("exit", ("found record at 0x%lx", (long) info->current_ptr)); |
|
2377 |
info->current_hash_ptr=0; /* Can't use rnext */ |
|
2378 |
DBUG_RETURN(0); |
|
2379 |
@@ -70,17 +75,17 @@
|
|
2380 |
{ |
|
2381 |
pos= ++info->current_record; |
|
2382 |
if (pos % share->block.records_in_block && /* Quick next record */ |
|
2383 |
- pos < share->records+share->deleted &&
|
|
2384 |
- (info->update & HA_STATE_PREV_FOUND))
|
|
2385 |
+ pos < share->used_chunk_count + share->deleted_chunk_count &&
|
|
2386 |
+ (info->update & HA_STATE_PREV_FOUND))
|
|
2387 |
{ |
|
2388 |
- info->current_ptr+=share->block.recbuffer;
|
|
2389 |
+ info->current_ptr+= share->block.recbufferlen;
|
|
2390 |
goto end; |
|
2391 |
} |
|
2392 |
} |
|
2393 |
else |
|
2394 |
info->current_record=pos; |
|
2395 |
||
2396 |
- if (pos >= share->records+share->deleted)
|
|
2397 |
+ if (pos >= share->used_chunk_count + share->deleted_chunk_count)
|
|
2398 |
{ |
|
2399 |
info->update= 0; |
|
2400 |
DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE); |
|
2401 |
@@ -90,13 +95,17 @@
|
|
2402 |
hp_find_record(info, pos); |
|
2403 |
||
2404 |
end: |
|
2405 |
- if (!info->current_ptr[share->reclength])
|
|
2406 |
+ if (GET_CHUNK_STATUS(info, info->current_ptr) != CHUNK_STATUS_ACTIVE)
|
|
2407 |
{ |
|
2408 |
+ /* treat deleted and linked chunks as deleted */
|
|
2409 |
info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND; |
|
2410 |
DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED); |
|
2411 |
} |
|
2412 |
info->update=HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV; |
|
2413 |
- memcpy(record,info->current_ptr,(size_t) share->reclength);
|
|
2414 |
+ if (hp_extract_record(info, record, info->current_ptr))
|
|
2415 |
+ {
|
|
2416 |
+ DBUG_RETURN(my_errno);
|
|
2417 |
+ }
|
|
2418 |
DBUG_PRINT("exit",("found record at 0x%lx",info->current_ptr)); |
|
2419 |
info->current_hash_ptr=0; /* Can't use rnext */ |
|
2420 |
DBUG_RETURN(0); |
|
2421 |
diff -ruN a/storage/heap/hp_rsame.c b/storage/heap/hp_rsame.c
|
|
2422 |
--- a/storage/heap/hp_rsame.c 2011-04-11 13:44:03.000000000 +0300
|
|
2423 |
+++ b/storage/heap/hp_rsame.c 2011-06-02 15:38:02.764917001 +0300
|
|
2424 |
@@ -31,7 +31,8 @@
|
|
2425 |
DBUG_ENTER("heap_rsame"); |
|
2426 |
||
2427 |
test_active(info); |
|
2428 |
- if (info->current_ptr[share->reclength])
|
|
2429 |
+ if (get_chunk_status(&share->recordspace, info->current_ptr) ==
|
|
2430 |
+ CHUNK_STATUS_ACTIVE)
|
|
2431 |
{ |
|
2432 |
if (inx < -1 || inx >= (int) share->keys) |
|
2433 |
{ |
|
2434 |
@@ -47,9 +48,15 @@
|
|
2435 |
DBUG_RETURN(my_errno); |
|
2436 |
} |
|
2437 |
} |
|
2438 |
- memcpy(record,info->current_ptr,(size_t) share->reclength);
|
|
2439 |
+ if (hp_extract_record(info, record, info->current_ptr))
|
|
2440 |
+ {
|
|
2441 |
+ DBUG_RETURN(my_errno);
|
|
2442 |
+ }
|
|
2443 |
DBUG_RETURN(0); |
|
2444 |
} |
|
2445 |
+
|
|
2446 |
+ /* treat deleted and linked chunks as deleted */
|
|
2447 |
+
|
|
2448 |
info->update=0; |
|
2449 |
||
2450 |
DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED); |
|
2451 |
diff -ruN a/storage/heap/hp_scan.c b/storage/heap/hp_scan.c
|
|
2452 |
--- a/storage/heap/hp_scan.c 2011-04-11 13:44:03.000000000 +0300
|
|
2453 |
+++ b/storage/heap/hp_scan.c 2011-06-02 15:38:02.774917002 +0300
|
|
2454 |
@@ -30,7 +30,6 @@
|
|
2455 |
info->lastinx= -1; |
|
2456 |
info->current_record= (ulong) ~0L; /* No current record */ |
|
2457 |
info->update=0; |
|
2458 |
- info->next_block=0;
|
|
2459 |
DBUG_RETURN(0); |
|
2460 |
} |
|
2461 |
||
2462 |
@@ -41,32 +40,26 @@
|
|
2463 |
DBUG_ENTER("heap_scan"); |
|
2464 |
||
2465 |
pos= ++info->current_record; |
|
2466 |
- if (pos < info->next_block)
|
|
2467 |
+ if (pos >= share->recordspace.chunk_count)
|
|
2468 |
{ |
|
2469 |
- info->current_ptr+=share->block.recbuffer;
|
|
2470 |
+ info->update= 0;
|
|
2471 |
+ DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
|
|
2472 |
} |
|
2473 |
- else
|
|
2474 |
- {
|
|
2475 |
- info->next_block+=share->block.records_in_block;
|
|
2476 |
- if (info->next_block >= share->records+share->deleted)
|
|
2477 |
- {
|
|
2478 |
- info->next_block= share->records+share->deleted;
|
|
2479 |
- if (pos >= info->next_block)
|
|
2480 |
- {
|
|
2481 |
- info->update= 0;
|
|
2482 |
- DBUG_RETURN(my_errno= HA_ERR_END_OF_FILE);
|
|
2483 |
- }
|
|
2484 |
- }
|
|
2485 |
- hp_find_record(info, pos);
|
|
2486 |
- }
|
|
2487 |
- if (!info->current_ptr[share->reclength])
|
|
2488 |
+
|
|
2489 |
+ hp_find_record(info, pos);
|
|
2490 |
+
|
|
2491 |
+ if (get_chunk_status(&share->recordspace, info->current_ptr) !=
|
|
2492 |
+ CHUNK_STATUS_ACTIVE)
|
|
2493 |
{ |
|
2494 |
- DBUG_PRINT("warning",("Found deleted record"));
|
|
2495 |
+ DBUG_PRINT("warning",("Found deleted record or secondary chunk"));
|
|
2496 |
info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND; |
|
2497 |
DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED); |
|
2498 |
} |
|
2499 |
info->update= HA_STATE_PREV_FOUND | HA_STATE_NEXT_FOUND | HA_STATE_AKTIV; |
|
2500 |
- memcpy(record,info->current_ptr,(size_t) share->reclength);
|
|
2501 |
+ if (hp_extract_record(info, record, info->current_ptr))
|
|
2502 |
+ {
|
|
2503 |
+ DBUG_RETURN(my_errno);
|
|
2504 |
+ }
|
|
2505 |
info->current_hash_ptr=0; /* Can't use read_next */ |
|
2506 |
DBUG_RETURN(0); |
|
2507 |
} /* heap_scan */ |
|
2508 |
diff -ruN a/storage/heap/hp_test1.c b/storage/heap/hp_test1.c
|
|
2509 |
--- a/storage/heap/hp_test1.c 2011-04-11 13:44:03.000000000 +0300
|
|
2510 |
+++ b/storage/heap/hp_test1.c 2011-06-02 15:38:02.774917002 +0300
|
|
2511 |
@@ -22,6 +22,7 @@
|
|
2512 |
#include <my_global.h> |
|
2513 |
#include <my_sys.h> |
|
2514 |
#include <m_string.h> |
|
2515 |
+#include <mysql_com.h>
|
|
2516 |
#include "heap.h" |
|
2517 |
||
2518 |
static int get_options(int argc, char *argv[]); |
|
2519 |
@@ -35,6 +36,7 @@
|
|
2520 |
uchar record[128],key[32]; |
|
2521 |
const char *filename; |
|
2522 |
HP_KEYDEF keyinfo[10]; |
|
2523 |
+ HP_COLUMNDEF columndef[2];
|
|
2524 |
HA_KEYSEG keyseg[4]; |
|
2525 |
HP_CREATE_INFO hp_create_info; |
|
2526 |
HP_SHARE *tmp_share; |
|
2527 |
@@ -51,6 +53,10 @@
|
|
2528 |
hp_create_info.reclength= 30; |
|
2529 |
hp_create_info.max_records= (ulong) flag*100000L; |
|
2530 |
hp_create_info.min_records= 10UL; |
|
2531 |
+ hp_create_info.columns= 2;
|
|
2532 |
+ hp_create_info.columndef= columndef;
|
|
2533 |
+ hp_create_info.fixed_key_fieldnr= 30;
|
|
2534 |
+ hp_create_info.fixed_data_size= sizeof(char*) * 2;
|
|
2535 |
||
2536 |
keyinfo[0].keysegs=1; |
|
2537 |
keyinfo[0].seg=keyseg; |
|
2538 |
@@ -62,11 +68,20 @@
|
|
2539 |
keyinfo[0].seg[0].null_bit= 0; |
|
2540 |
keyinfo[0].flag = HA_NOSAME; |
|
2541 |
||
2542 |
+ memset(columndef, 0, 2 * sizeof(HP_COLUMNDEF));
|
|
2543 |
+ columndef[0].type= MYSQL_TYPE_STRING;
|
|
2544 |
+ columndef[0].offset= 1;
|
|
2545 |
+ columndef[0].length= 6;
|
|
2546 |
+ columndef[1].type= MYSQL_TYPE_STRING;
|
|
2547 |
+ columndef[1].offset= 7;
|
|
2548 |
+ columndef[1].length= 23;
|
|
2549 |
+
|
|
2550 |
deleted=0; |
|
2551 |
bzero((uchar*) flags,sizeof(flags)); |
|
2552 |
||
2553 |
printf("- Creating heap-file\n"); |
|
2554 |
- if (heap_create(filename, &hp_create_info, &tmp_share, &unused) ||
|
|
2555 |
+ if (heap_create(filename, &hp_create_info,
|
|
2556 |
+ &tmp_share, &unused) ||
|
|
2557 |
!(file= heap_open(filename, 2))) |
|
2558 |
goto err; |
|
2559 |
printf("- Writing records:s\n"); |
|
2560 |
diff -ruN a/storage/heap/hp_test2.c b/storage/heap/hp_test2.c
|
|
2561 |
--- a/storage/heap/hp_test2.c 2011-04-11 13:44:03.000000000 +0300
|
|
2562 |
+++ b/storage/heap/hp_test2.c 2011-06-02 15:38:02.774917002 +0300
|
|
2563 |
@@ -18,6 +18,7 @@
|
|
2564 |
||
2565 |
#include "heapdef.h" /* Because of hp_find_block */ |
|
2566 |
#include <signal.h> |
|
2567 |
+#include <mysql_com.h>
|
|
2568 |
||
2569 |
#define MAX_RECORDS 100000 |
|
2570 |
#define MAX_KEYS 4 |
|
2571 |
@@ -44,6 +45,7 @@
|
|
2572 |
register uint i,j; |
|
2573 |
uint ant,n1,n2,n3; |
|
2574 |
uint write_count,update,opt_delete,check2,dupp_keys,found_key; |
|
2575 |
+ uint mem_per_keys;
|
|
2576 |
int error; |
|
2577 |
ulong pos; |
|
2578 |
unsigned long key_check; |
|
2579 |
@@ -53,6 +55,7 @@
|
|
2580 |
HP_SHARE *tmp_share; |
|
2581 |
HP_KEYDEF keyinfo[MAX_KEYS]; |
|
2582 |
HA_KEYSEG keyseg[MAX_KEYS*5]; |
|
2583 |
+ HP_COLUMNDEF columndef[4];
|
|
2584 |
HEAP_PTR UNINIT_VAR(position); |
|
2585 |
HP_CREATE_INFO hp_create_info; |
|
2586 |
CHARSET_INFO *cs= &my_charset_latin1; |
|
2587 |
@@ -65,12 +68,16 @@
|
|
2588 |
get_options(argc,argv); |
|
2589 |
||
2590 |
bzero(&hp_create_info, sizeof(hp_create_info)); |
|
2591 |
- hp_create_info.max_table_size= 1024L*1024L;
|
|
2592 |
+ hp_create_info.max_table_size= 1024L*1024L*1024L;
|
|
2593 |
hp_create_info.keys= keys; |
|
2594 |
hp_create_info.keydef= keyinfo; |
|
2595 |
hp_create_info.reclength= reclength; |
|
2596 |
hp_create_info.max_records= (ulong) flag*100000L; |
|
2597 |
hp_create_info.min_records= (ulong) recant/2; |
|
2598 |
+ hp_create_info.columns= 4;
|
|
2599 |
+ hp_create_info.columndef= columndef;
|
|
2600 |
+ hp_create_info.fixed_key_fieldnr= 4;
|
|
2601 |
+ hp_create_info.fixed_data_size= 39;
|
|
2602 |
||
2603 |
write_count=update=opt_delete=0; |
|
2604 |
key_check=0; |
|
2605 |
@@ -118,11 +125,30 @@
|
|
2606 |
keyinfo[3].seg[0].null_pos=38; |
|
2607 |
keyinfo[3].seg[0].charset=cs; |
|
2608 |
||
2609 |
+ memset(columndef, 0, 4 * sizeof(HP_COLUMNDEF));
|
|
2610 |
+ columndef[0].type= MYSQL_TYPE_STRING;
|
|
2611 |
+ columndef[0].offset= 0;
|
|
2612 |
+ columndef[0].length= 6;
|
|
2613 |
+ columndef[1].type= MYSQL_TYPE_STRING;
|
|
2614 |
+ columndef[1].offset= 7;
|
|
2615 |
+ columndef[1].length= 6;
|
|
2616 |
+ columndef[2].type= MYSQL_TYPE_STRING;
|
|
2617 |
+ columndef[2].offset= 12;
|
|
2618 |
+ columndef[2].length= 8;
|
|
2619 |
+ columndef[3].type= MYSQL_TYPE_TINY;
|
|
2620 |
+ columndef[3].offset= 37;
|
|
2621 |
+ columndef[3].length= 1;
|
|
2622 |
+ columndef[3].null_bit= 1;
|
|
2623 |
+ columndef[3].null_pos= 38;
|
|
2624 |
+
|
|
2625 |
+ mem_per_keys= (sizeof(char*) * 2) * 4;
|
|
2626 |
+
|
|
2627 |
bzero((char*) key1,sizeof(key1)); |
|
2628 |
bzero((char*) key3,sizeof(key3)); |
|
2629 |
||
2630 |
printf("- Creating heap-file\n"); |
|
2631 |
- if (heap_create(filename, &hp_create_info, &tmp_share, &unused) ||
|
|
2632 |
+ if (heap_create(filename, &hp_create_info,
|
|
2633 |
+ &tmp_share, &unused) ||
|
|
2634 |
!(file= heap_open(filename, 2))) |
|
2635 |
goto err; |
|
2636 |
signal(SIGINT,endprog); |
|
2637 |
diff -ruN a/storage/heap/hp_write.c b/storage/heap/hp_write.c
|
|
2638 |
--- a/storage/heap/hp_write.c 2011-04-11 13:44:03.000000000 +0300
|
|
2639 |
+++ b/storage/heap/hp_write.c 2011-06-02 15:38:02.774917002 +0300
|
|
2640 |
@@ -25,7 +25,6 @@
|
|
2641 |
#define HIGHFIND 4 |
|
2642 |
#define HIGHUSED 8 |
|
2643 |
||
2644 |
-static uchar *next_free_record_pos(HP_SHARE *info);
|
|
2645 |
static HASH_INFO *hp_find_free_hash(HP_SHARE *info, HP_BLOCK *block, |
|
2646 |
ulong records); |
|
2647 |
||
2648 |
@@ -34,6 +33,8 @@
|
|
2649 |
HP_KEYDEF *keydef, *end; |
|
2650 |
uchar *pos; |
|
2651 |
HP_SHARE *share=info->s; |
|
2652 |
+ uint rec_length, chunk_count;
|
|
2653 |
+
|
|
2654 |
DBUG_ENTER("heap_write"); |
|
2655 |
#ifndef DBUG_OFF |
|
2656 |
if (info->mode & O_RDONLY) |
|
2657 |
@@ -41,7 +42,18 @@
|
|
2658 |
DBUG_RETURN(my_errno=EACCES); |
|
2659 |
} |
|
2660 |
#endif |
|
2661 |
- if (!(pos=next_free_record_pos(share)))
|
|
2662 |
+
|
|
2663 |
+ if ((share->records >= share->max_records && share->max_records) ||
|
|
2664 |
+ (share->recordspace.total_data_length + share->index_length >=
|
|
2665 |
+ share->max_table_size))
|
|
2666 |
+ {
|
|
2667 |
+ my_errno= HA_ERR_RECORD_FILE_FULL;
|
|
2668 |
+ DBUG_RETURN(my_errno);
|
|
2669 |
+ }
|
|
2670 |
+
|
|
2671 |
+ rec_length= hp_get_encoded_data_length(share, record, &chunk_count);
|
|
2672 |
+
|
|
2673 |
+ if (!(pos= hp_allocate_chunkset(&share->recordspace, chunk_count)))
|
|
2674 |
DBUG_RETURN(my_errno); |
|
2675 |
share->changed=1; |
|
2676 |
||
2677 |
@@ -52,8 +64,8 @@
|
|
2678 |
goto err; |
|
2679 |
} |
|
2680 |
||
2681 |
- memcpy(pos,record,(size_t) share->reclength);
|
|
2682 |
- pos[share->reclength]=1; /* Mark record as not deleted */
|
|
2683 |
+ hp_copy_record_data_to_chunkset(share, record, pos);
|
|
2684 |
+
|
|
2685 |
if (++share->records == share->blength) |
|
2686 |
share->blength+= share->blength; |
|
2687 |
info->current_ptr=pos; |
|
2688 |
@@ -87,10 +99,7 @@
|
|
2689 |
keydef--; |
|
2690 |
} |
|
2691 |
||
2692 |
- share->deleted++;
|
|
2693 |
- *((uchar**) pos)=share->del_link;
|
|
2694 |
- share->del_link=pos;
|
|
2695 |
- pos[share->reclength]=0; /* Record deleted */
|
|
2696 |
+ hp_free_chunks(&share->recordspace, pos);
|
|
2697 |
||
2698 |
DBUG_RETURN(my_errno); |
|
2699 |
} /* heap_write */ |
|
2700 |
@@ -106,7 +115,8 @@
|
|
2701 |
uint old_allocated; |
|
2702 |
||
2703 |
custom_arg.keyseg= keyinfo->seg; |
|
2704 |
- custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
|
|
2705 |
+ custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos,
|
|
2706 |
+ FALSE);
|
|
2707 |
if (keyinfo->flag & HA_NOSAME) |
|
2708 |
{ |
|
2709 |
custom_arg.search_flag= SEARCH_FIND | SEARCH_UPDATE; |
|
2710 |
@@ -128,42 +138,6 @@
|
|
2711 |
return 0; |
|
2712 |
} |
|
2713 |
||
2714 |
- /* Find where to place new record */
|
|
2715 |
-
|
|
2716 |
-static uchar *next_free_record_pos(HP_SHARE *info)
|
|
2717 |
-{
|
|
2718 |
- int block_pos;
|
|
2719 |
- uchar *pos;
|
|
2720 |
- size_t length;
|
|
2721 |
- DBUG_ENTER("next_free_record_pos");
|
|
2722 |
-
|
|
2723 |
- if (info->del_link)
|
|
2724 |
- {
|
|
2725 |
- pos=info->del_link;
|
|
2726 |
- info->del_link= *((uchar**) pos);
|
|
2727 |
- info->deleted--;
|
|
2728 |
- DBUG_PRINT("exit",("Used old position: 0x%lx",(long) pos));
|
|
2729 |
- DBUG_RETURN(pos);
|
|
2730 |
- }
|
|
2731 |
- if (!(block_pos=(info->records % info->block.records_in_block)))
|
|
2732 |
- {
|
|
2733 |
- if ((info->records > info->max_records && info->max_records) ||
|
|
2734 |
- (info->data_length + info->index_length >= info->max_table_size))
|
|
2735 |
- {
|
|
2736 |
- my_errno=HA_ERR_RECORD_FILE_FULL;
|
|
2737 |
- DBUG_RETURN(NULL);
|
|
2738 |
- }
|
|
2739 |
- if (hp_get_new_block(&info->block,&length))
|
|
2740 |
- DBUG_RETURN(NULL);
|
|
2741 |
- info->data_length+=length;
|
|
2742 |
- }
|
|
2743 |
- DBUG_PRINT("exit",("Used new position: 0x%lx",
|
|
2744 |
- (long) ((uchar*) info->block.level_info[0].last_blocks+
|
|
2745 |
- block_pos * info->block.recbuffer)));
|
|
2746 |
- DBUG_RETURN((uchar*) info->block.level_info[0].last_blocks+
|
|
2747 |
- block_pos*info->block.recbuffer);
|
|
2748 |
-}
|
|
2749 |
-
|
|
2750 |
||
2751 |
/* |
|
2752 |
Write a hash-key to the hash-index |
|
2753 |
diff -ruN a/storage/heap/hp_update.c b/storage/heap/hp_update.c
|
|
2754 |
--- a/storage/heap/hp_update.c 2011-04-11 13:44:03.000000000 +0300
|
|
2755 |
+++ b/storage/heap/hp_update.c 2011-05-26 09:07:47.605561000 +0300
|
|
2756 |
@@ -17,43 +17,66 @@
|
|
2757 |
||
2758 |
#include "heapdef.h" |
|
2759 |
||
2760 |
-int heap_update(HP_INFO *info, const uchar *old, const uchar *heap_new)
|
|
2761 |
+int heap_update(HP_INFO *info, const uchar *old_record, const uchar *new_record)
|
|
2762 |
{ |
|
2763 |
HP_KEYDEF *keydef, *end, *p_lastinx; |
|
2764 |
uchar *pos; |
|
2765 |
my_bool auto_key_changed= 0; |
|
2766 |
HP_SHARE *share= info->s; |
|
2767 |
+ uint old_length, new_length;
|
|
2768 |
+ uint old_chunk_count, new_chunk_count;
|
|
2769 |
+
|
|
2770 |
DBUG_ENTER("heap_update"); |
|
2771 |
||
2772 |
test_active(info); |
|
2773 |
pos=info->current_ptr; |
|
2774 |
||
2775 |
- if (info->opt_flag & READ_CHECK_USED && hp_rectest(info,old))
|
|
2776 |
+ if (info->opt_flag & READ_CHECK_USED && hp_rectest(info, old_record))
|
|
2777 |
DBUG_RETURN(my_errno); /* Record changed */ |
|
2778 |
+
|
|
2779 |
+ old_length = hp_get_encoded_data_length(share, old_record, &old_chunk_count);
|
|
2780 |
+ new_length = hp_get_encoded_data_length(share, new_record, &new_chunk_count);
|
|
2781 |
+
|
|
2782 |
+ if (new_chunk_count > old_chunk_count)
|
|
2783 |
+ {
|
|
2784 |
+ /* extend the old chunkset size as necessary, but do not shrink yet */
|
|
2785 |
+ if (hp_reallocate_chunkset(&share->recordspace, new_chunk_count, pos))
|
|
2786 |
+ {
|
|
2787 |
+ DBUG_RETURN(my_errno); /* Out of memory or table space */
|
|
2788 |
+ }
|
|
2789 |
+ }
|
|
2790 |
+
|
|
2791 |
if (--(share->records) < share->blength >> 1) share->blength>>= 1; |
|
2792 |
share->changed=1; |
|
2793 |
||
2794 |
p_lastinx= share->keydef + info->lastinx; |
|
2795 |
for (keydef= share->keydef, end= keydef + share->keys; keydef < end; keydef++) |
|
2796 |
{ |
|
2797 |
- if (hp_rec_key_cmp(keydef, old, heap_new, 0))
|
|
2798 |
+ if (hp_rec_key_cmp(keydef, old_record, new_record, 0))
|
|
2799 |
{ |
|
2800 |
- if ((*keydef->delete_key)(info, keydef, old, pos, keydef == p_lastinx) ||
|
|
2801 |
- (*keydef->write_key)(info, keydef, heap_new, pos))
|
|
2802 |
+ if ((*keydef->delete_key)(info, keydef, old_record, pos,
|
|
2803 |
+ keydef == p_lastinx) ||
|
|
2804 |
+ (*keydef->write_key)(info, keydef, new_record, pos))
|
|
2805 |
goto err; |
|
2806 |
if (share->auto_key == (uint) (keydef - share->keydef + 1)) |
|
2807 |
auto_key_changed= 1; |
|
2808 |
} |
|
2809 |
} |
|
2810 |
||
2811 |
- memcpy(pos,heap_new,(size_t) share->reclength);
|
|
2812 |
+ hp_copy_record_data_to_chunkset(share, new_record, pos);
|
|
2813 |
if (++(share->records) == share->blength) share->blength+= share->blength; |
|
2814 |
||
2815 |
+ if (new_chunk_count < old_chunk_count)
|
|
2816 |
+ {
|
|
2817 |
+ /* Shrink the chunkset to its new size */
|
|
2818 |
+ hp_reallocate_chunkset(&share->recordspace, new_chunk_count, pos);
|
|
2819 |
+ }
|
|
2820 |
+
|
|
2821 |
#if !defined(DBUG_OFF) && defined(EXTRA_HEAP_DEBUG) |
|
2822 |
DBUG_EXECUTE("check_heap",heap_check_heap(info, 0);); |
|
2823 |
#endif |
|
2824 |
if (auto_key_changed) |
|
2825 |
- heap_update_auto_increment(info, heap_new);
|
|
2826 |
+ heap_update_auto_increment(info, new_record);
|
|
2827 |
DBUG_RETURN(0); |
|
2828 |
||
2829 |
err: |
|
2830 |
@@ -63,7 +86,7 @@
|
|
2831 |
if (keydef->algorithm == HA_KEY_ALG_BTREE) |
|
2832 |
{ |
|
2833 |
/* we don't need to delete non-inserted key from rb-tree */ |
|
2834 |
- if ((*keydef->write_key)(info, keydef, old, pos))
|
|
2835 |
+ if ((*keydef->write_key)(info, keydef, old_record, pos))
|
|
2836 |
{ |
|
2837 |
if (++(share->records) == share->blength) |
|
2838 |
share->blength+= share->blength; |
|
2839 |
@@ -73,10 +96,10 @@
|
|
2840 |
} |
|
2841 |
while (keydef >= share->keydef) |
|
2842 |
{ |
|
2843 |
- if (hp_rec_key_cmp(keydef, old, heap_new, 0))
|
|
2844 |
+ if (hp_rec_key_cmp(keydef, old_record, new_record, 0))
|
|
2845 |
{ |
|
2846 |
- if ((*keydef->delete_key)(info, keydef, heap_new, pos, 0) ||
|
|
2847 |
- (*keydef->write_key)(info, keydef, old, pos))
|
|
2848 |
+ if ((*keydef->delete_key)(info, keydef, new_record, pos, 0) ||
|
|
2849 |
+ (*keydef->write_key)(info, keydef, old_record, pos))
|
|
2850 |
break; |
|
2851 |
} |
|
2852 |
keydef--; |
|
2853 |
@@ -84,5 +107,12 @@
|
|
2854 |
} |
|
2855 |
if (++(share->records) == share->blength) |
|
2856 |
share->blength+= share->blength; |
|
2857 |
+
|
|
2858 |
+ if (new_chunk_count > old_chunk_count)
|
|
2859 |
+ {
|
|
2860 |
+ /* Shrink the chunkset to its original size */
|
|
2861 |
+ hp_reallocate_chunkset(&share->recordspace, old_chunk_count, pos);
|
|
2862 |
+ }
|
|
2863 |
+
|
|
2864 |
DBUG_RETURN(my_errno); |
|
2865 |
} /* heap_update */ |