~james-page/ubuntu/precise/mysql-5.5/misc-fixes

« back to all changes in this revision

Viewing changes to sql/ha_partition.cc

  • Committer: Package Import Robot
  • Author(s): Marc Deslauriers
  • Date: 2012-06-11 07:34:33 UTC
  • mfrom: (1.1.6)
  • Revision ID: package-import@ubuntu.com-20120611073433-l9za2ni4ipp848y3
Tags: 5.5.24-0ubuntu0.12.04.1
* SECURITY UPDATE: Update to 5.5.24 to fix security issues (LP: #1011371)
  - http://dev.mysql.com/doc/refman/5.5/en/news-5-5-24.html

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
  Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
 
2
  Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
3
3
 
4
4
  This program is free software; you can redistribute it and/or modify
5
5
  it under the terms of the GNU General Public License as published by
285
285
  m_is_sub_partitioned= 0;
286
286
  m_is_clone_of= NULL;
287
287
  m_clone_mem_root= NULL;
 
288
  m_part_ids_sorted_by_num_of_records= NULL;
288
289
 
289
290
#ifdef DONT_HAVE_TO_BE_INITALIZED
290
291
  m_start_key.flag= 0;
320
321
      delete m_file[i];
321
322
  }
322
323
  my_free(m_ordered_rec_buffer);
 
324
  my_free(m_part_ids_sorted_by_num_of_records);
323
325
 
324
326
  clear_handler_file();
325
327
  DBUG_VOID_RETURN;
2680
2682
      m_start_key.key= (const uchar*)ptr;
2681
2683
    }
2682
2684
  }
 
2685
  if (!m_part_ids_sorted_by_num_of_records)
 
2686
  {
 
2687
    if (!(m_part_ids_sorted_by_num_of_records=
 
2688
            (uint32*) my_malloc(m_tot_parts * sizeof(uint32), MYF(MY_WME))))
 
2689
      DBUG_RETURN(error);
 
2690
    uint32 i;
 
2691
    /* Initialize it with all partition ids. */
 
2692
    for (i= 0; i < m_tot_parts; i++)
 
2693
      m_part_ids_sorted_by_num_of_records[i]= i;
 
2694
  }
2683
2695
 
2684
2696
  /* Initialize the bitmap we use to minimize ha_start_bulk_insert calls */
2685
2697
  if (bitmap_init(&m_bulk_insert_started, NULL, m_tot_parts + 1, FALSE))
5273
5285
  and read_time calls
5274
5286
*/
5275
5287
 
 
5288
/**
 
5289
  Helper function for sorting according to number of rows in descending order.
 
5290
*/
 
5291
 
 
5292
int ha_partition::compare_number_of_records(ha_partition *me,
 
5293
                                            const uint32 *a,
 
5294
                                            const uint32 *b)
 
5295
{
 
5296
  handler **file= me->m_file;
 
5297
  /* Note: sorting in descending order! */
 
5298
  if (file[*a]->stats.records > file[*b]->stats.records)
 
5299
    return -1;
 
5300
  if (file[*a]->stats.records < file[*b]->stats.records)
 
5301
    return 1;
 
5302
  return 0;
 
5303
}
 
5304
 
 
5305
 
5276
5306
/*
5277
5307
  General method to gather info from handler
5278
5308
 
5517
5547
      }
5518
5548
      i++;
5519
5549
    } while (*(++file_array));
 
5550
    /*
 
5551
      Sort the array of part_ids by number of records in
 
5552
      in descending order.
 
5553
    */
 
5554
    my_qsort2((void*) m_part_ids_sorted_by_num_of_records,
 
5555
              m_tot_parts,
 
5556
              sizeof(uint32),
 
5557
              (qsort2_cmp) compare_number_of_records,
 
5558
              this);
5520
5559
 
5521
5560
    file= m_file[handler_instance];
5522
5561
    file->info(HA_STATUS_CONST | no_lock_flag);
6272
6311
  DBUG_RETURN(m_file[0]->keys_to_use_for_scanning());
6273
6312
}
6274
6313
 
6275
 
#define MAX_PARTS_FOR_OPTIMIZER_CALLS 10
6276
 
/*
6277
 
  Prepare start variables for estimating optimizer costs.
6278
 
 
6279
 
  @param[out] num_used_parts  Number of partitions after pruning.
6280
 
  @param[out] check_min_num   Number of partitions to call.
6281
 
  @param[out] first           first used partition.
6282
 
*/
6283
 
void ha_partition::partitions_optimizer_call_preparations(uint *first,
6284
 
                                                          uint *num_used_parts,
6285
 
                                                          uint *check_min_num)
6286
 
{
6287
 
  *first= bitmap_get_first_set(&(m_part_info->used_partitions));
6288
 
  *num_used_parts= bitmap_bits_set(&(m_part_info->used_partitions));
6289
 
  *check_min_num= min(MAX_PARTS_FOR_OPTIMIZER_CALLS, *num_used_parts);
 
6314
 
 
6315
/**
 
6316
  Minimum number of rows to base optimizer estimate on.
 
6317
*/
 
6318
 
 
6319
ha_rows ha_partition::min_rows_for_estimate()
 
6320
{
 
6321
  uint i, max_used_partitions, tot_used_partitions;
 
6322
  DBUG_ENTER("ha_partition::min_rows_for_estimate");
 
6323
 
 
6324
  tot_used_partitions= bitmap_bits_set(&m_part_info->used_partitions);
 
6325
  DBUG_ASSERT(tot_used_partitions);
 
6326
 
 
6327
  /*
 
6328
    Allow O(log2(tot_partitions)) increase in number of used partitions.
 
6329
    This gives O(tot_rows/log2(tot_partitions)) rows to base the estimate on.
 
6330
    I.e when the total number of partitions doubles, allow one more
 
6331
    partition to be checked.
 
6332
  */
 
6333
  i= 2;
 
6334
  max_used_partitions= 1;
 
6335
  while (i < m_tot_parts)
 
6336
  {
 
6337
    max_used_partitions++;
 
6338
    i= i << 1;
 
6339
  }
 
6340
  if (max_used_partitions > tot_used_partitions)
 
6341
    max_used_partitions= tot_used_partitions;
 
6342
 
 
6343
  /* stats.records is already updated by the info(HA_STATUS_VARIABLE) call. */
 
6344
  DBUG_PRINT("info", ("max_used_partitions: %u tot_rows: %lu",
 
6345
                      max_used_partitions,
 
6346
                      (ulong) stats.records));
 
6347
  DBUG_PRINT("info", ("tot_used_partitions: %u min_rows_to_check: %lu",
 
6348
                      tot_used_partitions,
 
6349
                      (ulong) stats.records * max_used_partitions
 
6350
                              / tot_used_partitions));
 
6351
  DBUG_RETURN(stats.records * max_used_partitions / tot_used_partitions);
 
6352
}
 
6353
 
 
6354
 
 
6355
/**
 
6356
  Get the biggest used partition.
 
6357
 
 
6358
  Starting at the N:th biggest partition and skips all non used
 
6359
  partitions, returning the biggest used partition found
 
6360
 
 
6361
  @param[in,out] part_index  Skip the *part_index biggest partitions
 
6362
 
 
6363
  @return The biggest used partition with index not lower than *part_index.
 
6364
    @retval NO_CURRENT_PART_ID     No more partition used.
 
6365
    @retval != NO_CURRENT_PART_ID  partition id of biggest used partition with
 
6366
                                   index >= *part_index supplied. Note that
 
6367
                                   *part_index will be updated to the next
 
6368
                                   partition index to use.
 
6369
*/
 
6370
 
 
6371
uint ha_partition::get_biggest_used_partition(uint *part_index)
 
6372
{
 
6373
  uint part_id;
 
6374
  while ((*part_index) < m_tot_parts)
 
6375
  {
 
6376
    part_id= m_part_ids_sorted_by_num_of_records[(*part_index)++];
 
6377
    if (bitmap_is_set(&m_part_info->used_partitions, part_id))
 
6378
      return part_id;
 
6379
  }
 
6380
  return NO_CURRENT_PART_ID;
6290
6381
}
6291
6382
 
6292
6383
 
6302
6393
 
6303
6394
double ha_partition::scan_time()
6304
6395
{
6305
 
  double scan_time= 0.0;
6306
 
  uint first, part_id, num_used_parts, check_min_num, partitions_called= 0;
 
6396
  double scan_time= 0;
 
6397
  handler **file;
6307
6398
  DBUG_ENTER("ha_partition::scan_time");
6308
6399
 
6309
 
  partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num);
6310
 
  for (part_id= first; partitions_called < num_used_parts ; part_id++)
6311
 
  {
6312
 
    if (!bitmap_is_set(&(m_part_info->used_partitions), part_id))
6313
 
      continue;
6314
 
    scan_time+= m_file[part_id]->scan_time();
6315
 
    partitions_called++;
6316
 
    if (partitions_called >= check_min_num && scan_time != 0.0)
6317
 
    {
6318
 
      DBUG_RETURN(scan_time *
6319
 
                      (double) num_used_parts / (double) partitions_called);
6320
 
    }
6321
 
  }
 
6400
  for (file= m_file; *file; file++)
 
6401
    if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
 
6402
      scan_time+= (*file)->scan_time();
6322
6403
  DBUG_RETURN(scan_time);
6323
6404
}
6324
6405
 
6325
6406
 
6326
 
/*
6327
 
  Estimate rows for records_in_range or estimate_rows_upper_bound.
6328
 
 
6329
 
  @param is_records_in_range  call records_in_range instead of
6330
 
                              estimate_rows_upper_bound.
6331
 
  @param inx                  (only for records_in_range) index to use.
6332
 
  @param min_key              (only for records_in_range) start of range.
6333
 
  @param max_key              (only for records_in_range) end of range.
6334
 
 
6335
 
  @return Number of rows or HA_POS_ERROR.
 
6407
/**
 
6408
  Find number of records in a range.
 
6409
  @param inx      Index number
 
6410
  @param min_key  Start of range
 
6411
  @param max_key  End of range
 
6412
 
 
6413
  @return Number of rows in range.
 
6414
 
 
6415
  Given a starting key, and an ending key estimate the number of rows that
 
6416
  will exist between the two. max_key may be empty which in case determine
 
6417
  if start_key matches any rows.
6336
6418
*/
6337
 
ha_rows ha_partition::estimate_rows(bool is_records_in_range, uint inx,
6338
 
                                    key_range *min_key, key_range *max_key)
 
6419
 
 
6420
ha_rows ha_partition::records_in_range(uint inx, key_range *min_key,
 
6421
                                       key_range *max_key)
6339
6422
{
6340
 
  ha_rows rows, estimated_rows= 0;
6341
 
  uint first, part_id, num_used_parts, check_min_num, partitions_called= 0;
 
6423
  ha_rows min_rows_to_check, rows, estimated_rows=0, checked_rows= 0;
 
6424
  uint partition_index= 0, part_id;
6342
6425
  DBUG_ENTER("ha_partition::records_in_range");
6343
6426
 
6344
 
  partitions_optimizer_call_preparations(&first, &num_used_parts, &check_min_num);
6345
 
  for (part_id= first; partitions_called < num_used_parts ; part_id++)
 
6427
  min_rows_to_check= min_rows_for_estimate();
 
6428
 
 
6429
  while ((part_id= get_biggest_used_partition(&partition_index))
 
6430
         != NO_CURRENT_PART_ID)
6346
6431
  {
6347
 
    if (!bitmap_is_set(&(m_part_info->used_partitions), part_id))
6348
 
      continue;
6349
 
    if (is_records_in_range)
6350
 
      rows= m_file[part_id]->records_in_range(inx, min_key, max_key);
6351
 
    else
6352
 
      rows= m_file[part_id]->estimate_rows_upper_bound();
 
6432
    rows= m_file[part_id]->records_in_range(inx, min_key, max_key);
 
6433
      
 
6434
    DBUG_PRINT("info", ("part %u match %lu rows of %lu", part_id, (ulong) rows,
 
6435
                        (ulong) m_file[part_id]->stats.records));
 
6436
 
6353
6437
    if (rows == HA_POS_ERROR)
6354
6438
      DBUG_RETURN(HA_POS_ERROR);
6355
6439
    estimated_rows+= rows;
6356
 
    partitions_called++;
6357
 
    if (partitions_called >= check_min_num && estimated_rows)
 
6440
    checked_rows+= m_file[part_id]->stats.records;
 
6441
    /*
 
6442
      Returning 0 means no rows can be found, so we must continue
 
6443
      this loop as long as we have estimated_rows == 0.
 
6444
      Also many engines return 1 to indicate that there may exist
 
6445
      a matching row, we do not normalize this by dividing by number of
 
6446
      used partitions, but leave it to be returned as a sum, which will
 
6447
      reflect that we will need to scan each partition's index.
 
6448
 
 
6449
      Note that this statistics may not always be correct, so we must
 
6450
      continue even if the current partition has 0 rows, since we might have
 
6451
      deleted rows from the current partition, or inserted to the next
 
6452
      partition.
 
6453
    */
 
6454
    if (estimated_rows && checked_rows &&
 
6455
        checked_rows >= min_rows_to_check)
6358
6456
    {
6359
 
      DBUG_RETURN(estimated_rows * num_used_parts / partitions_called);
 
6457
      DBUG_PRINT("info",
 
6458
                 ("records_in_range(inx %u): %lu (%lu * %lu / %lu)",
 
6459
                  inx,
 
6460
                  (ulong) (estimated_rows * stats.records / checked_rows),
 
6461
                  (ulong) estimated_rows,
 
6462
                  (ulong) stats.records,
 
6463
                  (ulong) checked_rows));
 
6464
      DBUG_RETURN(estimated_rows * stats.records / checked_rows);
6360
6465
    }
6361
6466
  }
 
6467
  DBUG_PRINT("info", ("records_in_range(inx %u): %lu",
 
6468
                      inx,
 
6469
                      (ulong) estimated_rows));
6362
6470
  DBUG_RETURN(estimated_rows);
6363
6471
}
6364
6472
 
6365
6473
 
6366
 
/*
6367
 
  Find number of records in a range
6368
 
 
6369
 
  SYNOPSIS
6370
 
    records_in_range()
6371
 
    inx                  Index number
6372
 
    min_key              Start of range
6373
 
    max_key              End of range
6374
 
 
6375
 
  RETURN VALUE
6376
 
    Number of rows in range
6377
 
 
6378
 
  DESCRIPTION
6379
 
    Given a starting key, and an ending key estimate the number of rows that
6380
 
    will exist between the two. end_key may be empty which in case determine
6381
 
    if start_key matches any rows.
6382
 
 
6383
 
    Called from opt_range.cc by check_quick_keys().
6384
 
 
6385
 
    monty: MUST be called for each range and added.
6386
 
          Note that MySQL will assume that if this returns 0 there is no
6387
 
          matching rows for the range!
6388
 
*/
6389
 
 
6390
 
ha_rows ha_partition::records_in_range(uint inx, key_range *min_key,
6391
 
                                       key_range *max_key)
6392
 
{
6393
 
  DBUG_ENTER("ha_partition::records_in_range");
6394
 
 
6395
 
  DBUG_RETURN(estimate_rows(TRUE, inx, min_key, max_key));
6396
 
}
6397
 
 
6398
 
 
6399
 
/*
6400
 
  Estimate upper bound of number of rows
6401
 
 
6402
 
  SYNOPSIS
6403
 
    estimate_rows_upper_bound()
6404
 
 
6405
 
  RETURN VALUE
6406
 
    Number of rows
 
6474
/**
 
6475
  Estimate upper bound of number of rows.
 
6476
 
 
6477
  @return Number of rows.
6407
6478
*/
6408
6479
 
6409
6480
ha_rows ha_partition::estimate_rows_upper_bound()
6410
6481
{
 
6482
  ha_rows rows, tot_rows= 0;
 
6483
  handler **file= m_file;
6411
6484
  DBUG_ENTER("ha_partition::estimate_rows_upper_bound");
6412
6485
 
6413
 
  DBUG_RETURN(estimate_rows(FALSE, 0, NULL, NULL));
 
6486
  do
 
6487
  {
 
6488
    if (bitmap_is_set(&(m_part_info->used_partitions), (file - m_file)))
 
6489
    {
 
6490
      rows= (*file)->estimate_rows_upper_bound();
 
6491
      if (rows == HA_POS_ERROR)
 
6492
        DBUG_RETURN(HA_POS_ERROR);
 
6493
      tot_rows+= rows;
 
6494
    }
 
6495
  } while (*(++file));
 
6496
  DBUG_RETURN(tot_rows);
6414
6497
}
6415
6498
 
6416
6499