~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/opt_range.cc

Merge trunk and resolve all conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
118
118
#include <vector>
119
119
#include <algorithm>
120
120
 
 
121
#include "drizzled/memory/multi_malloc.h"
 
122
 
121
123
using namespace std;
 
124
using namespace drizzled;
122
125
 
123
126
#define HA_END_SPACE_KEY 0
124
127
 
133
136
 
134
137
extern "C" int refpos_order_cmp(void* arg, const void *a,const void *b)
135
138
{
136
 
  handler *file= (handler*)arg;
 
139
  Cursor *file= (Cursor*)arg;
137
140
  return file->cmp_ref((const unsigned char*)a, (const unsigned char*)b);
138
141
}
139
142
 
141
144
 
142
145
static unsigned char is_null_string[2]= {1,0};
143
146
 
 
147
 
 
148
/**
 
149
  Get cost of reading nrows table records in a "disk sweep"
 
150
 
 
151
  A disk sweep read is a sequence of Cursor->rnd_pos(rowid) calls that made
 
152
  for an ordered sequence of rowids.
 
153
 
 
154
  We assume hard disk IO. The read is performed as follows:
 
155
 
 
156
   1. The disk head is moved to the needed cylinder
 
157
   2. The controller waits for the plate to rotate
 
158
   3. The data is transferred
 
159
 
 
160
  Time to do #3 is insignificant compared to #2+#1.
 
161
 
 
162
  Time to move the disk head is proportional to head travel distance.
 
163
 
 
164
  Time to wait for the plate to rotate depends on whether the disk head
 
165
  was moved or not.
 
166
 
 
167
  If disk head wasn't moved, the wait time is proportional to distance
 
168
  between the previous block and the block we're reading.
 
169
 
 
170
  If the head was moved, we don't know how much we'll need to wait for the
 
171
  plate to rotate. We assume the wait time to be a variate with a mean of
 
172
  0.5 of full rotation time.
 
173
 
 
174
  Our cost units are "random disk seeks". The cost of random disk seek is
 
175
  actually not a constant, it depends one range of cylinders we're going
 
176
  to access. We make it constant by introducing a fuzzy concept of "typical
 
177
  datafile length" (it's fuzzy as it's hard to tell whether it should
 
178
  include index file, temp.tables etc). Then random seek cost is:
 
179
 
 
180
    1 = half_rotation_cost + move_cost * 1/3 * typical_data_file_length
 
181
 
 
182
  We define half_rotation_cost as DISK_SEEK_BASE_COST=0.9.
 
183
 
 
184
  @param table             Table to be accessed
 
185
  @param nrows             Number of rows to retrieve
 
186
  @param interrupted       true <=> Assume that the disk sweep will be
 
187
                           interrupted by other disk IO. false - otherwise.
 
188
  @param cost         OUT  The cost.
 
189
*/
 
190
 
 
191
static void get_sweep_read_cost(Table *table, ha_rows nrows, bool interrupted,
 
192
                                COST_VECT *cost)
 
193
{
 
194
  cost->zero();
 
195
  if (table->file->primary_key_is_clustered())
 
196
  {
 
197
    cost->io_count= table->file->read_time(table->s->primary_key,
 
198
                                           (uint32_t) nrows, nrows);
 
199
  }
 
200
  else
 
201
  {
 
202
    double n_blocks=
 
203
      ceil(uint64_t2double(table->file->stats.data_file_length) / IO_SIZE);
 
204
    double busy_blocks=
 
205
      n_blocks * (1.0 - pow(1.0 - 1.0/n_blocks, rows2double(nrows)));
 
206
    if (busy_blocks < 1.0)
 
207
      busy_blocks= 1.0;
 
208
 
 
209
    cost->io_count= busy_blocks;
 
210
 
 
211
    if (!interrupted)
 
212
    {
 
213
      /* Assume reading is done in one 'sweep' */
 
214
      cost->avg_io_cost= (DISK_SEEK_BASE_COST +
 
215
                          DISK_SEEK_PROP_COST*n_blocks/busy_blocks);
 
216
    }
 
217
  }
 
218
}
 
219
 
144
220
class RANGE_OPT_PARAM;
145
221
/*
146
222
  A construction block of the SEL_ARG-graph.
1156
1232
 
1157
1233
int QUICK_RANGE_SELECT::init()
1158
1234
{
1159
 
  if (file->inited != handler::NONE)
 
1235
  if (file->inited != Cursor::NONE)
1160
1236
    file->ha_index_or_rnd_end();
1161
1237
  return(file->ha_index_init(index, 1));
1162
1238
}
1164
1240
 
1165
1241
void QUICK_RANGE_SELECT::range_end()
1166
1242
{
1167
 
  if (file->inited != handler::NONE)
 
1243
  if (file->inited != Cursor::NONE)
1168
1244
    file->ha_index_or_rnd_end();
1169
1245
}
1170
1246
 
1291
1367
  SYNOPSIS
1292
1368
    QUICK_RANGE_SELECT::init_ror_merged_scan()
1293
1369
      reuse_handler If true, use head->file, otherwise create a separate
1294
 
                    handler object
 
1370
                    Cursor object
1295
1371
 
1296
1372
  NOTES
1297
 
    This function creates and prepares for subsequent use a separate handler
 
1373
    This function creates and prepares for subsequent use a separate Cursor
1298
1374
    object if it can't reuse head->file. The reason for this is that during
1299
1375
    ROR-merge several key scans are performed simultaneously, and a single
1300
 
    handler is only capable of preserving context of a single key scan.
 
1376
    Cursor is only capable of preserving context of a single key scan.
1301
1377
 
1302
1378
    In ROR-merge the quick select doing merge does full records retrieval,
1303
1379
    merged quick selects read only keys.
1309
1385
 
1310
1386
int QUICK_RANGE_SELECT::init_ror_merged_scan(bool reuse_handler)
1311
1387
{
1312
 
  handler *save_file= file, *org_file;
 
1388
  Cursor *save_file= file, *org_file;
1313
1389
  Session *session;
1314
1390
 
1315
1391
  in_ror_merged_scan= 1;
1323
1399
    goto end;
1324
1400
  }
1325
1401
 
1326
 
  /* Create a separate handler object for this quick select */
 
1402
  /* Create a separate Cursor object for this quick select */
1327
1403
  if (free_file)
1328
1404
  {
1329
 
    /* already have own 'handler' object. */
 
1405
    /* already have own 'Cursor' object. */
1330
1406
    return 0;
1331
1407
  }
1332
1408
 
1400
1476
  SYNOPSIS
1401
1477
    QUICK_ROR_INTERSECT_SELECT::init_ror_merged_scan()
1402
1478
      reuse_handler If true, use head->file, otherwise create separate
1403
 
                    handler object.
 
1479
                    Cursor object.
1404
1480
  RETURN
1405
1481
    0     OK
1406
1482
    other error code
1488
1564
  quick_selects.delete_elements();
1489
1565
  delete cpk_quick;
1490
1566
  free_root(&alloc,MYF(0));
1491
 
  if (need_to_fetch_row && head->file->inited != handler::NONE)
 
1567
  if (need_to_fetch_row && head->file->inited != Cursor::NONE)
1492
1568
    head->file->ha_rnd_end();
1493
1569
  return;
1494
1570
}
1613
1689
    queue->pop();
1614
1690
  delete queue;
1615
1691
  quick_selects.delete_elements();
1616
 
  if (head->file->inited != handler::NONE)
 
1692
  if (head->file->inited != Cursor::NONE)
1617
1693
    head->file->ha_rnd_end();
1618
1694
  free_root(&alloc,MYF(0));
1619
1695
  return;
2360
2436
        }
2361
2437
 
2362
2438
        /*
2363
 
          Simultaneous key scans and row deletes on several handler
 
2439
          Simultaneous key scans and row deletes on several Cursor
2364
2440
          objects are not allowed so don't use ROR-intersection for
2365
2441
          table deletes.
2366
2442
        */
6312
6388
 
6313
6389
  RETURN
6314
6390
    Estimate # of records to be retrieved.
6315
 
    HA_POS_ERROR if estimate calculation failed due to table handler problems.
 
6391
    HA_POS_ERROR if estimate calculation failed due to table Cursor problems.
6316
6392
*/
6317
6393
 
6318
6394
static
6322
6398
{
6323
6399
  SEL_ARG_RANGE_SEQ seq;
6324
6400
  RANGE_SEQ_IF seq_if = {sel_arg_range_seq_init, sel_arg_range_seq_next};
6325
 
  handler *file= param->table->file;
 
6401
  Cursor *file= param->table->file;
6326
6402
  ha_rows rows;
6327
6403
  uint32_t keynr= param->real_keynr[idx];
6328
6404
 
6873
6949
  QUICK_RANGE_SELECT* cur_quick;
6874
6950
  int result;
6875
6951
  Unique *unique;
6876
 
  handler *file= head->file;
 
6952
  Cursor *file= head->file;
6877
6953
 
6878
6954
  file->extra(HA_EXTRA_KEYREAD);
6879
6955
  head->prepare_for_position();
6883
6959
  assert(cur_quick != 0);
6884
6960
 
6885
6961
  /*
6886
 
    We reuse the same instance of handler so we need to call both init and
 
6962
    We reuse the same instance of Cursor so we need to call both init and
6887
6963
    reset here.
6888
6964
  */
6889
6965
  if (cur_quick->init() || cur_quick->reset())
6903
6979
      if (!cur_quick)
6904
6980
        break;
6905
6981
 
6906
 
      if (cur_quick->file->inited != handler::NONE)
 
6982
      if (cur_quick->file->inited != Cursor::NONE)
6907
6983
        cur_quick->file->ha_index_end();
6908
6984
      if (cur_quick->init() || cur_quick->reset())
6909
6985
        return 0;
7145
7221
  last_range= NULL;
7146
7222
  cur_range= (QUICK_RANGE**) ranges.buffer;
7147
7223
 
7148
 
  if (file->inited == handler::NONE && (error= file->ha_index_init(index,1)))
 
7224
  if (file->inited == Cursor::NONE && (error= file->ha_index_init(index,1)))
7149
7225
    return(error);
7150
7226
 
7151
7227
  /* Allocate buffer if we need one but haven't allocated it yet */
7152
7228
  if (mrr_buf_size && !mrr_buf_desc)
7153
7229
  {
7154
7230
    buf_size= mrr_buf_size;
7155
 
    while (buf_size && !my_multi_malloc(MYF(MY_WME),
 
7231
    while (buf_size && ! memory::multi_malloc(false,
7156
7232
                                        &mrr_buf_desc, sizeof(*mrr_buf_desc),
7157
7233
                                        &mrange_buff, buf_size,
7158
7234
                                        NULL))
7163
7239
    if (!mrr_buf_desc)
7164
7240
      return(HA_ERR_OUT_OF_MEM);
7165
7241
 
7166
 
    /* Initialize the handler buffer. */
 
7242
    /* Initialize the Cursor buffer. */
7167
7243
    mrr_buf_desc->buffer= mrange_buff;
7168
7244
    mrr_buf_desc->buffer_end= mrange_buff + buf_size;
7169
7245
    mrr_buf_desc->end_of_used_area= mrange_buff;
9012
9088
 
9013
9089
QUICK_GROUP_MIN_MAX_SELECT::~QUICK_GROUP_MIN_MAX_SELECT()
9014
9090
{
9015
 
  if (file->inited != handler::NONE)
 
9091
  if (file->inited != Cursor::NONE)
9016
9092
    file->ha_index_end();
9017
9093
  if (min_max_arg_part)
9018
9094
    delete_dynamic(&min_max_ranges);