~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/handler.cc

  • Committer: Brian Aker
  • Date: 2009-07-28 23:44:32 UTC
  • mfrom: (1100.1.6 merge)
  • Revision ID: brian@gaz-20090728234432-t5hpryg40a4rz20b
Removal of all basic MRR

Show diffs side-by-side

added added

removed removed

Lines of Context:
2495
2495
}
2496
2496
 
2497
2497
 
2498
 
/* **************************************************************************
2499
 
 * DS-MRR implementation
2500
 
 ***************************************************************************/
2501
 
 
2502
 
/**
2503
 
  DS-MRR: Initialize and start MRR scan
2504
 
 
2505
 
  Initialize and start the MRR scan. Depending on the mode parameter, this
2506
 
  may use default or DS-MRR implementation.
2507
 
 
2508
 
  @param h               Table handler to be used
2509
 
  @param key             Index to be used
2510
 
  @param seq_funcs       Interval sequence enumeration functions
2511
 
  @param seq_init_param  Interval sequence enumeration parameter
2512
 
  @param n_ranges        Number of ranges in the sequence.
2513
 
  @param mode            HA_MRR_* modes to use
2514
 
  @param buf             INOUT Buffer to use
2515
 
 
2516
 
  @retval 0     Ok, Scan started.
2517
 
  @retval other Error
2518
 
*/
2519
 
 
2520
 
int DsMrr_impl::dsmrr_init(handler *h_in, KEY *key,
2521
 
                           RANGE_SEQ_IF *seq_funcs, void *seq_init_param,
2522
 
                           uint32_t n_ranges, uint32_t mode, HANDLER_BUFFER *buf)
2523
 
{
2524
 
  uint32_t elem_size;
2525
 
  uint32_t keyno;
2526
 
  Item *pushed_cond= NULL;
2527
 
  handler *new_h2;
2528
 
  keyno= h_in->active_index;
2529
 
  assert(h2 == NULL);
2530
 
  if (mode & HA_MRR_USE_DEFAULT_IMPL || mode & HA_MRR_SORTED)
2531
 
  {
2532
 
    use_default_impl= true;
2533
 
    return(h_in->handler::multi_range_read_init(seq_funcs, seq_init_param,
2534
 
                                                  n_ranges, mode, buf));
2535
 
  }
2536
 
  rowids_buf= buf->buffer;
2537
 
  //psergey-todo: don't add key_length as it is not needed anymore
2538
 
  rowids_buf += key->key_length + h_in->ref_length;
2539
 
 
2540
 
  is_mrr_assoc= !test(mode & HA_MRR_NO_ASSOCIATION);
2541
 
  rowids_buf_end= buf->buffer_end;
2542
 
 
2543
 
  elem_size= h_in->ref_length + (int)is_mrr_assoc * sizeof(void*);
2544
 
  rowids_buf_last= rowids_buf +
2545
 
                      ((rowids_buf_end - rowids_buf)/ elem_size)*
2546
 
                      elem_size;
2547
 
  rowids_buf_end= rowids_buf_last;
2548
 
 
2549
 
  /* Create a separate handler object to do rndpos() calls. */
2550
 
  Session *session= current_session;
2551
 
  if (!(new_h2= h_in->clone(session->mem_root)) ||
2552
 
      new_h2->ha_external_lock(session, F_RDLCK))
2553
 
  {
2554
 
    delete new_h2;
2555
 
    return 1;
2556
 
  }
2557
 
 
2558
 
  if (keyno == h_in->pushed_idx_cond_keyno)
2559
 
    pushed_cond= h_in->pushed_idx_cond;
2560
 
  if (h_in->ha_index_end())
2561
 
  {
2562
 
    new_h2= h2;
2563
 
    goto error;
2564
 
  }
2565
 
 
2566
 
  h2= new_h2;
2567
 
  table->prepare_for_position();
2568
 
  new_h2->extra(HA_EXTRA_KEYREAD);
2569
 
 
2570
 
  if (h2->ha_index_init(keyno, false) ||
2571
 
      h2->handler::multi_range_read_init(seq_funcs, seq_init_param, n_ranges,
2572
 
                                         mode, buf))
2573
 
    goto error;
2574
 
  use_default_impl= false;
2575
 
 
2576
 
  if (pushed_cond)
2577
 
    h2->idx_cond_push(keyno, pushed_cond);
2578
 
  if (dsmrr_fill_buffer(new_h2))
2579
 
    goto error;
2580
 
 
2581
 
  /*
2582
 
    If the above call has scanned through all intervals in *seq, then
2583
 
    adjust *buf to indicate that the remaining buffer space will not be used.
2584
 
  */
2585
 
  if (dsmrr_eof)
2586
 
    buf->end_of_used_area= rowids_buf_last;
2587
 
 
2588
 
  if (h_in->ha_rnd_init(false))
2589
 
    goto error;
2590
 
 
2591
 
  return 0;
2592
 
error:
2593
 
  h2->ha_index_or_rnd_end();
2594
 
  h2->ha_external_lock(session, F_UNLCK);
2595
 
  h2->close();
2596
 
  delete h2;
2597
 
  return 1;
2598
 
}
2599
 
 
2600
 
 
2601
 
void DsMrr_impl::dsmrr_close()
2602
 
{
2603
 
  if (h2)
2604
 
  {
2605
 
    h2->ha_external_lock(current_session, F_UNLCK);
2606
 
    h2->close();
2607
 
    delete h2;
2608
 
    h2= NULL;
2609
 
  }
2610
 
  use_default_impl= true;
2611
 
}
2612
 
 
2613
 
 
2614
 
static int rowid_cmp(void *h, unsigned char *a, unsigned char *b)
2615
 
{
2616
 
  return ((handler*)h)->cmp_ref(a, b);
2617
 
}
2618
 
 
2619
 
 
2620
 
/**
2621
 
  DS-MRR: Fill the buffer with rowids and sort it by rowid
2622
 
 
2623
 
  {This is an internal function of DiskSweep MRR implementation}
2624
 
  Scan the MRR ranges and collect ROWIDs (or {ROWID, range_id} pairs) into
2625
 
  buffer. When the buffer is full or scan is completed, sort the buffer by
2626
 
  rowid and return.
2627
 
 
2628
 
  The function assumes that rowids buffer is empty when it is invoked.
2629
 
 
2630
 
  @param h  Table handler
2631
 
 
2632
 
  @retval 0      OK, the next portion of rowids is in the buffer,
2633
 
                 properly ordered
2634
 
  @retval other  Error
2635
 
*/
2636
 
 
2637
 
int DsMrr_impl::dsmrr_fill_buffer(handler *)
2638
 
{
2639
 
  char *range_info;
2640
 
  int res = 0;
2641
 
 
2642
 
  rowids_buf_cur= rowids_buf;
2643
 
  while ((rowids_buf_cur < rowids_buf_end) &&
2644
 
         !(res= h2->handler::multi_range_read_next(&range_info)))
2645
 
  {
2646
 
    /* Put rowid, or {rowid, range_id} pair into the buffer */
2647
 
    h2->position(table->record[0]);
2648
 
    memcpy(rowids_buf_cur, h2->ref, h2->ref_length);
2649
 
    rowids_buf_cur += h->ref_length;
2650
 
 
2651
 
    if (is_mrr_assoc)
2652
 
    {
2653
 
      memcpy(rowids_buf_cur, &range_info, sizeof(void*));
2654
 
      rowids_buf_cur += sizeof(void*);
2655
 
    }
2656
 
  }
2657
 
 
2658
 
  if (res && res != HA_ERR_END_OF_FILE)
2659
 
    return res;
2660
 
  dsmrr_eof= test(res == HA_ERR_END_OF_FILE);
2661
 
 
2662
 
  /* Sort the buffer contents by rowid */
2663
 
  uint32_t elem_size= h->ref_length + (int)is_mrr_assoc * sizeof(void*);
2664
 
  uint32_t n_rowids= (rowids_buf_cur - rowids_buf) / elem_size;
2665
 
 
2666
 
  my_qsort2(rowids_buf, n_rowids, elem_size, (qsort2_cmp)rowid_cmp,
2667
 
            (void*)h);
2668
 
  rowids_buf_last= rowids_buf_cur;
2669
 
  rowids_buf_cur=  rowids_buf;
2670
 
  return 0;
2671
 
}
2672
 
 
2673
 
 
2674
 
/**
2675
 
  DS-MRR implementation: multi_range_read_next() function
2676
 
*/
2677
 
 
2678
 
int DsMrr_impl::dsmrr_next(handler *h_in, char **range_info)
2679
 
{
2680
 
  int res;
2681
 
 
2682
 
  if (use_default_impl)
2683
 
    return h_in->handler::multi_range_read_next(range_info);
2684
 
 
2685
 
  if (rowids_buf_cur == rowids_buf_last)
2686
 
  {
2687
 
    if (dsmrr_eof)
2688
 
    {
2689
 
      res= HA_ERR_END_OF_FILE;
2690
 
      goto end;
2691
 
    }
2692
 
    res= dsmrr_fill_buffer(h);
2693
 
    if (res)
2694
 
      goto end;
2695
 
  }
2696
 
 
2697
 
  /* Return EOF if there are no rowids in the buffer after re-fill attempt */
2698
 
  if (rowids_buf_cur == rowids_buf_last)
2699
 
  {
2700
 
    res= HA_ERR_END_OF_FILE;
2701
 
    goto end;
2702
 
  }
2703
 
 
2704
 
  res= h_in->rnd_pos(table->record[0], rowids_buf_cur);
2705
 
  rowids_buf_cur += h_in->ref_length;
2706
 
  if (is_mrr_assoc)
2707
 
  {
2708
 
    memcpy(range_info, rowids_buf_cur, sizeof(void*));
2709
 
    rowids_buf_cur += sizeof(void*);
2710
 
  }
2711
 
 
2712
 
end:
2713
 
  if (res)
2714
 
    dsmrr_close();
2715
 
  return res;
2716
 
}
2717
 
 
2718
 
 
2719
 
/**
2720
 
  DS-MRR implementation: multi_range_read_info() function
2721
 
*/
2722
 
int DsMrr_impl::dsmrr_info(uint32_t keyno, uint32_t n_ranges, uint32_t rows, uint32_t *bufsz,
2723
 
                           uint32_t *flags, COST_VECT *cost)
2724
 
{
2725
 
  int res;
2726
 
  uint32_t def_flags= *flags;
2727
 
  uint32_t def_bufsz= *bufsz;
2728
 
 
2729
 
  /* Get cost/flags/mem_usage of default MRR implementation */
2730
 
  res= h->handler::multi_range_read_info(keyno, n_ranges, rows, &def_bufsz,
2731
 
                                         &def_flags, cost);
2732
 
  assert(!res);
2733
 
 
2734
 
  if ((*flags & HA_MRR_USE_DEFAULT_IMPL) ||
2735
 
      choose_mrr_impl(keyno, rows, &def_flags, &def_bufsz, cost))
2736
 
  {
2737
 
    /* Default implementation is choosen */
2738
 
    *flags= def_flags;
2739
 
    *bufsz= def_bufsz;
2740
 
  }
2741
 
  return 0;
2742
 
}
2743
 
 
2744
 
 
2745
 
/**
2746
 
  DS-MRR Implementation: multi_range_read_info_const() function
2747
 
*/
2748
 
 
2749
 
ha_rows DsMrr_impl::dsmrr_info_const(uint32_t keyno, RANGE_SEQ_IF *seq,
2750
 
                                 void *seq_init_param, uint32_t n_ranges,
2751
 
                                 uint32_t *bufsz, uint32_t *flags, COST_VECT *cost)
2752
 
{
2753
 
  ha_rows rows;
2754
 
  uint32_t def_flags= *flags;
2755
 
  uint32_t def_bufsz= *bufsz;
2756
 
  /* Get cost/flags/mem_usage of default MRR implementation */
2757
 
  rows= h->handler::multi_range_read_info_const(keyno, seq, seq_init_param,
2758
 
                                                n_ranges, &def_bufsz,
2759
 
                                                &def_flags, cost);
2760
 
  if (rows == HA_POS_ERROR)
2761
 
  {
2762
 
    /* Default implementation can't perform MRR scan => we can't either */
2763
 
    return rows;
2764
 
  }
2765
 
 
2766
 
  /*
2767
 
    If HA_MRR_USE_DEFAULT_IMPL has been passed to us, that is an order to
2768
 
    use the default MRR implementation (we need it for UPDATE/DELETE).
2769
 
    Otherwise, make a choice based on cost and @@optimizer_use_mrr.
2770
 
  */
2771
 
  if ((*flags & HA_MRR_USE_DEFAULT_IMPL) ||
2772
 
      choose_mrr_impl(keyno, rows, flags, bufsz, cost))
2773
 
  {
2774
 
    *flags= def_flags;
2775
 
    *bufsz= def_bufsz;
2776
 
  }
2777
 
  else
2778
 
  {
2779
 
    *flags &= ~HA_MRR_USE_DEFAULT_IMPL;
2780
 
  }
2781
 
  return rows;
2782
 
}
2783
 
 
2784
 
 
2785
 
/**
2786
 
  Check if key has partially-covered columns
2787
 
 
2788
 
  We can't use DS-MRR to perform range scans when the ranges are over
2789
 
  partially-covered keys, because we'll not have full key part values
2790
 
  (we'll have their prefixes from the index) and will not be able to check
2791
 
  if we've reached the end the range.
2792
 
 
2793
 
  @param keyno  Key to check
2794
 
 
2795
 
  @todo
2796
 
    Allow use of DS-MRR in cases where the index has partially-covered
2797
 
    components but they are not used for scanning.
2798
 
 
2799
 
  @retval true   Yes
2800
 
  @retval false  No
2801
 
*/
2802
 
 
2803
 
bool DsMrr_impl::key_uses_partial_cols(uint32_t keyno)
2804
 
{
2805
 
  KEY_PART_INFO *kp= table->key_info[keyno].key_part;
2806
 
  KEY_PART_INFO *kp_end= kp + table->key_info[keyno].key_parts;
2807
 
  for (; kp != kp_end; kp++)
2808
 
  {
2809
 
    if (!kp->field->part_of_key.test(keyno))
2810
 
      return true;
2811
 
  }
2812
 
  return false;
2813
 
}
2814
 
 
2815
 
 
2816
 
/**
2817
 
  DS-MRR Internals: Choose between Default MRR implementation and DS-MRR
2818
 
 
2819
 
  Make the choice between using Default MRR implementation and DS-MRR.
2820
 
  This function contains common functionality factored out of dsmrr_info()
2821
 
  and dsmrr_info_const(). The function assumes that the default MRR
2822
 
  implementation's applicability requirements are satisfied.
2823
 
 
2824
 
  @param keyno       Index number
2825
 
  @param rows        E(full rows to be retrieved)
2826
 
  @param flags  IN   MRR flags provided by the MRR user
2827
 
                OUT  If DS-MRR is choosen, flags of DS-MRR implementation
2828
 
                     else the value is not modified
2829
 
  @param bufsz  IN   If DS-MRR is choosen, buffer use of DS-MRR implementation
2830
 
                     else the value is not modified
2831
 
  @param cost   IN   Cost of default MRR implementation
2832
 
                OUT  If DS-MRR is choosen, cost of DS-MRR scan
2833
 
                     else the value is not modified
2834
 
 
2835
 
  @retval true   Default MRR implementation should be used
2836
 
  @retval false  DS-MRR implementation should be used
2837
 
*/
2838
 
 
2839
 
bool DsMrr_impl::choose_mrr_impl(uint32_t keyno, ha_rows rows, uint32_t *flags,
2840
 
                                 uint32_t *bufsz, COST_VECT *cost)
2841
 
{
2842
 
  COST_VECT dsmrr_cost;
2843
 
  bool res;
2844
 
  Session *session= current_session;
2845
 
  if ((session->variables.optimizer_use_mrr == 2) ||
2846
 
      (*flags & HA_MRR_INDEX_ONLY) || (*flags & HA_MRR_SORTED) ||
2847
 
      (keyno == table->s->primary_key &&
2848
 
       h->primary_key_is_clustered()) ||
2849
 
       key_uses_partial_cols(keyno))
2850
 
  {
2851
 
    /* Use the default implementation */
2852
 
    *flags |= HA_MRR_USE_DEFAULT_IMPL;
2853
 
    return true;
2854
 
  }
2855
 
 
2856
 
  uint32_t add_len= table->key_info[keyno].key_length + h->ref_length;
2857
 
  *bufsz -= add_len;
2858
 
  if (get_disk_sweep_mrr_cost(keyno, rows, *flags, bufsz, &dsmrr_cost))
2859
 
    return true;
2860
 
  *bufsz += add_len;
2861
 
 
2862
 
  bool force_dsmrr;
2863
 
  /*
2864
 
    If @@optimizer_use_mrr==force, then set cost of DS-MRR to be minimum of
2865
 
    DS-MRR and Default implementations cost. This allows one to force use of
2866
 
    DS-MRR whenever it is applicable without affecting other cost-based
2867
 
    choices.
2868
 
  */
2869
 
  if ((force_dsmrr= (session->variables.optimizer_use_mrr == 1)) &&
2870
 
      dsmrr_cost.total_cost() > cost->total_cost())
2871
 
    dsmrr_cost= *cost;
2872
 
 
2873
 
  if (force_dsmrr || dsmrr_cost.total_cost() <= cost->total_cost())
2874
 
  {
2875
 
    *flags &= ~HA_MRR_USE_DEFAULT_IMPL;  /* Use the DS-MRR implementation */
2876
 
    *flags &= ~HA_MRR_SORTED;          /* We will return unordered output */
2877
 
    *cost= dsmrr_cost;
2878
 
    res= false;
2879
 
  }
2880
 
  else
2881
 
  {
2882
 
    /* Use the default MRR implementation */
2883
 
    res= true;
2884
 
  }
2885
 
  return res;
2886
 
}
2887
 
 
2888
 
 
2889
 
static void get_sort_and_sweep_cost(Table *table, ha_rows nrows, COST_VECT *cost);
2890
 
 
2891
 
 
2892
 
/**
2893
 
  Get cost of DS-MRR scan
2894
 
 
2895
 
  @param keynr              Index to be used
2896
 
  @param rows               E(Number of rows to be scanned)
2897
 
  @param flags              Scan parameters (HA_MRR_* flags)
2898
 
  @param buffer_size INOUT  Buffer size
2899
 
  @param cost        OUT    The cost
2900
 
 
2901
 
  @retval false  OK
2902
 
  @retval true   Error, DS-MRR cannot be used (the buffer is too small
2903
 
                 for even 1 rowid)
2904
 
*/
2905
 
 
2906
 
bool DsMrr_impl::get_disk_sweep_mrr_cost(uint32_t keynr, ha_rows rows, uint32_t flags,
2907
 
                                         uint32_t *buffer_size, COST_VECT *cost)
2908
 
{
2909
 
  uint32_t max_buff_entries, elem_size;
2910
 
  ha_rows rows_in_full_step, rows_in_last_step;
2911
 
  uint32_t n_full_steps;
2912
 
  double index_read_cost;
2913
 
 
2914
 
  elem_size= h->ref_length + sizeof(void*) * (!test(flags & HA_MRR_NO_ASSOCIATION));
2915
 
  max_buff_entries = *buffer_size / elem_size;
2916
 
 
2917
 
  if (!max_buff_entries)
2918
 
    return true; /* Buffer has not enough space for even 1 rowid */
2919
 
 
2920
 
  /* Number of iterations we'll make with full buffer */
2921
 
  n_full_steps= (uint32_t)floor(rows2double(rows) / max_buff_entries);
2922
 
 
2923
 
  /*
2924
 
    Get numbers of rows we'll be processing in
2925
 
     - non-last sweep, with full buffer
2926
 
     - last iteration, with non-full buffer
2927
 
  */
2928
 
  rows_in_full_step= max_buff_entries;
2929
 
  rows_in_last_step= rows % max_buff_entries;
2930
 
 
2931
 
  /* Adjust buffer size if we expect to use only part of the buffer */
2932
 
  if (n_full_steps)
2933
 
  {
2934
 
    get_sort_and_sweep_cost(table, rows, cost);
2935
 
    cost->multiply(n_full_steps);
2936
 
  }
2937
 
  else
2938
 
  {
2939
 
    cost->zero();
2940
 
    *buffer_size= max(*buffer_size,
2941
 
                      (uint32_t)(1.2*rows_in_last_step) * elem_size +
2942
 
                      h->ref_length + table->key_info[keynr].key_length);
2943
 
  }
2944
 
 
2945
 
  COST_VECT last_step_cost;
2946
 
  get_sort_and_sweep_cost(table, rows_in_last_step, &last_step_cost);
2947
 
  cost->add(&last_step_cost);
2948
 
 
2949
 
  if (n_full_steps != 0)
2950
 
    cost->mem_cost= *buffer_size;
2951
 
  else
2952
 
    cost->mem_cost= (double)rows_in_last_step * elem_size;
2953
 
 
2954
 
  /* Total cost of all index accesses */
2955
 
  index_read_cost= h->index_only_read_time(keynr, (double)rows);
2956
 
  cost->add_io(index_read_cost, 1 /* Random seeks */);
2957
 
  return false;
2958
 
}
2959
 
 
2960
 
#ifndef HAVE_LOG2
2961
 
#define log2(x)  (log(x) / M_LN2)
2962
 
#endif
2963
 
 
2964
 
/*
2965
 
  Get cost of one sort-and-sweep step
2966
 
 
2967
 
  SYNOPSIS
2968
 
    get_sort_and_sweep_cost()
2969
 
      table       Table being accessed
2970
 
      nrows       Number of rows to be sorted and retrieved
2971
 
      cost   OUT  The cost
2972
 
 
2973
 
  DESCRIPTION
2974
 
    Get cost of these operations:
2975
 
     - sort an array of #nrows ROWIDs using qsort
2976
 
     - read #nrows records from table in a sweep.
2977
 
*/
2978
 
 
2979
 
static
2980
 
void get_sort_and_sweep_cost(Table *table, ha_rows nrows, COST_VECT *cost)
2981
 
{
2982
 
  if (nrows)
2983
 
  {
2984
 
    get_sweep_read_cost(table, nrows, false, cost);
2985
 
    /* Add cost of qsort call: n * log2(n) * cost(rowid_comparison) */
2986
 
    double cmp_op= rows2double(nrows) * (1.0 / TIME_FOR_COMPARE_ROWID);
2987
 
    if (cmp_op < 3)
2988
 
      cmp_op= 3;
2989
 
    cost->cpu_cost += cmp_op * log2(cmp_op);
2990
 
  }
2991
 
  else
2992
 
    cost->zero();
2993
 
}
2994
 
 
2995
 
 
2996
2498
/**
2997
2499
  Get cost of reading nrows table records in a "disk sweep"
2998
2500