Merge lp:~zephyrleaves/percona-server/row_cache into lp:percona-server/5.5

Proposed by Kevin.Huang
Status: Work in progress
Proposed branch: lp:~zephyrleaves/percona-server/row_cache
Merge into: lp:percona-server/5.5
Diff against target: 3321 lines (+3317/-0)
1 file modified
patches/innodb_row_cache.diff (+3317/-0)
To merge this branch: bzr merge lp:~zephyrleaves/percona-server/row_cache
Reviewer Review Type Date Requested Status
Oleg Tsarev Pending
Vadim Tkachenko Pending
Review via email: mp+88310@code.launchpad.net

Description of the change

Row Cache For Innodb is designed for increase memory utilization when query is Key-Value-like.

To solve the problem that it is mainly in popular data and popular data distribution is discrete cases Page in memory cache utilization rate is low.

Some detail can see : http://code.google.com/p/row-cache-for-innodb/

Benchmarks can use this sysbench which i modified for row cache scene.
http://code.google.com/p/row-cache-for-innodb/downloads/detail?name=sysbench-0.4.8.tar.gz&can=2&q=#makechanges

To post a comment you must log in.
Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

fix bug for memory leak on shutdown
fix bug for crash on rollback

206. By

fix bug for memory leak on shutdown
fix bug for crash on rollback

207. By Kevin.Huang

fix bug for row cache is not evict when truncate

Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

Kevin,

can you pls provide merge proposal against current lp:percona-server ?
We do not have patches anymore, this is full bzr branch now.

Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

ok,
it was easier than I thought, I ported it there
lp:~vadim-tk/percona-server/5.5.22-rowcache

Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

I have a problem with compiling current patch
"(byte*) key_val_buff" is not defined.

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> I have a problem with compiling current patch
> "(byte*) key_val_buff" is not defined.

I will fix it with 5.5.22.

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> I have a problem with compiling current patch
> "(byte*) key_val_buff" is not defined.

I fixed the compatibility problems for percona 5.5.22.
I ported it here
lp:~zephyrleaves/percona-server/5.5.22-rowcache

Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

I can't get good performance numbers with row cache.

I am running sysbench oltp, ZipF distribution, 100GB database, 16 threads

mysqld --innodb-buffer-pool-size=10GB --innodb-log-file-size=4G --innodb_flush_log_at_trx_commit=1 --innodb_row_cache_mem_pool_size=10GB --innodb_row_cache_on=ON

with innodb_row_cache_mem_pool_size=10GB the results is actually worse then with innodb_row_cache_mem_pool_size=5GB

and in any case it is worse then with no row cache at all.

I suspect it maybe a some mutex contention issue.

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> I can't get good performance numbers with row cache.
>
> I am running sysbench oltp, ZipF distribution, 100GB database, 16 threads
>
> mysqld --innodb-buffer-pool-size=10GB --innodb-log-file-size=4G
> --innodb_flush_log_at_trx_commit=1 --innodb_row_cache_mem_pool_size=10GB
> --innodb_row_cache_on=ON
>
> with innodb_row_cache_mem_pool_size=10GB the results is actually worse then
> with innodb_row_cache_mem_pool_size=5GB
>
> and in any case it is worse then with no row cache at all.
>
> I suspect it maybe a some mutex contention issue.

You need use this sysbench
http://code.google.com/p/row-cache-for-innodb/downloads/detail?name=sysbench-0.4.8.tar.gz
for test.
This sysbench which i modified for row cache's scene.
You can use command like this to run test:
sysbench --test=oltp --oltp-test-mode=simple --oltp-skip-trx=on --oltp-table-size=80000000 --oltp-range-size=1 --mysql-host=localhost --mysql-user=xx --mysql-password=xx --oltp-read-only=on --init-rng=on --num-threads=70 --oltp-dist-type=special --oltp-dist-pct=1 --oltp-dist-res=80 --max-requests=0 --max-time=1800 run

Because of the common sysbench's oltp-dist-type is not random enough.

Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

Kevin,

I am not sure what do you mean by "not random" enough.

I am using sysbench 0.5 with new zipf distribution.

In anycase I do not expect a performance degradation when I use bigger cache, but
this is what I see.

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> > I can't get good performance numbers with row cache.
> >
> > I am running sysbench oltp, ZipF distribution, 100GB database, 16 threads
> >
> > mysqld --innodb-buffer-pool-size=10GB --innodb-log-file-size=4G
> > --innodb_flush_log_at_trx_commit=1 --innodb_row_cache_mem_pool_size=10GB
> > --innodb_row_cache_on=ON
> >
> > with innodb_row_cache_mem_pool_size=10GB the results is actually worse then
> > with innodb_row_cache_mem_pool_size=5GB
> >
> > and in any case it is worse then with no row cache at all.
> >
> > I suspect it maybe a some mutex contention issue.
>
> You need use this sysbench
> http://code.google.com/p/row-cache-for-
> innodb/downloads/detail?name=sysbench-0.4.8.tar.gz
> for test.
> This sysbench which i modified for row cache's scene.
> You can use command like this to run test:
> sysbench --test=oltp --oltp-test-mode=simple --oltp-skip-trx=on --oltp-table-
> size=80000000 --oltp-range-size=1 --mysql-host=localhost --mysql-user=xx
> --mysql-password=xx --oltp-read-only=on --init-rng=on --num-threads=70 --oltp-
> dist-type=special --oltp-dist-pct=1 --oltp-dist-res=80 --max-requests=0 --max-
> time=1800 run
>
> Because of the common sysbench's oltp-dist-type is not random enough.

RowCache is good at for hot data and the hot data is distributed in random ,not continuous.

Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

Kevin,

How does that explain that with
--innodb-buffer-pool-size=10GB --innodb_row_cache_mem_pool_size=10GB

I am getting worse throughput then with
--innodb-buffer-pool-size=5GB --innodb_row_cache_mem_pool_size=5GB

Again, whatever distribution is, I do not expect to see worse results with bigger cache.

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> Kevin,
>
> I am not sure what do you mean by "not random" enough.
>
> I am using sysbench 0.5 with new zipf distribution.
>
> In anycase I do not expect a performance degradation when I use bigger cache,
> but
> this is what I see.

Vadim,

I see.
I will test in sysbench 0.5 with zipf.
And improve the row cache.

thanks.

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> > Kevin,
> >
> > I am not sure what do you mean by "not random" enough.
> >
> > I am using sysbench 0.5 with new zipf distribution.
> >
> > In anycase I do not expect a performance degradation when I use bigger
> cache,
> > but
> > this is what I see.
>
> Vadim,
>
> I see.
> I will test in sysbench 0.5 with zipf.
> And improve the row cache.
>
> thanks.

Hi Vadim,

Can you provide the command which you use to test the row cache with sysbench?

tks.

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> Kevin,
>
> How does that explain that with
> --innodb-buffer-pool-size=10GB --innodb_row_cache_mem_pool_size=10GB
>
> I am getting worse throughput then with
> --innodb-buffer-pool-size=5GB --innodb_row_cache_mem_pool_size=5GB
>
> Again, whatever distribution is, I do not expect to see worse results with
> bigger cache.

Hi Vadim,

I think i found the reason why bigger cache cause worse performance.
If you set bigger innodb-buffer-pool-size,accordingly you need set bigger innodb_row_cache_cell_num too.
I use hashtable to store the records , so bigger innodb-buffer-pool-size cause more records to store in the hashtable, and the hashtable is more deeper , it make worse performance.

So set the bigger innodb_row_cache_cell_num can make hashtable shallower, it can make better performance.

Revision history for this message
Vadim Tkachenko (vadim-tk) wrote :

Kevin,

command is
sysbench --test=tests/db/oltp.lua --oltp_tables_count=16 --oltp-table-size=$ROWS --rand-init=on --num-threads=$thread --oltp-read-only=off --report-interval=10 --rand-type=zipf --rand-zipf-t=0.9 --mysql-socket=/var/lib/mysql/mysql.sock --max-time=$RT --max-requests=0 --mysql-user=root --percentile=99 run

what value should I use for innodb_row_cache_cell_num ?

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> Kevin,
>
> command is
> sysbench --test=tests/db/oltp.lua --oltp_tables_count=16 --oltp-table-
> size=$ROWS --rand-init=on --num-threads=$thread --oltp-read-only=off
> --report-interval=10 --rand-type=zipf --rand-zipf-t=0.9 --mysql-
> socket=/var/lib/mysql/mysql.sock --max-time=$RT --max-requests=0 --mysql-
> user=root --percentile=99 run
>
> what value should I use for innodb_row_cache_cell_num ?

Vadim,

The default value of innodb_row_cache_cell_num is 10000.
You can set --innodb-buffer-pool-size=5GB --innodb_row_cache_mem_pool_size=5GB --innodb_row_cache_cell_num=10000
and set --innodb-buffer-pool-size=10GB --innodb_row_cache_mem_pool_size=10GB --innodb_row_cache_cell_num=20000
for test.

Revision history for this message
Stewart Smith (stewart) wrote :

On Mon, 14 May 2012 01:24:17 -0000, "Kevin.Huang" <email address hidden> wrote:
> The default value of innodb_row_cache_cell_num is 10000.
> You can set --innodb-buffer-pool-size=5GB --innodb_row_cache_mem_pool_size=5GB --innodb_row_cache_cell_num=10000
> and set --innodb-buffer-pool-size=10GB --innodb_row_cache_mem_pool_size=10GB --innodb_row_cache_cell_num=20000
> for test.

I suggest perhaps having a sensible default calculation for it, maybe
1000/GB of row cache? does that seems sensible?

--
Stewart Smith

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> On Mon, 14 May 2012 01:24:17 -0000, "Kevin.Huang" <email address hidden>
> wrote:
> > The default value of innodb_row_cache_cell_num is 10000.
> > You can set --innodb-buffer-pool-size=5GB
> --innodb_row_cache_mem_pool_size=5GB --innodb_row_cache_cell_num=10000
> > and set --innodb-buffer-pool-size=10GB --innodb_row_cache_mem_pool_size=10GB
> --innodb_row_cache_cell_num=20000
> > for test.
>
> I suggest perhaps having a sensible default calculation for it, maybe
> 1000/GB of row cache? does that seems sensible?
>
> --
> Stewart Smith

Hi Stewart,

Innodb_row_cache_cell_num 's value depended on the size of the record which be cached by row cache.
The smaller record need more innodb_row_cache_cell_num for high performance, so i make it can be configured.

Revision history for this message
Stewart Smith (stewart) wrote :

On Wed, 16 May 2012 02:15:23 -0000, "Kevin.Huang" <email address hidden> wrote:
> Innodb_row_cache_cell_num 's value depended on the size of the record which be cached by row cache.
> The smaller record need more innodb_row_cache_cell_num for high performance, so i make it can be configured.

I completely understand, we do however see a lot of people who don't
know the intricacies of server configuration and will go with defaults
or something close to the default. Making it as easy for these people as
possible is a good feature, even if it may not be optimal for everyone
(people can change the variable by hand of course).

--
Stewart Smith

Revision history for this message
Kevin.Huang (zephyrleaves) wrote :

> On Wed, 16 May 2012 02:15:23 -0000, "Kevin.Huang" <email address hidden>
> wrote:
> > Innodb_row_cache_cell_num 's value depended on the size of the record which
> be cached by row cache.
> > The smaller record need more innodb_row_cache_cell_num for high performance,
> so i make it can be configured.
>
> I completely understand, we do however see a lot of people who don't
> know the intricacies of server configuration and will go with defaults
> or something close to the default. Making it as easy for these people as
> possible is a good feature, even if it may not be optimal for everyone
> (people can change the variable by hand of course).
>
> --
> Stewart Smith

Yeah, I will improve it ,the default value will be self-adaption ,and can be configured by people .

Unmerged revisions

207. By Kevin.Huang

fix bug for row cache is not evict when truncate

206. By

fix bug for memory leak on shutdown
fix bug for crash on rollback

205. By

fix bug for memory leak on shutdown
fix bug for crash on rollback

204. By Kevin.Huang

add row cache for innodb

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'patches/innodb_row_cache.diff'
2--- patches/innodb_row_cache.diff 1970-01-01 00:00:00 +0000
3+++ patches/innodb_row_cache.diff 2012-03-22 02:13:18 +0000
4@@ -0,0 +1,3317 @@
5+Index: storage/innobase/mtr/mtr0mtr.c
6+===================================================================
7+--- storage/innobase/mtr/mtr0mtr.c (revision 498)
8++++ storage/innobase/mtr/mtr0mtr.c (revision 724)
9+@@ -279,6 +279,11 @@
10+ }
11+ #endif /* UNIV_DEBUG_VALGRIND */
12+ ut_d(mtr->state = MTR_COMMITTED);
13++
14++ if (mtr->row_cache_value_queue_base.count > 0) {
15++ //release row cache value
16++ release_row_cache_value_in_mtr(mtr);
17++ }
18+ }
19+
20+ #ifndef UNIV_HOTBACKUP
21+Index: storage/innobase/cache/row0cache0lru.c
22+===================================================================
23+--- storage/innobase/cache/row0cache0lru.c (revision 0)
24++++ storage/innobase/cache/row0cache0lru.c (revision 724)
25+@@ -0,0 +1,155 @@
26++/********************************************************************
27++created: 2011/03/23
28++created: 23:3:2011 15:15
29++file base: row0cache0lru
30++file ext: c
31++author: wentong@taobao.com
32++
33++purpose:
34++*********************************************************************/
35++#include "row0cache0lru.h"
36++#include "row0cache0hash.h"
37++#include "row0cache0mempool.h"
38++#include "ut0rbt.h"
39++#include "ut0lst.h"
40++
41++#define ROW_CACHE_FREE_DISANCE 100
42++
43++static ROW_CACHE_VALUE_LIST_BASE *innodb_row_cache_lru;
44++
45++static row_cache_lru_stat_t _row_cache_lru_stat;
46++
47++UNIV_INTERN row_cache_lru_stat_t* row_cache_lru_stat = &_row_cache_lru_stat;
48++
49++UNIV_INTERN my_bool innodb_row_cache_clean_cache = FALSE;
50++
51++void init_innodb_row_cache_lru(){
52++ if (innodb_row_cache_mutex_num > 0){
53++ ulint i;
54++ innodb_row_cache_lru = (ROW_CACHE_VALUE_LIST_BASE*) ut_malloc(innodb_row_cache_mutex_num * sizeof(ROW_CACHE_VALUE_LIST_BASE));
55++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
56++ {
57++ UT_LIST_INIT(*(innodb_row_cache_lru+i));
58++ }
59++ }
60++ memset(row_cache_lru_stat , 0 , sizeof(row_cache_lru_stat_t));
61++}
62++
63++void deinit_innodb_row_cache_lru(){
64++ if (innodb_row_cache_mutex_num > 0){
65++ ulint i;
66++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
67++ {
68++ row_cache_value_t* value;
69++ ROW_CACHE_VALUE_LIST_BASE* free_lru = innodb_row_cache_lru + i;
70++ row_cache_enter_mutex_by_no(i);
71++ for (value = UT_LIST_GET_LAST(*free_lru);
72++ value!=NULL;){
73++ row_cache_value_t* free_value;
74++ ulint fold;
75++ free_value = value;
76++ fold = free_value->fold;
77++ value=UT_LIST_GET_PREV(list,value);
78++ UT_LIST_REMOVE(list,*free_lru,free_value);
79++ delete_row_cache_value(free_value);
80++ ca_free(free_value->buf ,free_value->buf_size ,fold);
81++ ca_free_for_value(free_value , fold);
82++ }
83++ row_cache_exit_mutex_by_no(i);
84++ }
85++ ut_free(innodb_row_cache_lru);
86++ }
87++}
88++
89++void clean_row_cache(){
90++ if (innodb_row_cache_mutex_num > 0){
91++ ulint i;
92++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
93++ {
94++ row_cache_value_t* value;
95++ ROW_CACHE_VALUE_LIST_BASE* free_lru = innodb_row_cache_lru + i;
96++ row_cache_enter_mutex_by_no(i);
97++ for (value = UT_LIST_GET_LAST(*free_lru);
98++ value!=NULL;){
99++ row_cache_value_t* free_value;
100++ ulint fold;
101++ free_value = value;
102++ fold = free_value->fold;
103++ value=UT_LIST_GET_PREV(list,value);
104++ if(free_value->ref_num==0){
105++ UT_LIST_REMOVE(list,*free_lru,free_value);
106++ delete_row_cache_value(free_value);
107++ ca_free(free_value->buf ,free_value->buf_size, fold);
108++ ca_free_for_value(free_value , fold);
109++ }
110++ }
111++ row_cache_exit_mutex_by_no(i);
112++ }
113++ }
114++}
115++
116++static ROW_CACHE_VALUE_LIST_BASE* get_current_lru_base(const ulint fold){
117++ return innodb_row_cache_lru + row_cache_get_mutex_no(fold);
118++}
119++
120++void add_row_cache_value_to_lru( row_cache_value_t* value ) {
121++ UT_LIST_ADD_FIRST(list,*get_current_lru_base(value->fold),value);
122++ row_cache_lru_stat->n_add++;
123++}
124++
125++void make_row_cache_value_first_from_lru( row_cache_value_t* value )
126++{
127++ ROW_CACHE_VALUE_LIST_BASE* lru_base = get_current_lru_base(value->fold);
128++ UT_LIST_REMOVE(list,*lru_base,value);
129++ UT_LIST_ADD_FIRST(list,*lru_base,value);
130++ row_cache_lru_stat->n_make_first++;
131++}
132++
133++ulint free_from_lru(const ulint size , const ulint used_fold)
134++{
135++ ulint iteration_size = 0;
136++ int free_distance = 0;
137++ ulint free_size = 0;
138++ row_cache_value_t* value;
139++ ROW_CACHE_VALUE_LIST_BASE* lru_base = get_current_lru_base(used_fold);
140++ for (value = UT_LIST_GET_LAST(*lru_base);
141++ free_distance < ROW_CACHE_FREE_DISANCE && value!=NULL;)
142++ {
143++ row_cache_value_t* free_value;
144++ free_value = value;
145++ value=UT_LIST_GET_PREV(list,value);
146++ iteration_size += free_value->buf_size;
147++ if(free_value->ref_num==0 && free_value->fold!=used_fold){
148++ //the value can't be used or can't be locked by the upper function
149++ UT_LIST_REMOVE(list,*lru_base,free_value);
150++ row_cache_lru_stat->n_evict++;
151++ free_size+=free_value->buf_size;
152++ delete_row_cache_value(free_value);
153++ ca_free(free_value->buf ,free_value->buf_size , used_fold);
154++ ca_free_for_value(free_value , used_fold);
155++ }
156++ if(iteration_size > size){
157++ //when may free enough mem and calc free distance
158++ free_distance++;
159++ }
160++ }
161++ return free_size;
162++}
163++
164++void remove_row_cache_value_from_lru( row_cache_value_t* value )
165++{
166++ UT_LIST_REMOVE(list,*get_current_lru_base(value->fold),value);
167++ row_cache_lru_stat->n_evict++;
168++}
169++
170++ulint get_row_cache_lru_count()
171++{
172++ ulint i;
173++ ulint ret = 0;
174++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
175++ {
176++ ret += UT_LIST_GET_LEN(*(innodb_row_cache_lru+i));
177++ }
178++ return ret;
179++}
180++
181+
182+Property changes on: storage/innobase/cache/row0cache0lru.c
183+___________________________________________________________________
184+Added: svn:mime-type
185+ + text/plain
186+
187+Index: storage/innobase/cache/row0cache0hash.c
188+===================================================================
189+--- storage/innobase/cache/row0cache0hash.c (revision 0)
190++++ storage/innobase/cache/row0cache0hash.c (revision 724)
191+@@ -0,0 +1,196 @@
192++/********************************************************************
193++created: 2011/03/24
194++created: 24:3:2011 8:49
195++file base: row0cache0hash
196++file ext: c
197++author: wentong@taobao.com
198++
199++purpose:
200++*********************************************************************/
201++
202++#include "row0cache0hash.h"
203++#include "ha0ha.h"
204++#include "hash0hash.h"
205++#include "rem0rec.h"
206++#include "rem0cmp.h"
207++#include "ut0byte.h"
208++
209++
210++
211++UNIV_INTERN unsigned long innodb_row_cache_cell_num = 10000L;
212++
213++UNIV_INTERN unsigned int innodb_row_cache_mutex_num_shift = 6;
214++
215++UNIV_INTERN ulint innodb_row_cache_mutex_num = 0;
216++
217++static row_cache_t _innodb_row_cache;
218++
219++UNIV_INTERN row_cache_t* innodb_row_cache = &_innodb_row_cache;
220++
221++int init_row_cache_hash(my_bool innodb_row_cache_on)
222++{
223++ memset(innodb_row_cache, 0 , sizeof(row_cache_t));
224++ if (innodb_row_cache_on)
225++ {
226++ innodb_row_cache_mutex_num = (1<<innodb_row_cache_mutex_num_shift);
227++ innodb_row_cache->row_cache = ha_create(innodb_row_cache_cell_num,innodb_row_cache_mutex_num,0);
228++
229++ }else{
230++ innodb_row_cache->row_cache = NULL;
231++ }
232++ return 0;
233++}
234++
235++static void free_hash_table_mutex(hash_table_t* table){
236++ //mutex was freed by sync_close();
237++ ulint i;
238++ for (i = 0; i < table->n_mutexes; i++) {
239++ mem_heap_free(table->heaps[i]);
240++ }
241++ mem_free(table->mutexes);
242++ table->mutexes = NULL;
243++ table->n_mutexes = 0;
244++ mem_free(table->heaps);
245++ table->heaps = NULL;
246++}
247++
248++void deinit_row_cache_hash(my_bool innodb_row_cache_on){
249++ if (innodb_row_cache_on)
250++ {
251++// ha_clear(innodb_row_cache->row_cache);
252++ free_hash_table_mutex(innodb_row_cache->row_cache);
253++ hash_table_free(innodb_row_cache->row_cache);
254++ }
255++}
256++
257++row_cache_value_t* search_row_cache_value(const dtuple_t* tuple, const dict_index_t* index, const ulint fold)
258++{
259++ ulint offsets_[REC_OFFS_NORMAL_SIZE];
260++ ulint* offsets = offsets_;
261++ mem_heap_t* heap = NULL;
262++ row_cache_chain_t* chain = NULL;
263++ rec_offs_init(offsets_);
264++
265++ HASH_SEARCH(
266++ /* hash_chain->"next" */
267++ next,
268++ /* the hash table */
269++ innodb_row_cache->row_cache,
270++ /* fold */
271++ fold,
272++ /* the type of the next variable */
273++ row_cache_chain_t*,
274++ /* auxiliary variable */
275++ chain,
276++ /* assertion on every traversed item */
277++ ,
278++ /* this determines if we have found the lock */
279++ (chain->value!=NULL && chain->value->tree_id == index->id && chain->value->table_id == index->table->id &&
280++ cmp_dtuple_rec(tuple,chain->value->rec,rec_get_offsets(chain->value->rec, index, offsets, ULINT_UNDEFINED, &heap)) == 0));
281++ if (UNIV_LIKELY_NULL(heap)) {
282++ mem_heap_free(heap);
283++ }
284++ if (chain == NULL) {
285++ return(NULL);
286++ }
287++ /* else */
288++ return(chain->value);
289++}
290++
291++
292++row_cache_value_t* search_row_cache_value_with_rec( const rec_t* rec, const ulint* rec_offsets, dict_index_t* index, const ulint fold )
293++{
294++ ulint offsets_[REC_OFFS_NORMAL_SIZE];
295++ ulint* offsets = offsets_;
296++ mem_heap_t* heap = NULL;
297++ row_cache_chain_t* chain = NULL;
298++ rec_offs_init(offsets_);
299++
300++ HASH_SEARCH(
301++ /* hash_chain->"next" */
302++ next,
303++ /* the hash table */
304++ innodb_row_cache->row_cache,
305++ /* fold */
306++ fold,
307++ /* the type of the next variable */
308++ row_cache_chain_t*,
309++ /* auxiliary variable */
310++ chain,
311++ /* assertion on every traversed item */
312++ ,
313++ /* this determines if we have found the lock */
314++ (chain->value!=NULL && chain->value->tree_id == index->id && chain->value->table_id == index->table->id &&
315++ cmp_rec_rec(rec,chain->value->rec,rec_offsets,rec_get_offsets(chain->value->rec, index, offsets, ULINT_UNDEFINED, &heap),index)==0));
316++
317++ if (UNIV_LIKELY_NULL(heap)) {
318++ mem_heap_free(heap);
319++ }
320++ if (chain == NULL) {
321++ return(NULL);
322++ }
323++ /* else */
324++ return(chain->value);
325++
326++}
327++
328++
329++
330++
331++row_cache_value_t* insert_row_cache_value(const ulint fold , row_cache_value_t* value){
332++ HASH_INSERT(
333++ /* the type used in the hash chain */
334++ row_cache_chain_t,
335++ /* hash_chain->"next" */
336++ next,
337++ /* the hash table */
338++ innodb_row_cache->row_cache,
339++ /* fold */
340++ fold,
341++ /* add this data to the hash */
342++ &value->chain);
343++ return value;
344++}
345++
346++
347++void delete_row_cache_value(row_cache_value_t* value){
348++ HASH_DELETE(
349++ row_cache_chain_t,
350++ next,
351++ innodb_row_cache->row_cache,
352++ value->fold,
353++ (&value->chain));
354++}
355++
356++void row_cache_enter_mutex_by_no(const ulint no){
357++ mutex_enter(hash_get_nth_mutex(innodb_row_cache->row_cache, no));
358++}
359++
360++void row_cache_exit_mutex_by_no(const ulint no){
361++ mutex_exit(hash_get_nth_mutex(innodb_row_cache->row_cache, no));
362++}
363++
364++void row_cache_enter_mutex( const ulint fold )
365++{
366++ hash_mutex_enter(innodb_row_cache->row_cache , fold);
367++}
368++
369++ulint row_cache_enter_mutex_nowait( const ulint fold )
370++{
371++ //hash_mutex_enter(innodb_row_cache->row_cache , fold);
372++ return mutex_enter_nowait(hash_get_mutex(innodb_row_cache->row_cache, fold));
373++}
374++
375++void row_cache_exit_mutex( const ulint fold )
376++{
377++ hash_mutex_exit(innodb_row_cache->row_cache , fold);
378++}
379++
380++int row_cache_own_mutex(const ulint fold1 , const ulint fold2){
381++ return hash_get_mutex_no(innodb_row_cache->row_cache , fold1) == hash_get_mutex_no(innodb_row_cache->row_cache , fold2);
382++}
383++
384++ulint row_cache_get_mutex_no( const ulint fold )
385++{
386++ return hash_get_mutex_no(innodb_row_cache->row_cache , fold);
387++}
388+
389+Property changes on: storage/innobase/cache/row0cache0hash.c
390+___________________________________________________________________
391+Added: svn:mime-type
392+ + text/plain
393+
394+Index: storage/innobase/cache/row0cache0filter.c
395+===================================================================
396+--- storage/innobase/cache/row0cache0filter.c (revision 0)
397++++ storage/innobase/cache/row0cache0filter.c (revision 724)
398+@@ -0,0 +1,295 @@
399++/********************************************************************
400++ created: 2011/05/31
401++ created: 31:5:2011 11:40
402++ file base: row0cache0filter
403++ file ext: c
404++ author: wentong@taobao.com
405++
406++ purpose:
407++ *********************************************************************/
408++
409++#include "row0cache0filter.h"
410++#include "ut0rbt.h"
411++#include "sync0rw.h"
412++#include "ut0lst.h"
413++#include "hash0hash.h"
414++#include "ut0rnd.h"
415++#include "dict0mem.h"
416++
417++#define FILTER_HASH_CELL_NUM 1000
418++
419++typedef struct row_cache_filter_index_chain row_cache_filter_index_chain_t;
420++typedef struct row_cache_filter_index_value row_cache_filter_index_value_t;
421++
422++struct row_cache_filter_index_chain {
423++ row_cache_filter_index_value_t* value;
424++ row_cache_filter_index_chain_t* next;
425++};
426++
427++struct row_cache_filter_index_value {
428++ index_id_t tree_id;
429++ row_cache_filter_index_chain_t chain;
430++};
431++
432++UNIV_INTERN char* innodb_row_cache_index = NULL;
433++
434++static char innodb_row_cache_index_r[INDEX_CONFIG_LEN + 1];
435++
436++static ibool has_filter = FALSE;
437++
438++static hash_table_t* filtered_in_index;
439++
440++static hash_table_t* filtered_out_index;
441++
442++#ifdef UNIV_PFS_RWLOCK
443++/* Key to register btr_search_sys with performance schema */
444++
445++UNIV_INTERN mysql_pfs_key_t row_cache_filter_lock_key;
446++#endif /* UNIV_PFS_RWLOCK */
447++
448++static rw_lock_t filter_lock;
449++
450++void reset_filter();
451++static int wild_case_compare_wl(const char *str, const char *wildstr,
452++ const size_t length);
453++static void free_hash_table_elem(hash_table_t* table);
454++
455++void init_row_cache_filter(my_bool innodb_row_cache_on) {
456++ if (innodb_row_cache_on) {
457++ rw_lock_create(row_cache_filter_lock_key, &filter_lock, SYNC_MEM_HASH);
458++ filtered_in_index = hash_create(FILTER_HASH_CELL_NUM);
459++ filtered_out_index = hash_create(FILTER_HASH_CELL_NUM);
460++ reset_filter();
461++ }
462++}
463++
464++void deinit_row_cache_filter(my_bool innodb_row_cache_on) {
465++ if (innodb_row_cache_on) {
466++ reset_filter();
467++ hash_table_free(filtered_in_index);
468++ hash_table_free(filtered_out_index);
469++ rw_lock_free(&filter_lock);
470++ }
471++}
472++
473++void reset_filter() {
474++ size_t len = 0;
475++ if (innodb_row_cache_index) {
476++ len = strlen(innodb_row_cache_index);
477++ }
478++ len = len > INDEX_CONFIG_LEN ? INDEX_CONFIG_LEN : len;
479++ rw_lock_x_lock(&filter_lock);
480++ memset(innodb_row_cache_index_r, 0, INDEX_CONFIG_LEN + 1);
481++ if (len) {
482++ ut_memcpy(innodb_row_cache_index_r, innodb_row_cache_index, len);
483++ }
484++ innodb_row_cache_index_r[len] = '\0';
485++ innodb_row_cache_index = innodb_row_cache_index_r;
486++
487++ free_hash_table_elem(filtered_in_index);
488++ free_hash_table_elem(filtered_out_index);
489++ if (!len) {
490++ has_filter = FALSE;
491++ } else {
492++ has_filter = TRUE;
493++ }
494++ rw_lock_x_unlock(&filter_lock);
495++}
496++
497++static void add_result_to_index_hash(ulint fold, index_id_t tree_id,
498++ my_bool is_in_filter) {
499++ hash_table_t* table;
500++ row_cache_filter_index_value_t* value;
501++ rw_lock_x_lock(&filter_lock);
502++ if (is_in_filter) {
503++ table = filtered_in_index;
504++ } else {
505++ table = filtered_out_index;
506++ }
507++ value =
508++ (row_cache_filter_index_value_t*) mem_alloc(sizeof(row_cache_filter_index_value_t));
509++ if (value) {
510++ value->tree_id = tree_id;
511++ value->chain.value = value;
512++ HASH_INSERT(
513++ /* the type used in the hash chain */
514++ row_cache_filter_index_chain_t,
515++ /* hash_chain->"next" */
516++ next,
517++ /* the hash table */
518++ table,
519++ /* fold */
520++ fold,
521++ /* add this data to the hash */
522++ &value->chain);
523++ }
524++ rw_lock_x_unlock(&filter_lock);
525++}
526++
527++static my_bool is_in_filter_index_hash(ulint fold, index_id_t tree_id,
528++ my_bool is_in_filter) {
529++ hash_table_t* table;
530++ row_cache_filter_index_chain_t* chain = NULL;
531++ if (is_in_filter) {
532++ table = filtered_in_index;
533++ } else {
534++ table = filtered_out_index;
535++ }HASH_SEARCH(
536++ /* hash_chain->"next" */
537++ next,
538++ /* the hash table */
539++ table,
540++ /* fold */
541++ fold,
542++ /* the type of the next variable */
543++ row_cache_filter_index_chain_t*,
544++ /* auxiliary variable */
545++ chain,
546++ /* assertion on every traversed item */
547++ ,
548++ /* this determines if we have found the lock */
549++ (chain->value!=NULL && chain->value->tree_id == tree_id));
550++ if (chain == NULL) {
551++ return (FALSE);
552++ }
553++ return (TRUE);
554++}
555++
556++static int wild_case_compare_wl(const char *str, const char *wildstr,
557++ const size_t length) {
558++ const char* start = wildstr;
559++ char wild_many = '*';
560++ char wild_one = '?';
561++ char wild_prefix = 0; /* QQ this can potentially cause a SIGSEGV */
562++ int flag;
563++ while ((size_t) (wildstr - start) < length) {
564++ while ((size_t) (wildstr - start) < length && *wildstr != wild_many
565++ && *wildstr != wild_one) {
566++ if (*wildstr == wild_prefix
567++ && (size_t) (wildstr + 1 - start) < length)
568++ wildstr++;
569++ if (toupper(*wildstr++) != toupper(*str++))
570++ return (1);
571++ }
572++ if ((size_t) (wildstr - start) >= length)
573++ return (*str != 0);
574++ if (*wildstr++ == wild_one) {
575++ if (!*str++)
576++ return (1); /* One char; skip */
577++ } else { /* Found '*' */
578++ if ((size_t) (wildstr - start) >= length)
579++ return (0); /* '*' as last char: OK */
580++ flag = (*wildstr != wild_many && *wildstr != wild_one);
581++ do {
582++ if (flag) {
583++ char cmp;
584++ if ((cmp = *wildstr) == wild_prefix
585++ && (size_t) (wildstr + 1 - start) < length)
586++ cmp = wildstr[1];
587++ cmp = toupper(cmp);
588++ while (*str && toupper(*str) != cmp)
589++ str++;
590++ if (!*str)
591++ return (1);
592++ }
593++ if (wild_case_compare_wl(str, wildstr,
594++ length - (wildstr - start)) == 0)
595++ return (0);
596++ } while (*str++);
597++ return (1);
598++ }
599++ }
600++ return (*str != '\0');
601++}
602++
603++static my_bool compare_index_config(const char* table_name,
604++ const char* index_name, const char* config) {
605++ char index_sp = ';';
606++ char table_sp = ':';
607++ my_bool is_index_now = FALSE;
608++ my_bool is_table_matching = FALSE;
609++ my_bool is_index_matching = FALSE;
610++ while (*config) {
611++ const char* o_config = config;
612++ size_t length = 0;
613++ while (*config && *config != index_sp && *config != table_sp) {
614++ config++;
615++ length++;
616++ }
617++ if (*config == table_sp) {
618++ if (!is_index_now) {
619++ is_table_matching = !wild_case_compare_wl(table_name, o_config,
620++ length);
621++ is_index_now = TRUE;
622++ } else if (is_table_matching) {
623++ is_index_matching = !wild_case_compare_wl(index_name, o_config,
624++ length);
625++ if (is_index_matching) {
626++ return TRUE;
627++ }
628++ }
629++ } else if (!*config || *config == index_sp) {
630++ if (is_index_now && is_table_matching) {
631++ is_index_matching = !wild_case_compare_wl(index_name, o_config,
632++ length);
633++ if (is_index_matching) {
634++ return TRUE;
635++ }
636++ }
637++ is_index_now = FALSE;
638++ is_table_matching = FALSE;
639++ is_index_matching = FALSE;
640++ }
641++ if (*config) {
642++ config++;
643++ }
644++ }
645++ return FALSE;
646++}
647++
648++static void free_hash_table_elem(hash_table_t* table) {
649++ ulint i;
650++ for (i = 0; i < table->n_cells; i++) {
651++ row_cache_filter_index_chain_t* chain =
652++ (row_cache_filter_index_chain_t*) HASH_GET_FIRST(table,i);
653++ while (chain != NULL) {
654++ row_cache_filter_index_value_t* value = chain->value;
655++ chain = chain->next;
656++ mem_free(value);
657++ }
658++ }
659++ hash_table_clear(table);
660++}
661++
662++#define index_id_get_high(id) ((ulint)(((id)>>32)&0xFFFFFFFF))
663++
664++#define index_id_get_low(id) ((ulint)((id)&0xFFFFFFFF))
665++
666++
667++my_bool is_index_need_cache(const dict_index_t* index) {
668++ const char* table_name = index->table_name;
669++ index_id_t index_id = index->id;
670++ const char* index_name = index->name;
671++ ulint fold = ut_fold_ulint_pair(index_id_get_high(index_id), index_id_get_low(index_id));
672++ my_bool is_in_hash = FALSE;
673++ my_bool ret;
674++ rw_lock_s_lock(&filter_lock);
675++ if (!has_filter) {
676++ is_in_hash = TRUE; //didn't need to be cache the result
677++ ret = TRUE;
678++ } else if (is_in_filter_index_hash(fold, index_id, TRUE)) {
679++ is_in_hash = TRUE;
680++ ret = TRUE;
681++ } else if (is_in_filter_index_hash(fold, index_id, FALSE)) {
682++ is_in_hash = TRUE;
683++ ret = FALSE;
684++ } else {
685++ ret = compare_index_config(table_name, index_name,
686++ innodb_row_cache_index_r);
687++ }rw_lock_s_unlock(&filter_lock);
688++ if (!is_in_hash) {
689++ add_result_to_index_hash(fold, index_id, ret);
690++ }
691++ return ret;
692++}
693++
694+
695+Property changes on: storage/innobase/cache/row0cache0filter.c
696+___________________________________________________________________
697+Added: svn:mime-type
698+ + text/plain
699+
700+Index: storage/innobase/cache/row0cache0mempool.c
701+===================================================================
702+--- storage/innobase/cache/row0cache0mempool.c (revision 0)
703++++ storage/innobase/cache/row0cache0mempool.c (revision 724)
704+@@ -0,0 +1,800 @@
705++/********************************************************************
706++ created: 2011/03/23
707++ created: 23:3:2011 15:15
708++ file base: row0cache0mempool
709++ file ext: c
710++ author: wentong@taobao.com
711++
712++ purpose:
713++*********************************************************************/
714++#include "row0cache0mempool.h"
715++#include "mem0mem.h"
716++#include "sync0sync.h"
717++#include "row0cache0lru.h"
718++#include "mem0pool.h"
719++#include "row0cache.h"
720++#include "ut0lst.h"
721++#include "os0proc.h"
722++#include "srv0srv.h"
723++
724++//copy from mem0pool.c
725++
726++/** The smallest memory area total size */
727++#define MEM_AREA_MIN_SIZE (2 * MEM_AREA_EXTRA_SIZE)
728++
729++/** Mask used to extract the free bit from area->size */
730++#define MEM_AREA_FREE 1
731++
732++/** Data structure for a memory pool. The space is allocated using the buddy
733++algorithm, where free list i contains areas of size 2 to power i. */
734++struct mem_pool_struct{
735++ byte* buf; /*!< memory pool */
736++ ulint size; /*!< memory common pool size */
737++ ulint reserved; /*!< amount of currently allocated
738++ memory */
739++ mutex_t mutex; /*!< mutex protecting this struct */
740++ UT_LIST_BASE_NODE_T(mem_area_t)
741++ free_list[64]; /*!< lists of free memory areas: an
742++ area is put to the list whose number
743++ is the 2-logarithm of the area size */
744++};
745++
746++/********************************************************************//**
747++Sets memory area size. */
748++static
749++void
750++mem_area_set_size_out(
751++/*==============*/
752++ mem_area_t* area, /*!< in: area */
753++ ulint size) /*!< in: size */
754++{
755++ area->size_and_free = (area->size_and_free & MEM_AREA_FREE)
756++ | size;
757++}
758++
759++/********************************************************************//**
760++Sets memory area free bit. */
761++static
762++void
763++mem_area_set_free_out(
764++/*==============*/
765++mem_area_t* area, /*!< in: area */
766++ibool free) /*!< in: free bit value */
767++{
768++#if TRUE != MEM_AREA_FREE
769++# error "TRUE != MEM_AREA_FREE"
770++#endif
771++ area->size_and_free = (area->size_and_free & ~MEM_AREA_FREE)
772++ | free;
773++}
774++
775++/********************************************************************//**
776++Returns memory area free bit.
777++ @return TRUE if free */
778++static
779++ibool
780++mem_area_get_free_out(
781++/*==============*/
782++mem_area_t* area) /*!< in: area */
783++{
784++#if TRUE != MEM_AREA_FREE
785++# error "TRUE != MEM_AREA_FREE"
786++#endif
787++ return(area->size_and_free & MEM_AREA_FREE);
788++}
789++
790++/********************************************************************//**
791++Returns memory area size.
792++@return size */
793++static
794++ulint
795++mem_area_get_size_out(
796++/*==============*/
797++mem_area_t* area) /*!< in: area */
798++{
799++ return(area->size_and_free & ~MEM_AREA_FREE);
800++}
801++
802++
803++/********************************************************************//**
804++Gets the buddy of an area, if it exists in pool.
805++@return the buddy, NULL if no buddy in pool */
806++static
807++mem_area_t*
808++mem_area_get_buddy_out(
809++/*===============*/
810++ mem_area_t* area, /*!< in: memory area */
811++ ulint size, /*!< in: memory area size */
812++ mem_pool_t* pool) /*!< in: memory pool */
813++{
814++ mem_area_t* buddy;
815++
816++ ut_ad(size != 0);
817++
818++ if (((((byte*)area) - pool->buf) % (2 * size)) == 0) {
819++
820++ /* The buddy is in a higher address */
821++
822++ buddy = (mem_area_t*)(((byte*)area) + size);
823++
824++ if ((((byte*)buddy) - pool->buf) + size > pool->size) {
825++
826++ /* The buddy is not wholly contained in the pool:
827++ there is no buddy */
828++
829++ buddy = NULL;
830++ }
831++ } else {
832++ /* The buddy is in a lower address; NOTE that area cannot
833++ be at the pool lower end, because then we would end up to
834++ the upper branch in this if-clause: the remainder would be
835++ 0 */
836++
837++ buddy = (mem_area_t*)(((byte*)area) - size);
838++ }
839++
840++ return(buddy);
841++}
842++/********************************************************************//**
843++Fills the specified free list.
844++@return TRUE if we were able to insert a block to the free list */
845++static
846++ibool
847++mem_pool_fill_free_list(
848++/*====================*/
849++ ulint i, /*!< in: free list index */
850++ mem_pool_t* pool) /*!< in: memory pool */
851++{
852++ mem_area_t* area;
853++ mem_area_t* area2;
854++ ibool ret;
855++
856++ ut_ad(mutex_own(&(pool->mutex)));
857++
858++ if (UNIV_UNLIKELY(i >= 63)) {
859++ /* We come here when we have run out of space in the
860++ memory pool: */
861++
862++ return(FALSE);
863++ }
864++
865++ area = UT_LIST_GET_FIRST(pool->free_list[i + 1]);
866++
867++ if (area == NULL) {
868++ if (UT_LIST_GET_LEN(pool->free_list[i + 1]) > 0) {
869++ ut_print_timestamp(stderr);
870++
871++ fprintf(stderr,
872++ " InnoDB: Error: mem pool free list %lu"
873++ " length is %lu\n"
874++ "InnoDB: though the list is empty!\n",
875++ (ulong) i + 1,
876++ (ulong)
877++ UT_LIST_GET_LEN(pool->free_list[i + 1]));
878++ }
879++
880++ ret = mem_pool_fill_free_list(i + 1, pool);
881++
882++ if (ret == FALSE) {
883++
884++ return(FALSE);
885++ }
886++
887++ area = UT_LIST_GET_FIRST(pool->free_list[i + 1]);
888++ }
889++
890++ if (UNIV_UNLIKELY(UT_LIST_GET_LEN(pool->free_list[i + 1]) == 0)) {
891++ mem_analyze_corruption(area);
892++
893++ ut_error;
894++ }
895++
896++ UT_LIST_REMOVE(free_list, pool->free_list[i + 1], area);
897++
898++ area2 = (mem_area_t*)(((byte*)area) + ut_2_exp(i));
899++ UNIV_MEM_ALLOC(area2, MEM_AREA_EXTRA_SIZE);
900++
901++ mem_area_set_size_out(area2, ut_2_exp(i));
902++ mem_area_set_free_out(area2, TRUE);
903++
904++ UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area2);
905++
906++ mem_area_set_size_out(area, ut_2_exp(i));
907++
908++ UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area);
909++
910++ return(TRUE);
911++}
912++
913++/********************************************************************//**
914++Creates a memory pool.
915++@return memory pool */
916++static
917++mem_pool_t*
918++mem_pool_create_out(
919++/*============*/
920++ ulint size) /*!< in: pool size in bytes */
921++{
922++ mem_pool_t* pool;
923++ mem_area_t* area;
924++ ulint i;
925++ ulint used;
926++
927++ pool = ut_malloc(sizeof(mem_pool_t));
928++
929++ /* We do not set the memory to zero (FALSE) in the pool,
930++ but only when allocated at a higher level in mem0mem.c.
931++ This is to avoid masking useful Purify warnings. */
932++
933++ pool->buf = ut_malloc_low(size, FALSE, TRUE);
934++ /* pool->buf = os_mem_alloc_large(&size);
935++ if (pool->buf == NULL) {
936++ ut_print_timestamp(stderr);
937++
938++ fprintf(stderr,
939++ " InnoDB: We now intentionally"
940++ " generate a seg fault so that\n"
941++ "InnoDB: on Linux we get a stack trace.\n");
942++
943++ if (*ut_mem_null_ptr) ut_mem_null_ptr = 0;
944++ } */
945++ pool->size = size;
946++
947++ mutex_create(PFS_NOT_INSTRUMENTED, &pool->mutex, SYNC_MEM_POOL);
948++
949++ /* Initialize the free lists */
950++
951++ for (i = 0; i < 64; i++) {
952++
953++ UT_LIST_INIT(pool->free_list[i]);
954++ }
955++
956++ used = 0;
957++
958++ while (size - used >= MEM_AREA_MIN_SIZE) {
959++
960++ i = ut_2_log(size - used);
961++
962++ if (ut_2_exp(i) > size - used) {
963++
964++ /* ut_2_log rounds upward */
965++
966++ i--;
967++ }
968++
969++ area = (mem_area_t*)(pool->buf + used);
970++
971++ mem_area_set_size_out(area, ut_2_exp(i));
972++ mem_area_set_free_out(area, TRUE);
973++ UNIV_MEM_FREE(MEM_AREA_EXTRA_SIZE + (byte*) area,
974++ ut_2_exp(i) - MEM_AREA_EXTRA_SIZE);
975++
976++ UT_LIST_ADD_FIRST(free_list, pool->free_list[i], area);
977++
978++ used = used + ut_2_exp(i);
979++ }
980++
981++ ut_ad(size >= used);
982++
983++ pool->reserved = 0;
984++
985++ return(pool);
986++}
987++
988++/********************************************************************//**
989++Frees a memory pool. */
990++static
991++void
992++mem_pool_free_out(
993++/*==========*/
994++ mem_pool_t* pool) /*!< in, own: memory pool */
995++{
996++ //os_mem_free_large(pool->buf , pool->size);
997++ ut_free(pool->buf);
998++ ut_free(pool);
999++}
1000++
1001++/********************************************************************//**
1002++Allocates memory from a pool. NOTE: This low-level function should only be
1003++used in mem0mem.*!
1004++@return own: allocated memory buffer */
1005++static
1006++void*
1007++mem_area_alloc_out(
1008++/*===========*/
1009++ ulint* psize, /*!< in: requested size in bytes; for optimum
1010++ space usage, the size should be a power of 2
1011++ minus MEM_AREA_EXTRA_SIZE;
1012++ out: allocated size in bytes (greater than
1013++ or equal to the requested size) */
1014++ mem_pool_t* pool) /*!< in: memory pool */
1015++{
1016++ mem_area_t* area;
1017++ ulint size;
1018++ ulint n;
1019++ ibool ret;
1020++
1021++
1022++ size = *psize;
1023++ n = ut_2_log(ut_max(size + MEM_AREA_EXTRA_SIZE, MEM_AREA_MIN_SIZE));
1024++
1025++ mutex_enter(&(pool->mutex));
1026++
1027++
1028++ area = UT_LIST_GET_FIRST(pool->free_list[n]);
1029++
1030++ if (area == NULL) {
1031++ ret = mem_pool_fill_free_list(n, pool);
1032++
1033++ if (ret == FALSE) {
1034++ /* Out of memory in memory pool: we try to allocate
1035++ from the operating system with the regular malloc: */
1036++
1037++ mutex_exit(&(pool->mutex));
1038++
1039++ return(NULL);
1040++ }
1041++
1042++ area = UT_LIST_GET_FIRST(pool->free_list[n]);
1043++ }
1044++
1045++ if (!mem_area_get_free_out(area)) {
1046++ fprintf(stderr,
1047++ "InnoDB: Error: Removing element from mem pool"
1048++ " free list %lu though the\n"
1049++ "InnoDB: element is not marked free!\n",
1050++ (ulong) n);
1051++
1052++ mem_analyze_corruption(area);
1053++
1054++ /* Try to analyze a strange assertion failure reported at
1055++ mysql@lists.mysql.com where the free bit IS 1 in the
1056++ hex dump above */
1057++
1058++ if (mem_area_get_free_out(area)) {
1059++ fprintf(stderr,
1060++ "InnoDB: Probably a race condition"
1061++ " because now the area is marked free!\n");
1062++ }
1063++
1064++ ut_error;
1065++ }
1066++
1067++ if (UT_LIST_GET_LEN(pool->free_list[n]) == 0) {
1068++ fprintf(stderr,
1069++ "InnoDB: Error: Removing element from mem pool"
1070++ " free list %lu\n"
1071++ "InnoDB: though the list length is 0!\n",
1072++ (ulong) n);
1073++ mem_analyze_corruption(area);
1074++
1075++ ut_error;
1076++ }
1077++
1078++ ut_ad(mem_area_get_size_out(area) == ut_2_exp(n));
1079++
1080++ mem_area_set_free_out(area, FALSE);
1081++
1082++ UT_LIST_REMOVE(free_list, pool->free_list[n], area);
1083++
1084++ pool->reserved += mem_area_get_size_out(area);
1085++
1086++ mutex_exit(&(pool->mutex));
1087++
1088++ ut_ad(mem_pool_validate(pool));
1089++
1090++ *psize = ut_2_exp(n) - MEM_AREA_EXTRA_SIZE;
1091++ UNIV_MEM_ALLOC(MEM_AREA_EXTRA_SIZE + (byte*)area, *psize);
1092++
1093++ return((void*)(MEM_AREA_EXTRA_SIZE + ((byte*)area)));
1094++}
1095++
1096++/********************************************************************//**
1097++Frees memory to a pool. */
1098++static
1099++void
1100++mem_area_free_out(
1101++/*==========*/
1102++ void* ptr, /*!< in, own: pointer to allocated memory
1103++ buffer */
1104++ mem_pool_t* pool) /*!< in: memory pool */
1105++{
1106++ mem_area_t* area;
1107++ mem_area_t* buddy;
1108++ void* new_ptr;
1109++ ulint size;
1110++ ulint n;
1111++
1112++
1113++
1114++ /* It may be that the area was really allocated from the OS with
1115++ regular malloc: check if ptr points within our memory pool */
1116++
1117++ if ((byte*)ptr < pool->buf || (byte*)ptr >= pool->buf + pool->size) {
1118++ ut_free(ptr);
1119++
1120++ return;
1121++ }
1122++
1123++ area = (mem_area_t*) (((byte*)ptr) - MEM_AREA_EXTRA_SIZE);
1124++
1125++ if (mem_area_get_free_out(area)) {
1126++ fprintf(stderr,
1127++ "InnoDB: Error: Freeing element to mem pool"
1128++ " free list though the\n"
1129++ "InnoDB: element is marked free!\n");
1130++
1131++ mem_analyze_corruption(area);
1132++ ut_error;
1133++ }
1134++
1135++ size = mem_area_get_size_out(area);
1136++ UNIV_MEM_FREE(ptr, size - MEM_AREA_EXTRA_SIZE);
1137++
1138++ if (size == 0) {
1139++ fprintf(stderr,
1140++ "InnoDB: Error: Mem area size is 0. Possibly a"
1141++ " memory overrun of the\n"
1142++ "InnoDB: previous allocated area!\n");
1143++
1144++ mem_analyze_corruption(area);
1145++ ut_error;
1146++ }
1147++
1148++#ifdef UNIV_LIGHT_MEM_DEBUG
1149++ if (((byte*)area) + size < pool->buf + pool->size) {
1150++
1151++ ulint next_size;
1152++
1153++ next_size = mem_area_get_size_out(
1154++ (mem_area_t*)(((byte*)area) + size));
1155++ if (UNIV_UNLIKELY(!next_size || !ut_is_2pow(next_size))) {
1156++ fprintf(stderr,
1157++ "InnoDB: Error: Memory area size %lu,"
1158++ " next area size %lu not a power of 2!\n"
1159++ "InnoDB: Possibly a memory overrun of"
1160++ " the buffer being freed here.\n",
1161++ (ulong) size, (ulong) next_size);
1162++ mem_analyze_corruption(area);
1163++
1164++ ut_error;
1165++ }
1166++ }
1167++#endif
1168++ buddy = mem_area_get_buddy_out(area, size, pool);
1169++
1170++ n = ut_2_log(size);
1171++
1172++ mutex_enter(&(pool->mutex));
1173++
1174++
1175++ if (buddy && mem_area_get_free_out(buddy)
1176++ && (size == mem_area_get_size_out(buddy))) {
1177++
1178++ /* The buddy is in a free list */
1179++
1180++ if ((byte*)buddy < (byte*)area) {
1181++ new_ptr = ((byte*)buddy) + MEM_AREA_EXTRA_SIZE;
1182++
1183++ mem_area_set_size_out(buddy, 2 * size);
1184++ mem_area_set_free_out(buddy, FALSE);
1185++ } else {
1186++ new_ptr = ptr;
1187++
1188++ mem_area_set_size_out(area, 2 * size);
1189++ }
1190++
1191++ /* Remove the buddy from its free list and merge it to area */
1192++
1193++ UT_LIST_REMOVE(free_list, pool->free_list[n], buddy);
1194++
1195++ pool->reserved += ut_2_exp(n);
1196++
1197++ mutex_exit(&(pool->mutex));
1198++
1199++ mem_area_free_out(new_ptr, pool);
1200++
1201++ return;
1202++ } else {
1203++ UT_LIST_ADD_FIRST(free_list, pool->free_list[n], area);
1204++
1205++ mem_area_set_free_out(area, TRUE);
1206++
1207++ ut_ad(pool->reserved >= size);
1208++
1209++ pool->reserved -= size;
1210++ }
1211++
1212++ mutex_exit(&(pool->mutex));
1213++
1214++ ut_ad(mem_pool_validate(pool));
1215++}
1216++
1217++//end copy
1218++
1219++UNIV_INTERN my_bool innodb_row_cache_use_sys_malloc = FALSE;
1220++
1221++UNIV_INTERN llong innodb_row_cache_mem_pool_size = 1024 * 1024L; //default is 1M
1222++
1223++UNIV_INTERN llong innodb_row_cache_additional_mem_pool_size = 1024 * 1024L;//default is 1M
1224++
1225++//mem pool
1226++static mem_pool_t** row_cache_mem_pool = NULL;
1227++
1228++//system malloc stat
1229++static llong* sys_malloc_mem_size = NULL;
1230++
1231++static llong* sys_malloc_mem_used = NULL;
1232++
1233++static ROW_CACHE_VALUE_LIST_BASE *innodb_row_cache_value_mem_list = NULL;
1234++
1235++static row_cache_value_t *innodb_row_cache_value_mem_pool = NULL;
1236++
1237++static ROW_CACHE_VALUE_QUEUE_LIST_BASE *innodb_row_cache_queue_mem_list = NULL;
1238++
1239++static row_cache_value_queue_t *innodb_row_cache_queue_mem_pool = NULL;
1240++
1241++void init_row_cache_mem_pool(my_bool innodb_row_cache_on)
1242++{
1243++ if(!innodb_row_cache_on){
1244++ innodb_row_cache_mem_pool_size = 1;
1245++ }
1246++ if (sizeof(ulint) == 4) {
1247++ if (innodb_row_cache_mem_pool_size > UINT_MAX32) {
1248++ ut_print_timestamp(stderr);
1249++ fprintf(stderr,
1250++ "[Error]innodb_row_cache_mem_pool_size can't be over 4GB"
1251++ " on 32-bit systems\n");
1252++ }
1253++ }
1254++ if (innodb_row_cache_mutex_num > 0){
1255++ long long mem_pool_size = 0;
1256++ ulint i;
1257++ //init row cache value mem pool
1258++ ulint row_cache_value_mem_list_size = 0;
1259++ ulint row_cache_mem_pool_value_num = innodb_row_cache_additional_mem_pool_size / sizeof(row_cache_value_t);
1260++ ulint row_cache_max_queue_num;
1261++ if (row_cache_mem_pool_value_num>0){
1262++ row_cache_value_mem_list_size = innodb_row_cache_mutex_num * sizeof(ROW_CACHE_VALUE_LIST_BASE);
1263++ //create row cache mem list
1264++ innodb_row_cache_value_mem_list = (ROW_CACHE_VALUE_LIST_BASE*) ut_malloc(row_cache_value_mem_list_size);
1265++ innodb_row_cache_value_mem_pool = (row_cache_value_t*) ut_malloc(row_cache_mem_pool_value_num * sizeof(row_cache_value_t));
1266++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
1267++ {
1268++ UT_LIST_INIT(*(innodb_row_cache_value_mem_list+i));
1269++ }
1270++ for (i = 0 ; i < row_cache_mem_pool_value_num ; i++)
1271++ {
1272++ ROW_CACHE_VALUE_LIST_BASE* value_list = innodb_row_cache_value_mem_list + (i % innodb_row_cache_mutex_num);
1273++ row_cache_value_t* value = innodb_row_cache_value_mem_pool + i;
1274++ memset(value , 0 , sizeof(row_cache_value_t));
1275++ UT_LIST_ADD_FIRST(list,*value_list,value);
1276++ }
1277++ }
1278++ //create row cache queue mem list
1279++ innodb_row_cache_queue_mem_list = (ROW_CACHE_VALUE_QUEUE_LIST_BASE*) ut_malloc(innodb_row_cache_mutex_num * sizeof(ROW_CACHE_VALUE_QUEUE_LIST_BASE));
1280++ row_cache_max_queue_num = srv_thread_concurrency * 2 * innodb_row_cache_mutex_num;
1281++ innodb_row_cache_queue_mem_pool = (row_cache_value_queue_t*) ut_malloc(row_cache_max_queue_num * sizeof(row_cache_value_queue_t));
1282++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
1283++ {
1284++ UT_LIST_INIT(*(innodb_row_cache_queue_mem_list+i));
1285++ }
1286++ for (i = 0 ; i < row_cache_max_queue_num ; i++)
1287++ {
1288++ ROW_CACHE_VALUE_QUEUE_LIST_BASE* list_base = innodb_row_cache_queue_mem_list + (i % innodb_row_cache_mutex_num);
1289++ row_cache_value_queue_t* value = innodb_row_cache_queue_mem_pool + i;
1290++ memset(value , 0 , sizeof(row_cache_value_queue_t));
1291++ UT_LIST_ADD_FIRST(list,*list_base,value);
1292++ }
1293++
1294++ if(!innodb_row_cache_use_sys_malloc){
1295++ //init general mem pool
1296++ row_cache_mem_pool = (mem_pool_t**) ut_malloc(innodb_row_cache_mutex_num * sizeof(mem_pool_t*));
1297++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
1298++ {
1299++ row_cache_mem_pool[i] = mem_pool_create_out(innodb_row_cache_mem_pool_size / innodb_row_cache_mutex_num);
1300++ mem_pool_size += row_cache_mem_pool[i]->size;
1301++ }
1302++ //set to real alloc size!
1303++ innodb_row_cache_mem_pool_size = mem_pool_size;
1304++ }else{
1305++ //init system malloc mem stat
1306++ sys_malloc_mem_size = (llong*) ut_malloc(innodb_row_cache_mutex_num * sizeof(llong));
1307++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
1308++ {
1309++ sys_malloc_mem_size[i] = innodb_row_cache_mem_pool_size / innodb_row_cache_mutex_num;
1310++ }
1311++ sys_malloc_mem_used = (llong*) ut_malloc(innodb_row_cache_mutex_num * sizeof(llong));
1312++ memset(sys_malloc_mem_used , 0 , innodb_row_cache_mutex_num * sizeof(llong));
1313++ }
1314++ }
1315++}
1316++
1317++void deinit_row_cache_mem_pool(){
1318++ if (innodb_row_cache_mutex_num > 0){
1319++ if(!innodb_row_cache_use_sys_malloc){
1320++ ulint i;
1321++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++){
1322++ //mutex_free(&row_cache_mem_pool[i]->mutex); //free in sync_close()
1323++ mem_pool_free_out(row_cache_mem_pool[i]);
1324++ }
1325++ ut_free(row_cache_mem_pool);
1326++ row_cache_mem_pool=NULL;
1327++ }else{
1328++ ut_free(sys_malloc_mem_size);
1329++ ut_free(sys_malloc_mem_used);
1330++ }
1331++ }
1332++ if(innodb_row_cache_value_mem_pool){
1333++ ut_free(innodb_row_cache_value_mem_pool);
1334++ innodb_row_cache_value_mem_pool=NULL;
1335++ }
1336++ if(innodb_row_cache_value_mem_list){
1337++ ut_free(innodb_row_cache_value_mem_list);
1338++ innodb_row_cache_value_mem_list=NULL;
1339++ }
1340++ if(innodb_row_cache_queue_mem_pool){
1341++ ut_free(innodb_row_cache_queue_mem_pool);
1342++ innodb_row_cache_queue_mem_pool=NULL;
1343++ }
1344++ if(innodb_row_cache_queue_mem_list){
1345++ ut_free(innodb_row_cache_queue_mem_list);
1346++ innodb_row_cache_queue_mem_list=NULL;
1347++ }
1348++}
1349++
1350++static mem_pool_t* get_current_mem_pool(const ulint fold){
1351++ return row_cache_mem_pool[row_cache_get_mutex_no(fold)];
1352++}
1353++
1354++void* ca_malloc_low(ulint n , const ulint used_fold)
1355++{
1356++ void* ret = NULL;
1357++ if(!innodb_row_cache_use_sys_malloc){
1358++ mem_pool_t* mem_pool = get_current_mem_pool(used_fold);
1359++ ret=mem_area_alloc_out(&n,mem_pool);
1360++ if(ret==NULL){
1361++ free_from_lru(n,used_fold);
1362++ ret=mem_area_alloc_out(&n,mem_pool);
1363++ }
1364++ }else{
1365++ ulint no = row_cache_get_mutex_no(used_fold);
1366++ if(sys_malloc_mem_size[no] - sys_malloc_mem_used[no] > n){
1367++ ret = malloc(n);
1368++ }
1369++ if(ret==NULL){
1370++ free_from_lru(n,used_fold);
1371++ ret=malloc(n);
1372++ }
1373++ if(ret){
1374++ sys_malloc_mem_used[no] += n;
1375++ }
1376++ }
1377++ return ret;
1378++}
1379++
1380++void ca_free_low( void* ptr , const ulint size ,const ulint used_fold)
1381++{
1382++ if(!innodb_row_cache_use_sys_malloc){
1383++ mem_area_free_out(ptr,get_current_mem_pool(used_fold));
1384++ }else{
1385++ ulint no = row_cache_get_mutex_no(used_fold);
1386++ free(ptr);
1387++ sys_malloc_mem_used[no] -= size;
1388++ }
1389++}
1390++
1391++static ROW_CACHE_VALUE_LIST_BASE* get_current_value_list(const ulint fold){
1392++ if(innodb_row_cache_value_mem_list){
1393++ return innodb_row_cache_value_mem_list + row_cache_get_mutex_no(fold);
1394++ }
1395++ return NULL;
1396++}
1397++
1398++row_cache_value_t* ca_malloc_for_value( const ulint used_fold )
1399++{
1400++ row_cache_value_t* value = NULL;
1401++ ROW_CACHE_VALUE_LIST_BASE* value_list = get_current_value_list(used_fold);
1402++ if(value_list && UT_LIST_GET_LEN(*value_list) > 0){
1403++ value = UT_LIST_GET_FIRST(*value_list);
1404++ UT_LIST_REMOVE(list,*value_list,value);
1405++ memset(value , 0 , sizeof(row_cache_value_t));
1406++ //set value mean it come from value's mem pool
1407++ onBit(value->flag,FLAG_VALUE_IS_FROM_VALUE_POOL);
1408++ }else{
1409++ value = (row_cache_value_t*) ca_malloc(sizeof(row_cache_value_t) , used_fold);
1410++ if(value){
1411++ memset(value , 0 , sizeof(row_cache_value_t));
1412++ }
1413++ }
1414++ return value;
1415++}
1416++
1417++void ca_free_for_value( row_cache_value_t* value, const ulint used_fold )
1418++{
1419++ if(isValueFromValuePool(value->flag)){
1420++ ROW_CACHE_VALUE_LIST_BASE* value_list = get_current_value_list(used_fold);
1421++ UT_LIST_ADD_FIRST(list,*value_list,value);
1422++ }else{
1423++ ca_free(value,sizeof(row_cache_value_t),used_fold);
1424++ }
1425++}
1426++
1427++static ROW_CACHE_VALUE_QUEUE_LIST_BASE* get_current_value_queue_list(const ulint fold){
1428++ if(innodb_row_cache_queue_mem_list){
1429++ return innodb_row_cache_queue_mem_list + row_cache_get_mutex_no(fold);
1430++ }
1431++ return NULL;
1432++}
1433++
1434++
1435++row_cache_value_queue_t* ca_malloc_for_queue( const ulint used_fold )
1436++{
1437++ row_cache_value_queue_t* value = NULL;
1438++ ROW_CACHE_VALUE_QUEUE_LIST_BASE* list_base = get_current_value_queue_list(used_fold);
1439++ if(list_base && UT_LIST_GET_LEN(*list_base) > 0){
1440++ value = UT_LIST_GET_FIRST(*list_base);
1441++ UT_LIST_REMOVE(list,*list_base,value);
1442++ memset(value , 0 , sizeof(row_cache_value_queue_t));
1443++ }else{
1444++ value = (row_cache_value_queue_t*) ca_malloc(sizeof(row_cache_value_queue_t) , used_fold);
1445++ if(value){
1446++ memset(value , 0 , sizeof(row_cache_value_queue_t));
1447++ }
1448++ }
1449++ return value;
1450++
1451++}
1452++
1453++void ca_free_for_queue( row_cache_value_queue_t* value, const ulint used_fold )
1454++{
1455++ ROW_CACHE_VALUE_QUEUE_LIST_BASE* list_base = get_current_value_queue_list(used_fold);
1456++ UT_LIST_ADD_FIRST(list,*list_base,value);
1457++}
1458++
1459++
1460++ulint row_cache_mem_pool_used()
1461++{
1462++ ulint ret = 0;
1463++ ulint i;
1464++ if(!innodb_row_cache_use_sys_malloc){
1465++ if(row_cache_mem_pool){
1466++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
1467++ {
1468++ ret += mem_pool_get_reserved(row_cache_mem_pool[i]);
1469++ }
1470++ }
1471++ }else{
1472++ if(sys_malloc_mem_used){
1473++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
1474++ {
1475++ ret += sys_malloc_mem_used[i];
1476++ }
1477++ }
1478++ }
1479++ return ret;
1480++}
1481++
1482++ulint row_cache_get_value_free_count(){
1483++ ulint ret = 0;
1484++ ulint i;
1485++ if(innodb_row_cache_value_mem_list){
1486++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
1487++ {
1488++ ret += UT_LIST_GET_LEN(innodb_row_cache_value_mem_list[i]);
1489++ }
1490++ }
1491++ return ret;
1492++}
1493++
1494++ulint row_cache_get_queue_free_count(){
1495++ ulint ret = 0;
1496++ ulint i;
1497++ if(innodb_row_cache_queue_mem_list){
1498++ for (i = 0 ; i < innodb_row_cache_mutex_num ; i++)
1499++ {
1500++ ret += UT_LIST_GET_LEN(innodb_row_cache_queue_mem_list[i]);
1501++ }
1502++ }
1503++ return ret;
1504++}
1505+
1506+Property changes on: storage/innobase/cache/row0cache0mempool.c
1507+___________________________________________________________________
1508+Added: svn:mime-type
1509+ + text/plain
1510+
1511+Index: storage/innobase/cache/row0cache.c
1512+===================================================================
1513+--- storage/innobase/cache/row0cache.c (revision 0)
1514++++ storage/innobase/cache/row0cache.c (revision 724)
1515+@@ -0,0 +1,385 @@
1516++/********************************************************************
1517++ created: 2011/03/17
1518++ created: 17:3:2011 16:51
1519++ file base: row0cache
1520++ file ext: c
1521++ author: wentong@taobao.com
1522++
1523++ purpose: for row cache
1524++ *********************************************************************/
1525++#include "row0cache.h"
1526++#include "row0cache0mempool.h"
1527++#include "row0cache0hash.h"
1528++#include "mtr0mtr.h"
1529++#include "rem0rec.h"
1530++#include "row0cache0lru.h"
1531++#include "trx0types.h"
1532++#include "page0page.h"
1533++#include "log0recv.h"
1534++#include "read0read.h"
1535++#include "rem0cmp.h"
1536++#include "row0cache0filter.h"
1537++UNIV_INTERN my_bool innodb_row_cache_on = FALSE;
1538++
1539++static row_cache_stat_t _row_cache_stat;
1540++UNIV_INTERN row_cache_stat_t* row_cache_stat = &_row_cache_stat;
1541++
1542++void init_row_cache() {
1543++ DBUG_ENTER("init_row_cache");
1544++ memset(row_cache_stat, 0, sizeof(row_cache_stat_t));
1545++ init_row_cache_hash(innodb_row_cache_on);
1546++ init_innodb_row_cache_lru();
1547++ init_row_cache_mem_pool(innodb_row_cache_on);
1548++ init_row_cache_filter(innodb_row_cache_on);
1549++ //init_row_cache_lock_pool(1000);//TODO
1550++ DBUG_VOID_RETURN;
1551++}
1552++
1553++void deinit_row_cache() {
1554++ DBUG_ENTER("deinit_row_cache");
1555++ deinit_innodb_row_cache_lru();
1556++ deinit_row_cache_hash(innodb_row_cache_on);
1557++ deinit_row_cache_mem_pool();
1558++ /*deinit_row_cache_filter(innodb_row_cache_on);*/ // deinitde in innobase_shutdown_for_mysql*/
1559++ DBUG_VOID_RETURN;
1560++}
1561++
1562++static row_cache_value_t* create_row_cache_value(const rec_t* rec,
1563++ const ulint* offsets, ulint fold, const dict_index_t* index,
1564++ ibool is_sec_index) {
1565++ ulint buf_size;
1566++ row_cache_value_t* value = ca_malloc_for_value(fold);
1567++ if (value == NULL) {
1568++ //not enough mem
1569++ ut_print_timestamp(stderr);
1570++ fprintf(
1571++ stderr,
1572++ "[Warnning] malloc row_cache_value_t failded in create_row_cache_value !\n");
1573++ return NULL;
1574++ }
1575++ buf_size = rec_offs_extra_size(offsets) + rec_offs_data_size(offsets);
1576++ if (is_sec_index) {
1577++ buf_size += sizeof(trx_id_t);
1578++ }
1579++ value->buf = (rec_t*) ca_malloc(buf_size , fold);
1580++ if (value->buf == NULL) {
1581++ //not enough mem
1582++ ut_print_timestamp(stderr);
1583++ fprintf(
1584++ stderr,
1585++ "[Warnning] malloc rec copy buf failded in create_row_cache_value !\n");
1586++ ca_free_for_value(value, fold);
1587++ return NULL;
1588++ }
1589++ memset(value->buf, 0, buf_size);
1590++ value->fold = fold;
1591++ value->tree_id = index->id;
1592++ value->table_id = index->table->id;
1593++ value->rec = rec_copy(value->buf, rec, offsets);
1594++ if (is_sec_index) {
1595++ trx_id_t* trx_id_in_rec = (trx_id_t*) (value->buf + buf_size
1596++ - sizeof(trx_id_t));
1597++ *trx_id_in_rec = page_get_max_trx_id(page_align(rec));
1598++ }
1599++ value->buf_size = buf_size;
1600++ value->ref_num = 0;
1601++ value->chain.value = value;
1602++ return value;
1603++}
1604++
1605++static int update_row_cache_value(row_cache_value_t* value, const rec_t* rec,
1606++ const ulint* offsets, ulint fold, const dict_index_t* index,
1607++ ibool is_sec_index) {
1608++ ulint buf_size;
1609++ ca_free(value->buf, value->buf_size, fold);
1610++ buf_size = rec_offs_extra_size(offsets) + rec_offs_data_size(offsets);
1611++ if (is_sec_index) {
1612++ buf_size += sizeof(trx_id_t);
1613++ }
1614++ value->buf = (rec_t*) ca_malloc(buf_size , fold);
1615++ if (value->buf == NULL) {
1616++ //not enough mem
1617++ ut_print_timestamp(stderr);
1618++ fprintf(
1619++ stderr,
1620++ "[Warnning] malloc rec copy buf failded in create_row_cache_value !\n");
1621++ return NOT_ENOUGH_MEM;
1622++ }
1623++ memset(value->buf, 0, buf_size);
1624++ value->fold = fold;
1625++ value->tree_id = index->id;
1626++ value->table_id = index->table->id;
1627++ value->rec = rec_copy(value->buf, rec, offsets);
1628++ if (is_sec_index) {
1629++ trx_id_t* trx_id_in_rec = (trx_id_t*) (value->buf + buf_size
1630++ - sizeof(trx_id_t));
1631++ *trx_id_in_rec = page_get_max_trx_id(page_align(rec));
1632++ }
1633++ value->buf_size = buf_size;
1634++ //trun off is_removed
1635++ offBit(value->flag, FLAG_VALUE_IS_REMOVED);
1636++ value->ref_num = 0;
1637++ return 0;
1638++}
1639++
1640++void put_rec_to_row_cache(const dtuple_t* tuple, const rec_t* rec, /*!< in: physical record */
1641++const ulint* offsets, /*!< in: array returned by rec_get_offsets() */
1642++const dict_index_t* index, ibool is_sec_index) {
1643++ row_cache_value_t* value;
1644++ ulint fold;
1645++ if (!innodb_row_cache_on) {
1646++ return;
1647++ }
1648++ if (!is_index_need_cache(index)) {
1649++ return;
1650++ }
1651++ //if rec is deleted ,it can,t be put into row cache
1652++ if (rec_get_deleted_flag(rec, dict_table_is_comp(index->table))) {
1653++ return;
1654++ }
1655++ fold = calc_fold_by_rec(rec, offsets, dict_index_get_n_unique(index),
1656++ index->id);
1657++ row_cache_enter_mutex(fold);
1658++ value = search_row_cache_value(tuple, index, fold);
1659++ if (value == NULL) {
1660++ value = create_row_cache_value(rec, offsets, fold, index, is_sec_index);
1661++ if (value != NULL) {
1662++ insert_row_cache_value(fold, value);
1663++ add_row_cache_value_to_lru(value);
1664++ }
1665++ } else {
1666++ if (isValueRemoved(value->flag) && value->ref_num == 0) {
1667++ //can be overwrite
1668++ if (update_row_cache_value(value, rec, offsets, fold, index,
1669++ is_sec_index) == NOT_ENOUGH_MEM) {
1670++ delete_row_cache_value(value);
1671++ remove_row_cache_value_from_lru(value);
1672++ ca_free_for_value(value, fold); //value->buf already free in update_row_cache_value()
1673++ } else {
1674++ make_row_cache_value_first_from_lru(value);
1675++ }
1676++ }
1677++ }
1678++ row_cache_exit_mutex(fold);
1679++}
1680++
1681++static int add_row_cache_value_to_mtr(mtr_t* mtr, row_cache_value_t* value) {
1682++ row_cache_value_queue_t* row_cache_value_queue;
1683++ row_cache_value_queue = (row_cache_value_queue_t*) ca_malloc_for_queue(
1684++ value->fold);
1685++ if (NULL == row_cache_value_queue) {
1686++ ut_print_timestamp(stderr);
1687++ fprintf(
1688++ stderr,
1689++ "[Warnning] malloc row_cache_value_queue_t failded in add_row_cache_value_to_mtr!\n");
1690++ return NOT_ENOUGH_MEM;
1691++ }
1692++ row_cache_value_queue->value = value;
1693++ UT_LIST_ADD_LAST(list, mtr->row_cache_value_queue_base,
1694++ row_cache_value_queue);
1695++ return 0;
1696++}
1697++
1698++void release_row_cache_value_in_mtr(mtr_t* mtr) {
1699++ row_cache_value_queue_t* row_cache_value_queue;
1700++ if (!innodb_row_cache_on) {
1701++ return;
1702++ }
1703++ while (mtr->row_cache_value_queue_base.count != 0) {
1704++ ulint fold;
1705++ row_cache_value_queue = mtr->row_cache_value_queue_base.end;
1706++ //release Reference
1707++ fold = row_cache_value_queue->value->fold;
1708++ row_cache_enter_mutex(fold);
1709++ row_cache_value_queue->value->ref_num--;
1710++ UT_LIST_REMOVE(list, mtr->row_cache_value_queue_base,
1711++ row_cache_value_queue);
1712++ ca_free_for_queue(row_cache_value_queue, fold);
1713++ row_cache_exit_mutex(fold);
1714++ }
1715++}
1716++
1717++static void free_row_cache_value(row_cache_value_t* value) {
1718++ ulint fold = value->fold;
1719++ ca_free(value->buf, value->buf_size, fold);
1720++ ca_free_for_value(value, fold);
1721++}
1722++
1723++int contain_row_cache_low(const ulint fold, const dtuple_t* tuple,
1724++ const dict_index_t* index) {
1725++ row_cache_value_t* value;
1726++ int ret = 0;
1727++ if (!innodb_row_cache_on) {
1728++ return ret;
1729++ }
1730++ if (!is_index_need_cache(index)) {
1731++ return ret;
1732++ }
1733++ row_cache_enter_mutex(fold);
1734++ value = search_row_cache_value(tuple, index, fold);
1735++ if (value != NULL && !isValueRemoved(value->flag)) {
1736++ ret = 1;
1737++ }
1738++ row_cache_exit_mutex(fold);
1739++ return ret;
1740++}
1741++
1742++rec_t* get_from_row_cache_low(const ulint fold, const dtuple_t* tuple,
1743++ const dict_index_t* index, mtr_t* mtr) {
1744++ row_cache_value_t* value;
1745++ if (!innodb_row_cache_on) {
1746++ return NULL;
1747++ }
1748++ if (!is_index_need_cache(index)) {
1749++ return NULL;
1750++ }
1751++ row_cache_stat->n_get++;
1752++ row_cache_enter_mutex(fold);
1753++ value = search_row_cache_value(tuple, index, fold);
1754++ if (value != NULL) {
1755++ if (isValueRemoved(value->flag) && value->ref_num == 0) {
1756++ //can be free
1757++ delete_row_cache_value(value);
1758++ remove_row_cache_value_from_lru(value);
1759++ free_row_cache_value(value);
1760++ value = NULL;
1761++ } else if (!isValueRemoved(value->flag)) {
1762++ //can be read
1763++ if (add_row_cache_value_to_mtr(mtr, value) == 0) {
1764++ make_row_cache_value_first_from_lru(value);
1765++ value->ref_num++;
1766++ } else {
1767++ //not have enough mem
1768++ value = NULL;
1769++ }
1770++
1771++ } else {
1772++ // is removed can't be read
1773++ value = NULL;
1774++ }
1775++ }
1776++ row_cache_exit_mutex(fold);
1777++ if (value != NULL) {
1778++ row_cache_stat->geted++;
1779++ return value->rec;
1780++ }
1781++ return NULL;
1782++}
1783++
1784++void remove_from_row_cache_low(const ulint fold, const rec_t* rec,
1785++ const ulint* offsets, const dtuple_t* tuple, dict_index_t* index) {
1786++ row_cache_value_t* value = NULL;
1787++ if (!innodb_row_cache_on) {
1788++ return;
1789++ }
1790++ row_cache_enter_mutex(fold);
1791++ if (rec && offsets) {
1792++ value = search_row_cache_value_with_rec(rec, offsets, index, fold);
1793++ } else if (tuple) {
1794++ value = search_row_cache_value(tuple, index, fold);
1795++ }
1796++ if (value != NULL) {
1797++ if (value->ref_num == 0) {
1798++ //can be free
1799++ delete_row_cache_value(value);
1800++ remove_row_cache_value_from_lru(value);
1801++ free_row_cache_value(value);
1802++ value = NULL;
1803++ } else {
1804++ //using just set is_removed = 1
1805++ onBit(value->flag, FLAG_VALUE_IS_REMOVED);
1806++ }
1807++ }
1808++ row_cache_exit_mutex(fold);
1809++}
1810++
1811++ulint calc_fold_by_rec(const rec_t* rec, /*!< in: the physical record */
1812++const ulint* offsets, /*!< in: array returned by rec_get_offsets() */
1813++ulint n_fields, /*!< in: number of complete fields to fold */
1814++index_id_t tree_id) {
1815++ return rec_fold(rec, offsets, n_fields, 0, tree_id);
1816++}
1817++
1818++ulint lock_sec_rec_in_row_cache_cons_read_sees(const rec_t* rec,
1819++ const ulint* offsets, const read_view_t* view) {
1820++ trx_id_t* max_trx_id;
1821++ if (recv_recovery_is_on()) {
1822++
1823++ return (FALSE);
1824++ }
1825++
1826++ max_trx_id = (trx_id_t*) (rec + rec_offs_data_size(offsets));
1827++ ut_ad((*max_trx_id)!=0);
1828++
1829++ return (*max_trx_id) < (view->up_limit_id);
1830++// return(ut_dulint_cmp( *max_trx_id, view->up_limit_id) < 0);
1831++}
1832++
1833++void row_cache_refresh_stats() {
1834++ row_cache_stat->last_printout_time = time(NULL);
1835++ row_cache_stat->old_geted = row_cache_stat->geted;
1836++ row_cache_stat->old_n_get = row_cache_stat->n_get;
1837++ row_cache_lru_stat->old_n_add = row_cache_lru_stat->n_add;
1838++ row_cache_lru_stat->old_n_evict = row_cache_lru_stat->n_evict;
1839++ row_cache_lru_stat->old_n_make_first = row_cache_lru_stat->n_make_first;
1840++}
1841++
1842++void print_row_cache_stats(FILE* file) {
1843++ time_t current_time;
1844++ double time_elapsed;
1845++ ulint n_gets_diff = 0;
1846++ unsigned long long n_geted_diff = 0;
1847++ unsigned long long mem_pool_used = row_cache_mem_pool_used();
1848++
1849++ fputs("----------------------\n"
1850++ "ROW CACHE\n"
1851++ "----------------------\n", file);
1852++ fprintf(file, "Total memory allocated " ULINTPF
1853++ "; used " ULINTPF " (" ULINTPF " / 1000)"
1854++ "; additional pool allocated " ULINTPF
1855++ "; Total LRU count " ULINTPF"\n", (ulong) innodb_row_cache_mem_pool_size,
1856++ (ulong) mem_pool_used,
1857++ (ulong) (1000 * mem_pool_used / innodb_row_cache_mem_pool_size),
1858++ (ulong) innodb_row_cache_additional_mem_pool_size,
1859++ (ulong) get_row_cache_lru_count());
1860++
1861++ fprintf(file, "Free Value Count " ULINTPF
1862++ "; Free Queue Count " ULINTPF "\n",
1863++ (ulong) row_cache_get_value_free_count(),
1864++ (ulong) row_cache_get_queue_free_count());
1865++
1866++ current_time = time(NULL);
1867++ time_elapsed = 0.001
1868++ + difftime(current_time, row_cache_stat->last_printout_time);
1869++
1870++ n_geted_diff = row_cache_stat->geted - row_cache_stat->old_geted;
1871++ n_gets_diff = row_cache_stat->n_get - row_cache_stat->old_n_get;
1872++
1873++ fprintf(
1874++ file,
1875++ "Row total add " ULINTPF " , %.2f add/s \n"
1876++ "Row total make first " ULINTPF " , %.2f mf/s \n"
1877++ "Row total evict " ULINTPF " , %.2f evict/s \n"
1878++ "Row read from cache " ULINTPF ", %.2f read/s \n"
1879++ "Row get from cache " ULINTPF ", %.2f get/s \n",
1880++ (ulong) row_cache_lru_stat->n_add,
1881++ (row_cache_lru_stat->n_add - row_cache_lru_stat->old_n_add)
1882++ / time_elapsed,
1883++ (ulong) row_cache_lru_stat->n_make_first,
1884++ (row_cache_lru_stat->n_make_first
1885++ - row_cache_lru_stat->old_n_make_first) / time_elapsed,
1886++ (ulong) row_cache_lru_stat->n_evict,
1887++ (row_cache_lru_stat->n_evict - row_cache_lru_stat->old_n_evict)
1888++ / time_elapsed, (ulong) row_cache_stat->n_get,
1889++ n_gets_diff / time_elapsed, (ulong) row_cache_stat->geted,
1890++ n_geted_diff / time_elapsed);
1891++
1892++ if (n_gets_diff) {
1893++ fprintf(file, "Row cache hit rate %lu / 1000 \n",
1894++ (ulong) (1000 * n_geted_diff) / n_gets_diff);
1895++ } else {
1896++ fputs("No row cache gets since the last printout\n", file);
1897++ }
1898++
1899++ row_cache_refresh_stats();
1900++}
1901+
1902+Property changes on: storage/innobase/cache/row0cache.c
1903+___________________________________________________________________
1904+Added: svn:mime-type
1905+ + text/plain
1906+
1907+Index: storage/innobase/srv/srv0srv.c
1908+===================================================================
1909+--- storage/innobase/srv/srv0srv.c (revision 498)
1910++++ storage/innobase/srv/srv0srv.c (revision 724)
1911+@@ -86,6 +86,9 @@
1912+ #include "read0read.h"
1913+ #include "mysql/plugin.h"
1914+ #include "mysql/service_thd_wait.h"
1915++#include "row0cache.h" /* for row cache*/
1916++#include "row0cache0lru.h"
1917++#include "row0cache0mempool.h"
1918+
1919+ /* prototypes of new functions added to ha_innodb.cc for kill_idle_transaction */
1920+ ibool innobase_thd_is_idle(const void* thd);
1921+@@ -1139,6 +1142,8 @@
1922+
1923+ /* Initialize some INFORMATION SCHEMA internal structures */
1924+ trx_i_s_cache_init(trx_i_s_cache);
1925++
1926++ init_row_cache();
1927+ }
1928+
1929+ /*********************************************************************//**
1930+@@ -1162,6 +1167,8 @@
1931+ srv_mysql_table = NULL;
1932+
1933+ trx_i_s_cache_free(trx_i_s_cache);
1934++
1935++ deinit_row_cache();
1936+ }
1937+
1938+ /*********************************************************************//**
1939+@@ -1967,6 +1974,8 @@
1940+
1941+ buf_refresh_io_stats_all();
1942+
1943++ row_cache_refresh_stats();
1944++
1945+ srv_n_rows_inserted_old = srv_n_rows_inserted;
1946+ srv_n_rows_updated_old = srv_n_rows_updated;
1947+ srv_n_rows_deleted_old = srv_n_rows_deleted;
1948+@@ -2160,6 +2169,8 @@
1949+
1950+ buf_print_io(file);
1951+
1952++ print_row_cache_stats(file);
1953++
1954+ fputs("--------------\n"
1955+ "ROW OPERATIONS\n"
1956+ "--------------\n", file);
1957+@@ -2471,6 +2482,19 @@
1958+ export_vars.innodb_rows_deleted = srv_n_rows_deleted;
1959+ export_vars.innodb_truncated_status_writes = srv_truncated_status_writes;
1960+
1961++
1962++ export_vars.innodb_row_cache_n_get = row_cache_stat->n_get;
1963++ export_vars.innodb_row_cache_geted = row_cache_stat->geted;
1964++
1965++ export_vars.innodb_row_cache_lru_n_add = row_cache_lru_stat->n_add;
1966++ export_vars.innodb_row_cache_lru_n_make_first = row_cache_lru_stat->n_make_first;
1967++ export_vars.innodb_row_cache_lru_n_evict = row_cache_lru_stat->n_evict;
1968++ export_vars.innodb_row_cache_lru_count = get_row_cache_lru_count();
1969++
1970++ export_vars.innodb_row_cache_mem_pool_size = innodb_row_cache_mem_pool_size;
1971++ export_vars.innodb_row_cache_mem_pool_used = row_cache_mem_pool_used();
1972++
1973++
1974+ mutex_exit(&srv_innodb_monitor_mutex);
1975+ }
1976+
1977+Index: storage/innobase/srv/srv0start.c
1978+===================================================================
1979+--- storage/innobase/srv/srv0start.c (revision 498)
1980++++ storage/innobase/srv/srv0start.c (revision 724)
1981+@@ -62,6 +62,8 @@
1982+ #include "ibuf0ibuf.h"
1983+ #include "srv0start.h"
1984+ #include "srv0srv.h"
1985++#include "row0cache.h"
1986++#include "row0cache0filter.h"
1987+ #ifndef UNIV_HOTBACKUP
1988+ # include "os0proc.h"
1989+ # include "sync0sync.h"
1990+@@ -2390,6 +2392,7 @@
1991+ /* 3. Free all InnoDB's own mutexes and the os_fast_mutexes inside
1992+ them */
1993+ os_aio_free();
1994++ deinit_row_cache_filter(innodb_row_cache_on);
1995+ sync_close();
1996+ srv_free();
1997+ fil_close();
1998+Index: storage/innobase/CMakeLists.txt
1999+===================================================================
2000+--- storage/innobase/CMakeLists.txt (revision 498)
2001++++ storage/innobase/CMakeLists.txt (revision 724)
2002+@@ -245,7 +245,9 @@
2003+ trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c
2004+ usr/usr0sess.c
2005+ ut/ut0byte.c ut/ut0dbg.c ut/ut0list.c ut/ut0mem.c ut/ut0rbt.c ut/ut0rnd.c
2006+- ut/ut0ut.c ut/ut0vec.c ut/ut0wqueue.c ut/ut0bh.c)
2007++ ut/ut0ut.c ut/ut0vec.c ut/ut0wqueue.c ut/ut0bh.c
2008++ cache/row0cache.c cache/row0cache0hash.c cache/row0cache0lru.c cache/row0cache0mempool.c
2009++ cache/row0cache0filter.c)
2010+
2011+ IF(WITH_INNODB)
2012+ # Legacy option
2013+Index: storage/innobase/handler/ha_innodb.cc
2014+===================================================================
2015+--- storage/innobase/handler/ha_innodb.cc (revision 498)
2016++++ storage/innobase/handler/ha_innodb.cc (revision 724)
2017+@@ -97,6 +97,10 @@
2018+ #include "ha_prototypes.h"
2019+ #include "ut0mem.h"
2020+ #include "ibuf0ibuf.h"
2021++#include "row0cache0mempool.h"
2022++#include "row0cache0hash.h"
2023++#include "row0cache0filter.h"
2024++#include "row0cache0lru.h"
2025+ }
2026+
2027+ #include "ha_innodb.h"
2028+@@ -342,7 +346,8 @@
2029+ {&trx_i_s_cache_lock_key, "trx_i_s_cache_lock", 0},
2030+ {&trx_purge_latch_key, "trx_purge_latch", 0},
2031+ {&index_tree_rw_lock_key, "index_tree_rw_lock", 0},
2032+- {&dict_table_stats_latch_key, "dict_table_stats", 0}
2033++ {&dict_table_stats_latch_key, "dict_table_stats", 0},
2034++ {&row_cache_filter_lock_key, "row_cache_filter_lock", 0}
2035+ };
2036+ # endif /* UNIV_PFS_RWLOCK */
2037+
2038+@@ -844,6 +849,22 @@
2039+ (char*) &export_vars.innodb_x_lock_spin_rounds, SHOW_LONGLONG},
2040+ {"x_lock_spin_waits",
2041+ (char*) &export_vars.innodb_x_lock_spin_waits, SHOW_LONGLONG},
2042++ {"row_cache_n_get",
2043++ (char*) &export_vars.innodb_row_cache_n_get, SHOW_LONG},
2044++ {"row_cache_n_geted",
2045++ (char*) &export_vars.innodb_row_cache_geted, SHOW_LONG},
2046++ {"row_cache_lru_count",
2047++ (char*) &export_vars.innodb_row_cache_lru_count, SHOW_LONG},
2048++ {"row_cache_lru_n_add",
2049++ (char*) &export_vars.innodb_row_cache_lru_n_add, SHOW_LONG},
2050++ {"row_cache_lru_n_evict",
2051++ (char*) &export_vars.innodb_row_cache_lru_n_evict, SHOW_LONG},
2052++ {"row_cache_lru_n_make_first",
2053++ (char*) &export_vars.innodb_row_cache_lru_n_make_first, SHOW_LONG},
2054++ {"row_cache_mem_pool_size",
2055++ (char*) &export_vars.innodb_row_cache_mem_pool_size, SHOW_LONGLONG},
2056++ {"row_cache_mem_pool_used",
2057++ (char*) &export_vars.innodb_row_cache_mem_pool_used, SHOW_LONG},
2058+ {NullS, NullS, SHOW_LONG}
2059+ };
2060+
2061+@@ -6330,6 +6351,37 @@
2062+ start of a new SQL statement. */
2063+
2064+
2065++UNIV_INTERN
2066++bool ha_innobase::is_in_cache(const uchar * key_ptr, uint key_len) {
2067++ dict_index_t* index;
2068++ bool ret = false;
2069++
2070++ DBUG_ENTER("index_read");
2071++ ut_a(prebuilt->trx == thd_to_trx(user_thd));
2072++ index = prebuilt->index;
2073++
2074++ if (UNIV_UNLIKELY(index == NULL) || dict_index_is_corrupted(index)) {
2075++ prebuilt->index_usable = FALSE;
2076++ DBUG_RETURN(ret);
2077++ }
2078++ if (UNIV_UNLIKELY(!prebuilt->index_usable)) {
2079++ DBUG_RETURN(ret);
2080++ }
2081++
2082++ if (key_ptr) {
2083++ /* Convert the search key value to InnoDB format into
2084++ prebuilt->search_tuple */
2085++
2086++ row_sel_convert_mysql_key_to_innobase(prebuilt->search_tuple,
2087++ (byte*) key_val_buff, (ulint) upd_and_key_val_buff_len, index,
2088++ (byte*) key_ptr, (ulint) key_len, prebuilt->trx);
2089++
2090++ ret = (contain_row_cache(prebuilt->search_tuple,index) == 1);
2091++ }
2092++
2093++ DBUG_RETURN(ret);
2094++}
2095++
2096+ /**********************************************************************//**
2097+ Positions an index cursor to the index specified in the handle. Fetches the
2098+ row if any.
2099+@@ -12556,6 +12608,89 @@
2100+ "e.g. for http://bugs.mysql.com/51325",
2101+ NULL, NULL, 0, 0, 1, 0);
2102+
2103++
2104++static
2105++void
2106++innodb_row_cache_index_update(
2107++/*===========================*/
2108++THD* thd, /*!< in: thread handle */
2109++struct st_mysql_sys_var* var, /*!< in: pointer to
2110++ system variable */
2111++void* var_ptr, /*!< out: where the
2112++ formal string goes */
2113++const void* save) /*!< in: immediate result
2114++ from check function */
2115++{
2116++ ut_a(var_ptr != NULL);
2117++ ut_a(save != NULL);
2118++
2119++ *static_cast<const char**>(var_ptr) = *static_cast<const char*const*>(save);
2120++ reset_filter();
2121++}
2122++
2123++static
2124++void
2125++innodb_row_cache_clean_cache_update(
2126++/*===========================*/
2127++THD* thd, /*!< in: thread handle */
2128++struct st_mysql_sys_var* var, /*!< in: pointer to
2129++ system variable */
2130++void* var_ptr, /*!< out: where the
2131++ formal string goes */
2132++const void* save) /*!< in: immediate result
2133++ from check function */
2134++{
2135++ ut_a(var_ptr != NULL);
2136++ ut_a(save != NULL);
2137++
2138++ if(*(my_bool*) save){
2139++ clean_row_cache();
2140++ }
2141++}
2142++
2143++static MYSQL_SYSVAR_LONGLONG(row_cache_mem_pool_size, innodb_row_cache_mem_pool_size,
2144++ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
2145++ "The size of the memory buffer InnoDB uses to cache row.",
2146++ NULL, NULL, 1024*1024L, 1024*1024L, LONGLONG_MAX, 0);
2147++
2148++static MYSQL_SYSVAR_LONGLONG(row_cache_additional_mem_pool_size, innodb_row_cache_additional_mem_pool_size,
2149++ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
2150++ "The size of the memory buffer InnoDB uses create buffer for cache row 's struct.",
2151++ NULL, NULL, 1024*1024L, 1024*1024L, LONGLONG_MAX, 0);
2152++
2153++static MYSQL_SYSVAR_BOOL(row_cache_on, innodb_row_cache_on,
2154++ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
2155++ "Enable row cache",
2156++ NULL, NULL, FALSE);
2157++
2158++static MYSQL_SYSVAR_ULONG(row_cache_cell_num, innodb_row_cache_cell_num,
2159++ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
2160++ "Number of row cache 's hash table cell.",
2161++ NULL, NULL, 10000L, 100L, ~0L, 0);
2162++
2163++static MYSQL_SYSVAR_UINT(row_cache_mutex_num_shift, innodb_row_cache_mutex_num_shift,
2164++ PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
2165++ "Number of row cache 's hash table mutex number's shift.",
2166++ NULL, NULL, 6, 1, 14, 0);
2167++
2168++static MYSQL_SYSVAR_STR(row_cache_index, innodb_row_cache_index,
2169++ PLUGIN_VAR_OPCMDARG,
2170++ "The config of index need to cache.",
2171++ NULL,
2172++ innodb_row_cache_index_update, NULL);
2173++
2174++static MYSQL_SYSVAR_BOOL(row_cache_clean_cache, innodb_row_cache_clean_cache,
2175++ PLUGIN_VAR_NOCMDARG,
2176++ "Set ON to Clean cache For DEBUG!",
2177++ NULL, innodb_row_cache_clean_cache_update, FALSE);
2178++
2179++static MYSQL_SYSVAR_BOOL(row_cache_use_sys_malloc, innodb_row_cache_use_sys_malloc,
2180++ PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
2181++ "row cache use system malloc (disabled by default)",
2182++ NULL, NULL, FALSE);
2183++
2184++
2185++
2186+ static struct st_mysql_sys_var* innobase_system_variables[]= {
2187+ MYSQL_SYSVAR(page_size),
2188+ MYSQL_SYSVAR(log_block_size),
2189+@@ -12656,6 +12791,14 @@
2190+ MYSQL_SYSVAR(corrupt_table_action),
2191+ MYSQL_SYSVAR(lazy_drop_table),
2192+ MYSQL_SYSVAR(fake_changes),
2193++ MYSQL_SYSVAR(row_cache_mem_pool_size),
2194++ MYSQL_SYSVAR(row_cache_additional_mem_pool_size),
2195++ MYSQL_SYSVAR(row_cache_on),
2196++ MYSQL_SYSVAR(row_cache_cell_num),
2197++ MYSQL_SYSVAR(row_cache_mutex_num_shift),
2198++ MYSQL_SYSVAR(row_cache_index),
2199++ MYSQL_SYSVAR(row_cache_clean_cache),
2200++ MYSQL_SYSVAR(row_cache_use_sys_malloc),
2201+ NULL
2202+ };
2203+
2204+Index: storage/innobase/handler/ha_innodb.h
2205+===================================================================
2206+--- storage/innobase/handler/ha_innodb.h (revision 498)
2207++++ storage/innobase/handler/ha_innodb.h (revision 724)
2208+@@ -147,6 +147,8 @@
2209+
2210+ int index_init(uint index, bool sorted);
2211+ int index_end();
2212++ bool is_in_cache(const uchar * key,
2213++ uint key_len);
2214+ int index_read(uchar * buf, const uchar * key,
2215+ uint key_len, enum ha_rkey_function find_flag);
2216+ int index_read_idx(uchar * buf, uint index, const uchar * key,
2217+Index: storage/innobase/include/row0cache0mempool.h
2218+===================================================================
2219+--- storage/innobase/include/row0cache0mempool.h (revision 0)
2220++++ storage/innobase/include/row0cache0mempool.h (revision 724)
2221+@@ -0,0 +1,55 @@
2222++/********************************************************************
2223++ created: 2011/03/23
2224++ created: 23:3:2011 14:49
2225++ file base: row0cache0mempool
2226++ file ext: h
2227++ author: wentong@taobao.vom
2228++
2229++ purpose:
2230++*********************************************************************/
2231++
2232++#ifndef row0cache0mempool_h__
2233++#define row0cache0mempool_h__
2234++
2235++#include "ut0rbt.h"
2236++#include "row0cache0hash.h"
2237++#include "row0cache.h"
2238++
2239++typedef long long llong;
2240++
2241++extern my_bool innodb_row_cache_use_sys_malloc;
2242++
2243++extern llong innodb_row_cache_mem_pool_size;
2244++
2245++extern llong innodb_row_cache_additional_mem_pool_size;
2246++
2247++#define NOT_ENOUGH_MEM 1
2248++
2249++void init_row_cache_mem_pool(my_bool innodb_row_cache_on);
2250++
2251++void deinit_row_cache_mem_pool();
2252++
2253++void* ca_malloc_low(ulint n , const ulint used_fold);
2254++
2255++void ca_free_low(void* ptr, const ulint size ,const ulint used_fold);
2256++
2257++#define ca_malloc(S,F) ca_malloc_low(S,F)
2258++#define ca_free(P,S,F) ca_free_low(P,S,F)
2259++
2260++//#define ca_malloc_for_value(F) ca_malloc(sizeof(row_cache_value_t),F)
2261++//#define ca_free_for_value(S,F) ca_free(S,F)
2262++
2263++//#define ca_malloc_for_queue(F) ca_malloc(sizeof(row_cache_value_queue_t),F)
2264++//#define ca_free_for_queue(S,F) ca_free(S,F)
2265++
2266++row_cache_value_t* ca_malloc_for_value(const ulint used_fold);
2267++void ca_free_for_value(row_cache_value_t* value, const ulint used_fold);
2268++
2269++row_cache_value_queue_t* ca_malloc_for_queue(const ulint used_fold);
2270++void ca_free_for_queue(row_cache_value_queue_t* value, const ulint used_fold);
2271++
2272++ulint row_cache_mem_pool_used();
2273++ulint row_cache_get_value_free_count();
2274++ulint row_cache_get_queue_free_count();
2275++
2276++#endif // row0cache0mempool_h__
2277+
2278+Property changes on: storage/innobase/include/row0cache0mempool.h
2279+___________________________________________________________________
2280+Added: svn:mime-type
2281+ + text/plain
2282+
2283+Index: storage/innobase/include/srv0srv.h
2284+===================================================================
2285+--- storage/innobase/include/srv0srv.h (revision 498)
2286++++ storage/innobase/include/srv0srv.h (revision 724)
2287+@@ -842,6 +842,18 @@
2288+ ib_int64_t innodb_x_lock_os_waits;
2289+ ib_int64_t innodb_x_lock_spin_rounds;
2290+ ib_int64_t innodb_x_lock_spin_waits;
2291++
2292++ ulint innodb_row_cache_n_get;
2293++ ulint innodb_row_cache_geted;
2294++
2295++ ulint innodb_row_cache_lru_n_add;
2296++ ulint innodb_row_cache_lru_n_make_first;
2297++ ulint innodb_row_cache_lru_n_evict;
2298++ ulint innodb_row_cache_lru_count;
2299++
2300++ ib_int64_t innodb_row_cache_mem_pool_size;
2301++ ib_int64_t innodb_row_cache_mem_pool_used;
2302++
2303+ };
2304+
2305+ /** Thread slot in the thread table */
2306+Index: storage/innobase/include/row0cache0lru.h
2307+===================================================================
2308+--- storage/innobase/include/row0cache0lru.h (revision 0)
2309++++ storage/innobase/include/row0cache0lru.h (revision 724)
2310+@@ -0,0 +1,46 @@
2311++/********************************************************************
2312++ created: 2011/03/23
2313++ created: 23:3:2011 14:48
2314++ file base: row0cache0lru
2315++ file ext: h
2316++ author: wentong@taobao.com
2317++
2318++ purpose:
2319++*********************************************************************/
2320++
2321++#ifndef row0cache0lru_h__
2322++#define row0cache0lru_h__
2323++
2324++#include "row0cache0hash.h"
2325++#include "rem0types.h"
2326++
2327++typedef struct struct_row_cache_lru_stat{
2328++ ulint n_add;
2329++ ulint n_make_first;
2330++ ulint n_evict;
2331++ ulint old_n_add;
2332++ ulint old_n_make_first;
2333++ ulint old_n_evict;
2334++}row_cache_lru_stat_t;
2335++
2336++extern row_cache_lru_stat_t* row_cache_lru_stat;
2337++
2338++extern my_bool innodb_row_cache_clean_cache;
2339++
2340++void init_innodb_row_cache_lru();
2341++
2342++void deinit_innodb_row_cache_lru();
2343++
2344++void clean_row_cache();
2345++
2346++void add_row_cache_value_to_lru(row_cache_value_t* value);
2347++
2348++void make_row_cache_value_first_from_lru(row_cache_value_t* value);
2349++
2350++ulint free_from_lru(const ulint size , const ulint used_fold);
2351++
2352++void remove_row_cache_value_from_lru(row_cache_value_t* value);
2353++
2354++ulint get_row_cache_lru_count();
2355++
2356++#endif // row0cache0lru_h__
2357+
2358+Property changes on: storage/innobase/include/row0cache0lru.h
2359+___________________________________________________________________
2360+Added: svn:mime-type
2361+ + text/plain
2362+
2363+Index: storage/innobase/include/mtr0mtr.h
2364+===================================================================
2365+--- storage/innobase/include/mtr0mtr.h (revision 498)
2366++++ storage/innobase/include/mtr0mtr.h (revision 724)
2367+@@ -34,6 +34,7 @@
2368+ #include "ut0byte.h"
2369+ #include "mtr0types.h"
2370+ #include "page0types.h"
2371++#include "row0cache.h"
2372+
2373+ /* Logging modes for a mini-transaction */
2374+ #define MTR_LOG_ALL 21 /* default mode: log all operations
2375+@@ -368,6 +369,7 @@
2376+ #endif
2377+ dyn_array_t memo; /*!< memo stack for locks etc. */
2378+ dyn_array_t log; /*!< mini-transaction log */
2379++ UT_LIST_BASE_NODE_T(row_cache_value_queue_t) row_cache_value_queue_base; /*!< row cache lock queue base*/
2380+ ibool inside_ibuf;
2381+ /*!< TRUE if inside ibuf changes */
2382+ ibool modifications;
2383+Index: storage/innobase/include/mtr0mtr.ic
2384+===================================================================
2385+--- storage/innobase/include/mtr0mtr.ic (revision 498)
2386++++ storage/innobase/include/mtr0mtr.ic (revision 724)
2387+@@ -41,6 +41,8 @@
2388+
2389+ dyn_array_create(&(mtr->memo));
2390+ dyn_array_create(&(mtr->log));
2391++
2392++ UT_LIST_INIT(mtr->row_cache_value_queue_base);
2393+
2394+ mtr->log_mode = MTR_LOG_ALL;
2395+ mtr->modifications = FALSE;
2396+Index: storage/innobase/include/row0cache0hash.h
2397+===================================================================
2398+--- storage/innobase/include/row0cache0hash.h (revision 0)
2399++++ storage/innobase/include/row0cache0hash.h (revision 724)
2400+@@ -0,0 +1,86 @@
2401++/********************************************************************
2402++ created: 2011/03/24
2403++ created: 24:3:2011 8:48
2404++ file base: row0cache0hash
2405++ file ext: h
2406++ author: wentong@taobao.com
2407++
2408++ purpose:
2409++*********************************************************************/
2410++#ifndef row0cache0hash_h__
2411++#define row0cache0hash_h__
2412++
2413++#include "hash0hash.h"
2414++#include "rem0types.h"
2415++#include "data0types.h"
2416++#include "ut0byte.h"
2417++#include "ut0rbt.h"
2418++#include "dict0types.h"
2419++
2420++//flag and bit handler
2421++#define onBit(flag,bit) ((flag) |= (bit))
2422++#define offBit(flag,bit) ((flag) &= ~(bit))
2423++#define testFlag(flag,bit) (((flag) & (bit)) == (bit))
2424++
2425++
2426++typedef struct row_cache_chain row_cache_chain_t;
2427++typedef struct row_cache_value row_cache_value_t;
2428++typedef UT_LIST_BASE_NODE_T(row_cache_value_t) ROW_CACHE_VALUE_LIST_BASE;
2429++
2430++struct row_cache_chain{
2431++ row_cache_value_t* value;
2432++ row_cache_chain_t* next;
2433++};
2434++
2435++struct row_cache_value{
2436++ ulint fold;
2437++ index_id_t tree_id;
2438++ table_id_t table_id;
2439++ rec_t* buf; /*!< the real mem*/
2440++ rec_t* rec; /*!< the physical record */
2441++ ulint buf_size;
2442++ UT_LIST_NODE_T(row_cache_value_t) list;
2443++ ulint ref_num; /*!< the Reference Number */
2444++ unsigned char flag;
2445++ row_cache_chain_t chain;
2446++};
2447++
2448++#define FLAG_VALUE_IS_FROM_VALUE_POOL 1
2449++#define FLAG_VALUE_IS_REMOVED (1<<1)
2450++
2451++#define isValueFromValuePool(flag) testFlag(flag,FLAG_VALUE_IS_FROM_VALUE_POOL)
2452++#define isValueRemoved(flag) testFlag(flag,FLAG_VALUE_IS_REMOVED)
2453++
2454++typedef struct ha_row_cache{
2455++ hash_table_t* row_cache;
2456++}row_cache_t;
2457++
2458++extern row_cache_t* innodb_row_cache;
2459++
2460++extern unsigned long innodb_row_cache_cell_num;
2461++
2462++extern unsigned int innodb_row_cache_mutex_num_shift;
2463++
2464++extern ulint innodb_row_cache_mutex_num;
2465++
2466++int init_row_cache_hash(my_bool innodb_row_cache_on);
2467++
2468++void deinit_row_cache_hash(my_bool innodb_row_cache_on);
2469++
2470++row_cache_value_t* search_row_cache_value(const dtuple_t* tuple ,const dict_index_t* index, const ulint fold);
2471++row_cache_value_t* search_row_cache_value_with_rec(const rec_t* rec, const ulint* rec_offsets, dict_index_t* index, const ulint fold);
2472++row_cache_value_t* insert_row_cache_value(const ulint fold , row_cache_value_t* value);
2473++void delete_row_cache_value(row_cache_value_t* value);
2474++
2475++ulint row_cache_enter_mutex_nowait(const ulint fold);
2476++void row_cache_enter_mutex(const ulint fold);
2477++void row_cache_exit_mutex(const ulint fold);
2478++
2479++int row_cache_own_mutex(const ulint fold1 , const ulint fold2);
2480++
2481++ulint row_cache_get_mutex_no(const ulint fold);
2482++
2483++void row_cache_enter_mutex_by_no(const ulint no);
2484++void row_cache_exit_mutex_by_no(const ulint no);
2485++
2486++#endif // row0cache0hash_h__
2487+
2488+Property changes on: storage/innobase/include/row0cache0hash.h
2489+___________________________________________________________________
2490+Added: svn:mime-type
2491+ + text/plain
2492+
2493+Index: storage/innobase/include/row0cache.h
2494+===================================================================
2495+--- storage/innobase/include/row0cache.h (revision 0)
2496++++ storage/innobase/include/row0cache.h (revision 724)
2497+@@ -0,0 +1,89 @@
2498++/********************************************************************
2499++created: 2011/03/08
2500++created: 8:3:2011 10:56
2501++file base: row0cache
2502++file ext: h
2503++author: wentong@taobao.com
2504++
2505++purpose: for row cache
2506++*********************************************************************/
2507++#ifndef row0cache_h_
2508++#define row0cache_h_
2509++
2510++#include "univ.i"
2511++#include "rem0types.h"
2512++#include "data0types.h"
2513++#include "data0data.h"
2514++#include "ut0byte.h"
2515++#include "mtr0types.h"
2516++#include "ut0lst.h"
2517++#include "row0cache0hash.h"
2518++#include "read0types.h"
2519++
2520++extern my_bool innodb_row_cache_on;
2521++
2522++typedef struct struct_row_cache_stat{
2523++ ulint n_get; /*the total get*/
2524++ ulint geted; /*the get from row cache*/
2525++ ulint old_n_get;
2526++ ulint old_geted;
2527++ time_t last_printout_time;
2528++}row_cache_stat_t;
2529++
2530++extern row_cache_stat_t* row_cache_stat;
2531++
2532++
2533++#define calc_fold_by_tuple(tuple , n_fields , tree_id) dtuple_fold((tuple) , (n_fields) , 0 , (tree_id))
2534++ulint calc_fold_by_rec(
2535++/*=====*/
2536++ const rec_t* rec, /*!< in: the physical record */
2537++ const ulint* offsets, /*!< in: array returned by
2538++ rec_get_offsets() */
2539++ ulint n_fields, /*!< in: number of complete
2540++ fields to fold */
2541++ index_id_t tree_id); /*!< in: index tree id */
2542++
2543++typedef struct row_cache_value_queue_struct row_cache_value_queue_t;
2544++
2545++struct row_cache_value_queue_struct{
2546++ row_cache_value_t* value;
2547++ /*!< linear list of dyn blocks: this node is
2548++ used only in the first block */
2549++ UT_LIST_NODE_T(row_cache_value_queue_t) list;
2550++ /*!< linear list node: used in all blocks */
2551++};
2552++
2553++typedef UT_LIST_BASE_NODE_T(row_cache_value_queue_t) ROW_CACHE_VALUE_QUEUE_LIST_BASE;
2554++
2555++void init_row_cache();
2556++
2557++void deinit_row_cache();
2558++
2559++void put_rec_to_row_cache(const dtuple_t* tuple,
2560++ const rec_t* rec, /*!< in: physical record */
2561++ const ulint* offsets, /*!< in: array returned by rec_get_offsets() */
2562++ const dict_index_t* index, /*!< in: index tree id */
2563++ ibool is_sec_index);
2564++
2565++int contain_row_cache_low(const ulint fold, const dtuple_t* tuple,
2566++ const dict_index_t* index);
2567++
2568++rec_t* get_from_row_cache_low(const ulint fold, const dtuple_t* tuple, const dict_index_t* index ,mtr_t* mtr); /*!<in: mtr*/
2569++
2570++void remove_from_row_cache_low(const ulint fold, const rec_t* rec, const ulint* offsets, const dtuple_t* tuple, dict_index_t* index);
2571++
2572++void release_row_cache_value_in_mtr(mtr_t* mtr);
2573++
2574++ulint lock_sec_rec_in_row_cache_cons_read_sees(const rec_t* rec, const ulint* offsets, const read_view_t* view);
2575++
2576++#define contain_row_cache(tuple , index) contain_row_cache_low(calc_fold_by_tuple((tuple) , (dict_index_get_n_unique(index)) , (index->id)), (tuple) ,(index))
2577++#define get_from_row_cache(tuple , index , mtr) get_from_row_cache_low(calc_fold_by_tuple((tuple) , (dict_index_get_n_unique(index)) , (index->id)), (tuple) ,(index) ,(mtr) )
2578++#define remove_from_row_cache(rec, offsets, index) remove_from_row_cache_low(calc_fold_by_rec((rec), (offsets), (dict_index_get_n_unique(index)), (index->id)),(rec),(offsets) ,NULL,index)
2579++
2580++#define remove_from_row_cache_for_tuple(tuple, index) remove_from_row_cache_low(calc_fold_by_tuple((tuple) , (dict_index_get_n_unique(index)) , (index->id)) , NULL,NULL,(tuple),(index))
2581++
2582++void row_cache_refresh_stats();
2583++
2584++void print_row_cache_stats(FILE* file);
2585++
2586++#endif
2587+
2588+Property changes on: storage/innobase/include/row0cache.h
2589+___________________________________________________________________
2590+Added: svn:mime-type
2591+ + text/plain
2592+
2593+Index: storage/innobase/include/row0cache0filter.h
2594+===================================================================
2595+--- storage/innobase/include/row0cache0filter.h (revision 0)
2596++++ storage/innobase/include/row0cache0filter.h (revision 724)
2597+@@ -0,0 +1,33 @@
2598++/********************************************************************
2599++ created: 2011/05/31
2600++ created: 31:5:2011 11:39
2601++ file base: row0cache0filter
2602++ file ext: h
2603++ author: wentong@taobao.com
2604++
2605++ purpose:
2606++*********************************************************************/
2607++
2608++#ifndef row0cache0filter_h__
2609++#define row0cache0filter_h__
2610++
2611++#include "hash0hash.h"
2612++#include "dict0types.h"
2613++
2614++#ifdef UNIV_PFS_RWLOCK
2615++/* Key to register btr_search_sys with performance schema */
2616++extern mysql_pfs_key_t row_cache_filter_lock_key;
2617++#endif /* UNIV_PFS_RWLOCK */
2618++
2619++#define INDEX_CONFIG_LEN 2048
2620++
2621++extern char* innodb_row_cache_index;
2622++
2623++void init_row_cache_filter(my_bool innodb_row_cache_on);
2624++void deinit_row_cache_filter(my_bool innodb_row_cache_on);
2625++
2626++void reset_filter();
2627++
2628++my_bool is_index_need_cache(const dict_index_t* index);
2629++
2630++#endif // row0cache0filter_h__
2631+
2632+Property changes on: storage/innobase/include/row0cache0filter.h
2633+___________________________________________________________________
2634+Added: svn:mime-type
2635+ + text/plain
2636+
2637+Index: storage/innobase/row/row0upd.c
2638+===================================================================
2639+--- storage/innobase/row/row0upd.c (revision 498)
2640++++ storage/innobase/row/row0upd.c (revision 724)
2641+@@ -32,6 +32,7 @@
2642+ #include "dict0dict.h"
2643+ #include "trx0undo.h"
2644+ #include "rem0rec.h"
2645++#include "row0cache.h"
2646+ #ifndef UNIV_HOTBACKUP
2647+ #include "dict0boot.h"
2648+ #include "dict0crea.h"
2649+@@ -1665,6 +1666,12 @@
2650+ }
2651+ break;
2652+ }
2653++ //TB_HOOK
2654++ if(dict_index_is_unique(index)){
2655++ ulint offsets_[REC_OFFS_NORMAL_SIZE];
2656++ ulint* offsets = rec_get_offsets( rec, index, offsets_, ULINT_UNDEFINED, &heap);
2657++ remove_from_row_cache(rec,offsets,index);
2658++ }
2659+
2660+ btr_pcur_close(&pcur);
2661+ mtr_commit(&mtr);
2662+@@ -2199,6 +2206,8 @@
2663+ }
2664+ }
2665+
2666++ remove_from_row_cache(rec , offsets , index);
2667++
2668+ /* NOTE: the following function calls will also commit mtr */
2669+
2670+ if (node->is_delete) {
2671+Index: storage/innobase/row/row0uins.c
2672+===================================================================
2673+--- storage/innobase/row/row0uins.c (revision 498)
2674++++ storage/innobase/row/row0uins.c (revision 724)
2675+@@ -45,6 +45,8 @@
2676+ #include "que0que.h"
2677+ #include "ibuf0ibuf.h"
2678+ #include "log0log.h"
2679++#include "row0cache.h"
2680++#include "btr0sea.h"
2681+
2682+ /*************************************************************************
2683+ IMPORTANT NOTE: Any operation that generates redo MUST check that there
2684+@@ -66,11 +68,23 @@
2685+ /*==========================*/
2686+ undo_node_t* node) /*!< in: undo node */
2687+ {
2688++ dict_index_t* index;
2689++ btr_pcur_t* pcur;
2690++
2691+ btr_cur_t* btr_cur;
2692+ ibool success;
2693+ ulint err;
2694+ ulint n_tries = 0;
2695+ mtr_t mtr;
2696++ rec_t* rec;
2697++
2698++ mem_heap_t* heap = NULL;
2699++ ulint offsets_[REC_OFFS_NORMAL_SIZE];
2700++ ulint* offsets;
2701++ rec_offs_init(offsets_);
2702++
2703++ pcur = &(node->pcur);
2704++ index = dict_table_get_first_index(node->table);
2705+
2706+ mtr_start(&mtr);
2707+
2708+@@ -78,6 +92,11 @@
2709+ &mtr);
2710+ ut_a(success);
2711+
2712++ //TB_HOOK
2713++ rec = btr_pcur_get_rec(pcur);
2714++ offsets = rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap);
2715++ remove_from_row_cache(rec , offsets,index);
2716++
2717+ if (node->table->id == DICT_INDEXES_ID) {
2718+ ut_ad(node->trx->dict_operation_lock_mode == RW_X_LATCH);
2719+
2720+@@ -103,7 +122,9 @@
2721+
2722+ if (success) {
2723+ trx_undo_rec_release(node->trx, node->undo_no);
2724+-
2725++ if (UNIV_LIKELY_NULL(heap)) {
2726++ mem_heap_free(heap);
2727++ }
2728+ return(DB_SUCCESS);
2729+ }
2730+ retry:
2731+@@ -139,6 +160,9 @@
2732+
2733+ trx_undo_rec_release(node->trx, node->undo_no);
2734+
2735++ if (UNIV_LIKELY_NULL(heap)) {
2736++ mem_heap_free(heap);
2737++ }
2738+ return(err);
2739+ }
2740+
2741+@@ -348,6 +372,10 @@
2742+ transactions. */
2743+ ut_a(trx_is_recv(node->trx));
2744+ } else {
2745++ //TB_HOOK
2746++ if(dict_index_is_unique(node->index)){
2747++ remove_from_row_cache_for_tuple(entry , node->index);
2748++ }
2749+ log_free_check();
2750+ err = row_undo_ins_remove_sec(node->index, entry);
2751+
2752+Index: storage/innobase/row/row0sel.c
2753+===================================================================
2754+--- storage/innobase/row/row0sel.c (revision 498)
2755++++ storage/innobase/row/row0sel.c (revision 724)
2756+@@ -57,6 +57,7 @@
2757+ #include "read0read.h"
2758+ #include "buf0lru.h"
2759+ #include "ha_prototypes.h"
2760++#include "row0cache.h"
2761+
2762+ /* Maximum number of rows to prefetch; MySQL interface has another parameter */
2763+ #define SEL_MAX_N_PREFETCH 16
2764+@@ -2904,6 +2905,7 @@
2765+ rec_t* old_vers;
2766+ enum db_err err;
2767+ trx_t* trx;
2768++ ibool is_get_from_row_cache = FALSE;
2769+
2770+ *out_rec = NULL;
2771+ trx = thr_get_trx(thr);
2772+@@ -2913,20 +2915,31 @@
2773+
2774+ clust_index = dict_table_get_first_index(sec_index->table);
2775+
2776+- btr_pcur_open_with_no_init(clust_index, prebuilt->clust_ref,
2777+- PAGE_CUR_LE, BTR_SEARCH_LEAF,
2778+- prebuilt->clust_pcur, 0, mtr);
2779++ //TB_HOOK get_from_row_cache
2780++ if(prebuilt->select_lock_type == LOCK_NONE
2781++ && trx->mysql_n_tables_locked == 0){
2782++ clust_rec = get_from_row_cache(prebuilt->clust_ref,clust_index,mtr);
2783++ if (clust_rec!=NULL)
2784++ {
2785++ is_get_from_row_cache=TRUE;
2786++ }
2787++ }
2788++ if(is_get_from_row_cache == FALSE){
2789++ btr_pcur_open_with_no_init(clust_index, prebuilt->clust_ref,
2790++ PAGE_CUR_LE, BTR_SEARCH_LEAF,
2791++ prebuilt->clust_pcur, 0, mtr);
2792+
2793+- clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur);
2794++ clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur);
2795++ }
2796+
2797+ prebuilt->clust_pcur->trx_if_known = trx;
2798+
2799+ /* Note: only if the search ends up on a non-infimum record is the
2800+ low_match value the real match to the search tuple */
2801+
2802+- if (!page_rec_is_user_rec(clust_rec)
2803++ if (is_get_from_row_cache == FALSE && (!page_rec_is_user_rec(clust_rec)
2804+ || btr_pcur_get_low_match(prebuilt->clust_pcur)
2805+- < dict_index_get_n_unique(clust_index)) {
2806++ < dict_index_get_n_unique(clust_index))) {
2807+
2808+ /* In a rare case it is possible that no clust rec is found
2809+ for a delete-marked secondary index record: if in row0umod.c
2810+@@ -3011,6 +3024,13 @@
2811+ }
2812+
2813+ clust_rec = old_vers;
2814++ } else {
2815++ //TB_HOOK put_rec_to_row_cache
2816++ if (is_get_from_row_cache == FALSE && !prebuilt->templ_contains_blob
2817++ && !prebuilt->used_in_HANDLER) {
2818++ put_rec_to_row_cache(prebuilt->clust_ref, clust_rec, *offsets,
2819++ clust_index, FALSE);
2820++ }
2821+ }
2822+
2823+ /* If we had to go to an earlier version of row or the
2824+@@ -3356,6 +3376,18 @@
2825+ return(SEL_FOUND);
2826+ }
2827+
2828++static void put_rec_to_row_cache_in_sel(row_prebuilt_t* prebuilt,
2829++ ulint direction, ibool unique_search, const rec_t* rec, ulint* offsets,
2830++ dict_index_t* index, ibool is_sec_index) {
2831++ if (prebuilt->select_lock_type == LOCK_NONE && direction == 0
2832++ && unique_search && !prebuilt->templ_contains_blob
2833++ && !prebuilt->used_in_HANDLER) {
2834++ put_rec_to_row_cache(prebuilt->search_tuple, rec, offsets, index,
2835++ is_sec_index);
2836++ }
2837++}
2838++
2839++
2840+ /********************************************************************//**
2841+ Searches for rows in the database. This is used in the interface to
2842+ MySQL. This function opens a cursor, and also implements fetch next
2843+@@ -3417,6 +3449,7 @@
2844+ ibool same_user_rec;
2845+ mtr_t mtr;
2846+ mem_heap_t* heap = NULL;
2847++ ibool is_get_from_row_cache = FALSE;
2848+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
2849+ ulint* offsets = offsets_;
2850+ ibool table_lock_waited = FALSE;
2851+@@ -3929,14 +3962,26 @@
2852+
2853+ } else if (dtuple_get_n_fields(search_tuple) > 0) {
2854+
2855+- btr_pcur_open_with_no_init(index, search_tuple, mode,
2856+- BTR_SEARCH_LEAF,
2857+- pcur, 0, &mtr);
2858+-
2859++ //TB_HOOK get_from_row_cache
2860++ if(prebuilt->select_lock_type == LOCK_NONE
2861++ && trx->mysql_n_tables_locked == 0
2862++ && direction == 0
2863++ && unique_search
2864++ && !prebuilt->used_in_HANDLER){
2865++ rec = get_from_row_cache(search_tuple,index,&mtr);
2866++ if (rec != NULL)
2867++ {
2868++ is_get_from_row_cache = TRUE;
2869++ }
2870++ }
2871++ if(is_get_from_row_cache == FALSE){
2872++ btr_pcur_open_with_no_init(index, search_tuple, mode,
2873++ BTR_SEARCH_LEAF,
2874++ pcur, 0, &mtr);
2875++ rec = btr_pcur_get_rec(pcur);
2876++ }
2877+ pcur->trx_if_known = trx;
2878+
2879+- rec = btr_pcur_get_rec(pcur);
2880+-
2881+ if (!moves_up
2882+ && !page_rec_is_supremum(rec)
2883+ && set_also_gap_locks
2884+@@ -3979,9 +4024,10 @@
2885+ rec_loop:
2886+ /*-------------------------------------------------------------*/
2887+ /* PHASE 4: Look for matching records in a loop */
2888+-
2889+- rec = btr_pcur_get_rec(pcur);
2890+-
2891++ if (is_get_from_row_cache == FALSE)
2892++ {
2893++ rec = btr_pcur_get_rec(pcur);
2894++ }
2895+ if (srv_pass_corrupt_table && !rec) {
2896+ err = DB_CORRUPTION;
2897+ goto lock_wait_or_error;
2898+@@ -3998,122 +4044,123 @@
2899+ rec_print(rec);
2900+ */
2901+ #endif /* UNIV_SEARCH_DEBUG */
2902+-
2903+- if (page_rec_is_infimum(rec)) {
2904++ if(is_get_from_row_cache==FALSE){
2905++ if (page_rec_is_infimum(rec)) {
2906+
2907+- /* The infimum record on a page cannot be in the result set,
2908+- and neither can a record lock be placed on it: we skip such
2909+- a record. */
2910++ /* The infimum record on a page cannot be in the result set,
2911++ and neither can a record lock be placed on it: we skip such
2912++ a record. */
2913+
2914+- goto next_rec;
2915+- }
2916++ goto next_rec;
2917++ }
2918+
2919+- if (page_rec_is_supremum(rec)) {
2920++ if (page_rec_is_supremum(rec)) {
2921+
2922+- if (set_also_gap_locks
2923+- && !(srv_locks_unsafe_for_binlog
2924+- || trx->isolation_level <= TRX_ISO_READ_COMMITTED)
2925+- && prebuilt->select_lock_type != LOCK_NONE) {
2926++ if (set_also_gap_locks
2927++ && !(srv_locks_unsafe_for_binlog
2928++ || trx->isolation_level <= TRX_ISO_READ_COMMITTED)
2929++ && prebuilt->select_lock_type != LOCK_NONE) {
2930+
2931+- /* Try to place a lock on the index record */
2932++ /* Try to place a lock on the index record */
2933+
2934+- /* If innodb_locks_unsafe_for_binlog option is used
2935+- or this session is using a READ COMMITTED isolation
2936+- level we do not lock gaps. Supremum record is really
2937+- a gap and therefore we do not set locks there. */
2938++ /* If innodb_locks_unsafe_for_binlog option is used
2939++ or this session is using a READ COMMITTED isolation
2940++ level we do not lock gaps. Supremum record is really
2941++ a gap and therefore we do not set locks there. */
2942+
2943+- offsets = rec_get_offsets(rec, index, offsets,
2944+- ULINT_UNDEFINED, &heap);
2945+- err = sel_set_rec_lock(btr_pcur_get_block(pcur),
2946+- rec, index, offsets,
2947+- prebuilt->select_lock_type,
2948+- LOCK_ORDINARY, thr);
2949++ offsets = rec_get_offsets(rec, index, offsets,
2950++ ULINT_UNDEFINED, &heap);
2951++ err = sel_set_rec_lock(btr_pcur_get_block(pcur),
2952++ rec, index, offsets,
2953++ prebuilt->select_lock_type,
2954++ LOCK_ORDINARY, thr);
2955+
2956+- switch (err) {
2957+- case DB_SUCCESS_LOCKED_REC:
2958+- err = DB_SUCCESS;
2959+- case DB_SUCCESS:
2960+- break;
2961+- default:
2962+- goto lock_wait_or_error;
2963++ switch (err) {
2964++ case DB_SUCCESS_LOCKED_REC:
2965++ err = DB_SUCCESS;
2966++ case DB_SUCCESS:
2967++ break;
2968++ default:
2969++ goto lock_wait_or_error;
2970++ }
2971+ }
2972+- }
2973+- /* A page supremum record cannot be in the result set: skip
2974+- it now that we have placed a possible lock on it */
2975++ /* A page supremum record cannot be in the result set: skip
2976++ it now that we have placed a possible lock on it */
2977+
2978+- goto next_rec;
2979+- }
2980++ goto next_rec;
2981++ }
2982+
2983+- /*-------------------------------------------------------------*/
2984+- /* Do sanity checks in case our cursor has bumped into page
2985+- corruption */
2986++ /*-------------------------------------------------------------*/
2987++ /* Do sanity checks in case our cursor has bumped into page
2988++ corruption */
2989+
2990+- if (comp) {
2991+- next_offs = rec_get_next_offs(rec, TRUE);
2992+- if (UNIV_UNLIKELY(next_offs < PAGE_NEW_SUPREMUM)) {
2993++ if (comp) {
2994++ next_offs = rec_get_next_offs(rec, TRUE);
2995++ if (UNIV_UNLIKELY(next_offs < PAGE_NEW_SUPREMUM)) {
2996+
2997+- goto wrong_offs;
2998+- }
2999+- } else {
3000+- next_offs = rec_get_next_offs(rec, FALSE);
3001+- if (UNIV_UNLIKELY(next_offs < PAGE_OLD_SUPREMUM)) {
3002++ goto wrong_offs;
3003++ }
3004++ } else {
3005++ next_offs = rec_get_next_offs(rec, FALSE);
3006++ if (UNIV_UNLIKELY(next_offs < PAGE_OLD_SUPREMUM)) {
3007+
3008+- goto wrong_offs;
3009++ goto wrong_offs;
3010++ }
3011+ }
3012+- }
3013+
3014+- if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
3015++ if (UNIV_UNLIKELY(next_offs >= UNIV_PAGE_SIZE - PAGE_DIR)) {
3016+
3017+ wrong_offs:
3018+- if (srv_pass_corrupt_table && !trx_sys_sys_space(index->table->space)) {
3019+- index->table->is_corrupt = TRUE;
3020+- fil_space_set_corrupt(index->table->space);
3021+- }
3022++ if (srv_pass_corrupt_table && !trx_sys_sys_space(index->table->space)) {
3023++ index->table->is_corrupt = TRUE;
3024++ fil_space_set_corrupt(index->table->space);
3025++ }
3026+
3027+- if ((srv_force_recovery == 0 || moves_up == FALSE)
3028+- && srv_pass_corrupt_table <= 1) {
3029+- ut_print_timestamp(stderr);
3030+- buf_page_print(page_align(rec), 0);
3031+- fprintf(stderr,
3032+- "\nInnoDB: rec address %p,"
3033+- " buf block fix count %lu\n",
3034+- (void*) rec, (ulong)
3035+- btr_cur_get_block(btr_pcur_get_btr_cur(pcur))
3036+- ->page.buf_fix_count);
3037+- fprintf(stderr,
3038+- "InnoDB: Index corruption: rec offs %lu"
3039+- " next offs %lu, page no %lu,\n"
3040+- "InnoDB: ",
3041+- (ulong) page_offset(rec),
3042+- (ulong) next_offs,
3043+- (ulong) page_get_page_no(page_align(rec)));
3044+- dict_index_name_print(stderr, trx, index);
3045+- fputs(". Run CHECK TABLE. You may need to\n"
3046+- "InnoDB: restore from a backup, or"
3047+- " dump + drop + reimport the table.\n",
3048+- stderr);
3049++ if ((srv_force_recovery == 0 || moves_up == FALSE)
3050++ && srv_pass_corrupt_table <= 1) {
3051++ ut_print_timestamp(stderr);
3052++ buf_page_print(page_align(rec), 0);
3053++ fprintf(stderr,
3054++ "\nInnoDB: rec address %p,"
3055++ " buf block fix count %lu\n",
3056++ (void*) rec, (ulong)
3057++ btr_cur_get_block(btr_pcur_get_btr_cur(pcur))
3058++ ->page.buf_fix_count);
3059++ fprintf(stderr,
3060++ "InnoDB: Index corruption: rec offs %lu"
3061++ " next offs %lu, page no %lu,\n"
3062++ "InnoDB: ",
3063++ (ulong) page_offset(rec),
3064++ (ulong) next_offs,
3065++ (ulong) page_get_page_no(page_align(rec)));
3066++ dict_index_name_print(stderr, trx, index);
3067++ fputs(". Run CHECK TABLE. You may need to\n"
3068++ "InnoDB: restore from a backup, or"
3069++ " dump + drop + reimport the table.\n",
3070++ stderr);
3071+
3072+- err = DB_CORRUPTION;
3073++ err = DB_CORRUPTION;
3074+
3075+- goto lock_wait_or_error;
3076+- } else {
3077+- /* The user may be dumping a corrupt table. Jump
3078+- over the corruption to recover as much as possible. */
3079++ goto lock_wait_or_error;
3080++ } else {
3081++ /* The user may be dumping a corrupt table. Jump
3082++ over the corruption to recover as much as possible. */
3083+
3084+- fprintf(stderr,
3085+- "InnoDB: Index corruption: rec offs %lu"
3086+- " next offs %lu, page no %lu,\n"
3087+- "InnoDB: ",
3088+- (ulong) page_offset(rec),
3089+- (ulong) next_offs,
3090+- (ulong) page_get_page_no(page_align(rec)));
3091+- dict_index_name_print(stderr, trx, index);
3092+- fputs(". We try to skip the rest of the page.\n",
3093+- stderr);
3094++ fprintf(stderr,
3095++ "InnoDB: Index corruption: rec offs %lu"
3096++ " next offs %lu, page no %lu,\n"
3097++ "InnoDB: ",
3098++ (ulong) page_offset(rec),
3099++ (ulong) next_offs,
3100++ (ulong) page_get_page_no(page_align(rec)));
3101++ dict_index_name_print(stderr, trx, index);
3102++ fputs(". We try to skip the rest of the page.\n",
3103++ stderr);
3104+
3105+- btr_pcur_move_to_last_on_page(pcur, &mtr);
3106++ btr_pcur_move_to_last_on_page(pcur, &mtr);
3107+
3108+- goto next_rec;
3109++ goto next_rec;
3110++ }
3111+ }
3112+ }
3113+ /*-------------------------------------------------------------*/
3114+@@ -4364,7 +4411,11 @@
3115+
3116+ /* Do nothing: we let a non-locking SELECT read the
3117+ latest version of the record */
3118+-
3119++ //TB_HOOK put_rec_to_row_cache
3120++ if (is_get_from_row_cache == FALSE) {
3121++ put_rec_to_row_cache_in_sel(prebuilt, direction, unique_search,
3122++ rec, offsets, index, index != clust_index);
3123++ }
3124+ } else if (index == clust_index) {
3125+
3126+ /* Fetch a previous version of the row if the current
3127+@@ -4390,6 +4441,11 @@
3128+ }
3129+
3130+ if (old_vers == NULL) {
3131++ if (is_get_from_row_cache == TRUE) {
3132++ //this should be Phantom read
3133++ err = DB_RECORD_NOT_FOUND;
3134++ goto normal_return;
3135++ }
3136+ /* The row did not exist yet in
3137+ the read view */
3138+
3139+@@ -4397,6 +4453,13 @@
3140+ }
3141+
3142+ rec = old_vers;
3143++ } else {
3144++ //TB_HOOK put_rec_to_row_cache
3145++ if (is_get_from_row_cache == FALSE) {
3146++ put_rec_to_row_cache_in_sel(prebuilt, direction,
3147++ unique_search, rec, offsets, index,
3148++ index != clust_index);
3149++ }
3150+ }
3151+ } else {
3152+ /* We are looking into a non-clustered index,
3153+@@ -4407,9 +4470,19 @@
3154+
3155+ ut_ad(!dict_index_is_clust(index));
3156+
3157+- if (!lock_sec_rec_cons_read_sees(
3158+- rec, trx->read_view)) {
3159++ if ((is_get_from_row_cache == FALSE
3160++ && !lock_sec_rec_cons_read_sees(rec, trx->read_view))
3161++ || (is_get_from_row_cache == TRUE
3162++ && !lock_sec_rec_in_row_cache_cons_read_sees(rec,
3163++ offsets, trx->read_view))) {
3164+ goto requires_clust_rec;
3165++ } else {
3166++ //TB_HOOK put_rec_to_row_cache
3167++ if (is_get_from_row_cache == FALSE) {
3168++ put_rec_to_row_cache_in_sel(prebuilt, direction,
3169++ unique_search, rec, offsets, index,
3170++ index != clust_index);
3171++ }
3172+ }
3173+ }
3174+ }
3175+@@ -4483,7 +4556,13 @@
3176+ if (clust_rec == NULL) {
3177+ /* The record did not exist in the read view */
3178+ ut_ad(prebuilt->select_lock_type == LOCK_NONE);
3179++ if(is_get_from_row_cache == TRUE){
3180++ // when is is_get_from_row_cache ,if clust_rec == NULL mean there is not record which can be
3181++ // read by this trx
3182++ err = DB_RECORD_NOT_FOUND;
3183+
3184++ goto normal_return;
3185++ }
3186+ goto next_rec;
3187+ }
3188+ break;
3189+@@ -4573,6 +4652,10 @@
3190+ goto got_row;
3191+ }
3192+
3193++ if(is_get_from_row_cache == TRUE){
3194++ goto got_row;
3195++ }
3196++
3197+ goto next_rec;
3198+ } else {
3199+ if (UNIV_UNLIKELY
3200+@@ -4634,10 +4717,11 @@
3201+ return 'end of file'. Exceptions are locking reads and the MySQL
3202+ HANDLER command where the user can move the cursor with PREV or NEXT
3203+ even after a unique search. */
3204+-
3205+- if (!unique_search_from_clust_index
3206+- || prebuilt->select_lock_type != LOCK_NONE
3207+- || prebuilt->used_in_HANDLER) {
3208++ //if get from row_cache ,it is no next or prev
3209++ if (is_get_from_row_cache == FALSE
3210++ && (!unique_search_from_clust_index
3211++ || prebuilt->select_lock_type != LOCK_NONE
3212++ || prebuilt->used_in_HANDLER)) {
3213+
3214+ /* Inside an update always store the cursor position */
3215+
3216+@@ -4649,6 +4733,7 @@
3217+ goto normal_return;
3218+
3219+ next_rec:
3220++ ut_ad(is_get_from_row_cache == FALSE);
3221+ /* Reset the old and new "did semi-consistent read" flags. */
3222+ if (UNIV_UNLIKELY(prebuilt->row_read_type
3223+ == ROW_READ_DID_SEMI_CONSISTENT)) {
3224+Index: storage/innobase/row/row0umod.c
3225+===================================================================
3226+--- storage/innobase/row/row0umod.c (revision 498)
3227++++ storage/innobase/row/row0umod.c (revision 724)
3228+@@ -43,6 +43,8 @@
3229+ #include "row0upd.h"
3230+ #include "que0que.h"
3231+ #include "log0log.h"
3232++#include "row0cache.h"
3233++#include "btr0sea.h"
3234+
3235+ /* Considerations on undoing a modify operation.
3236+ (1) Undoing a delete marking: all index records should be found. Some of
3237+@@ -128,6 +130,26 @@
3238+
3239+ ut_ad(success);
3240+
3241++ //TB_HOOK
3242++ {
3243++ dict_index_t* index;
3244++ rec_t* rec;
3245++ mem_heap_t* heap = NULL;
3246++ ulint offsets_[REC_OFFS_NORMAL_SIZE];
3247++ ulint* offsets;
3248++ rec_offs_init(offsets_);
3249++
3250++ index = dict_table_get_first_index(node->table);
3251++ //TB_HOOK
3252++ rec = btr_pcur_get_rec(pcur);
3253++ offsets = rec_get_offsets(rec, index, offsets_, ULINT_UNDEFINED, &heap);
3254++ remove_from_row_cache(rec, offsets, index);
3255++
3256++ if (UNIV_LIKELY_NULL(heap)) {
3257++ mem_heap_free(heap);
3258++ }
3259++ }
3260++
3261+ if (mode == BTR_MODIFY_LEAF) {
3262+
3263+ err = btr_cur_optimistic_update(BTR_NO_LOCKING_FLAG
3264+@@ -597,6 +619,10 @@
3265+ transactions. */
3266+ ut_a(thr_is_recv(thr));
3267+ } else {
3268++ //TB_HOOK
3269++ if(dict_index_is_unique(index)){
3270++ remove_from_row_cache_for_tuple(entry , index);
3271++ }
3272+ err = row_undo_mod_del_mark_or_remove_sec(
3273+ node, thr, index, entry);
3274+
3275+@@ -646,6 +672,10 @@
3276+ entry = row_build_index_entry(node->row, node->ext,
3277+ index, heap);
3278+ ut_a(entry);
3279++ //TB_HOOK
3280++ if(dict_index_is_unique(index)){
3281++ remove_from_row_cache_for_tuple(entry , index);
3282++ }
3283+ err = row_undo_mod_del_unmark_sec_and_undo_update(
3284+ BTR_MODIFY_LEAF, thr, index, entry);
3285+ if (err == DB_FAIL) {
3286+@@ -746,7 +776,10 @@
3287+ version of it, if the secondary index record
3288+ through which we do the search is
3289+ delete-marked. */
3290+-
3291++ //TB_HOOK
3292++ if(dict_index_is_unique(index)){
3293++ remove_from_row_cache_for_tuple(entry , index);
3294++ }
3295+ err = row_undo_mod_del_mark_or_remove_sec(
3296+ node, thr, index, entry);
3297+ if (err != DB_SUCCESS) {
3298+Index: sql/handler.h
3299+===================================================================
3300+--- sql/handler.h (revision 498)
3301++++ sql/handler.h (revision 724)
3302+@@ -1579,6 +1579,10 @@
3303+ DBUG_ASSERT(FALSE);
3304+ return HA_ERR_WRONG_COMMAND;
3305+ }
3306++ virtual bool ha_is_in_cache(const uchar * key, key_part_map keypart_map) {
3307++ uint key_len = calculate_key_len(table, active_index, key, keypart_map);
3308++ return is_in_cache(key, key_len);
3309++ }
3310+ /**
3311+ @brief
3312+ Positions an index cursor to the index specified in the handle. Fetches the
3313+@@ -2069,6 +2073,8 @@
3314+ virtual int open(const char *name, int mode, uint test_if_locked)=0;
3315+ virtual int index_init(uint idx, bool sorted) { active_index= idx; return 0; }
3316+ virtual int index_end() { active_index= MAX_KEY; return 0; }
3317++ virtual bool is_in_cache(const uchar * key,
3318++ uint key_len){return false;}
3319+ /**
3320+ rnd_init() can be called two times without rnd_end() in between
3321+ (it only makes sense if scan=1).

Subscribers

People subscribed via source and target branches