MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
DbtuxSearch.cpp
1 /*
2  Copyright (C) 2004-2006 MySQL AB, 2009 Sun Microsystems, Inc.
3  All rights reserved. Use is subject to license terms.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 #define DBTUX_SEARCH_CPP
20 #include "Dbtux.hpp"
21 
22 /*
23  * Search down non-empty tree for node to update. Compare search key to
24  * each node minimum. If greater, move to right subtree. This can
25  * overshoot target node. The last such node is saved. The search ends
26  * at a final node which is a semi-leaf or leaf. If search key is less
27  * than final node minimum then the saved node (if any) is the g.l.b of
28  * the final node and we move back to it.
29  *
30  * Search within the found node is done by caller. On add, search key
31  * may be before minimum or after maximum entry. On remove, search key
32  * is within the node.
33  */
34 void
35 Dbtux::findNodeToUpdate(TuxCtx& ctx, Frag& frag, const KeyDataC& searchKey, TreeEnt searchEnt, NodeHandle& currNode)
36 {
37  const Index& index = *c_indexPool.getPtr(frag.m_indexId);
38  const Uint32 numAttrs = index.m_numAttrs;
39  const Uint32 prefAttrs = index.m_prefAttrs;
40  const Uint32 prefBytes = index.m_prefBytes;
41  KeyData entryKey(index.m_keySpec, false, 0);
42  entryKey.set_buf(ctx.c_entryKey, MaxAttrDataSize << 2);
43  KeyDataC prefKey(index.m_keySpec, false);
44  NodeHandle glbNode(frag); // potential g.l.b of final node
45  while (true) {
46  thrjam(ctx.jamBuffer);
47  selectNode(currNode, currNode.m_loc);
48  prefKey.set_buf(currNode.getPref(), prefBytes, prefAttrs);
49  int ret = 0;
50  if (prefAttrs > 0) {
51  thrjam(ctx.jamBuffer);
52  ret = cmpSearchKey(ctx, searchKey, prefKey, prefAttrs);
53  }
54  if (ret == 0 && prefAttrs < numAttrs) {
55  thrjam(ctx.jamBuffer);
56  // read and compare all attributes
57  readKeyAttrs(ctx, frag, currNode.getEnt(0), entryKey, numAttrs);
58  ret = cmpSearchKey(ctx, searchKey, entryKey, numAttrs);
59  }
60  if (ret == 0) {
61  thrjam(ctx.jamBuffer);
62  // keys are equal, compare entry values
63  ret = searchEnt.cmp(currNode.getEnt(0));
64  }
65  if (ret < 0) {
66  thrjam(ctx.jamBuffer);
67  const TupLoc loc = currNode.getLink(0);
68  if (loc != NullTupLoc) {
69  thrjam(ctx.jamBuffer);
70  // continue to left subtree
71  currNode.m_loc = loc;
72  continue;
73  }
74  if (! glbNode.isNull()) {
75  thrjam(ctx.jamBuffer);
76  // move up to the g.l.b
77  currNode = glbNode;
78  }
79  break;
80  }
81  if (ret > 0) {
82  thrjam(ctx.jamBuffer);
83  const TupLoc loc = currNode.getLink(1);
84  if (loc != NullTupLoc) {
85  thrjam(ctx.jamBuffer);
86  // save potential g.l.b
87  glbNode = currNode;
88  // continue to right subtree
89  currNode.m_loc = loc;
90  continue;
91  }
92  break;
93  }
94  // ret == 0
95  thrjam(ctx.jamBuffer);
96  break;
97  }
98 }
99 
100 /*
101  * Find position within the final node to add entry to. Use binary
102  * search. Return true if ok i.e. entry to add is not a duplicate.
103  */
104 bool
105 Dbtux::findPosToAdd(TuxCtx& ctx, Frag& frag, const KeyDataC& searchKey, TreeEnt searchEnt, NodeHandle& currNode, TreePos& treePos)
106 {
107  const Index& index = *c_indexPool.getPtr(frag.m_indexId);
108  int lo = -1;
109  int hi = (int)currNode.getOccup();
110  KeyData entryKey(index.m_keySpec, false, 0);
111  entryKey.set_buf(ctx.c_entryKey, MaxAttrDataSize << 2);
112  while (hi - lo > 1) {
113  thrjam(ctx.jamBuffer);
114  // hi - lo > 1 implies lo < j < hi
115  int j = (hi + lo) / 2;
116  // read and compare all attributes
117  readKeyAttrs(ctx, frag, currNode.getEnt(j), entryKey, index.m_numAttrs);
118  int ret = cmpSearchKey(ctx, searchKey, entryKey, index.m_numAttrs);
119  if (ret == 0) {
120  thrjam(ctx.jamBuffer);
121  // keys are equal, compare entry values
122  ret = searchEnt.cmp(currNode.getEnt(j));
123  }
124  if (ret < 0) {
125  thrjam(ctx.jamBuffer);
126  hi = j;
127  } else if (ret > 0) {
128  thrjam(ctx.jamBuffer);
129  lo = j;
130  } else {
131  treePos.m_pos = j;
132  // entry found - error
133  return false;
134  }
135  }
136  ndbrequire(hi - lo == 1);
137  // return hi pos, see treeAdd() for next step
138  treePos.m_pos = hi;
139  return true;
140 }
141 
142 /*
143  * Find position within the final node to remove entry from. Use linear
144  * search. Return true if ok i.e. the entry was found.
145  */
146 bool
147 Dbtux::findPosToRemove(TuxCtx& ctx, Frag& frag, const KeyDataC& searchKey, TreeEnt searchEnt, NodeHandle& currNode, TreePos& treePos)
148 {
149  const unsigned occup = currNode.getOccup();
150  for (unsigned j = 0; j < occup; j++) {
151  thrjam(ctx.jamBuffer);
152  // compare only the entry
153  if (searchEnt.eq(currNode.getEnt(j))) {
154  thrjam(ctx.jamBuffer);
155  treePos.m_pos = j;
156  return true;
157  }
158  }
159  treePos.m_pos = occup;
160  // not found - failed
161  return false;
162 }
163 
164 /*
165  * Search for entry to add.
166  */
167 bool
168 Dbtux::searchToAdd(TuxCtx& ctx, Frag& frag, const KeyDataC& searchKey, TreeEnt searchEnt, TreePos& treePos)
169 {
170  const TreeHead& tree = frag.m_tree;
171  NodeHandle currNode(frag);
172  currNode.m_loc = tree.m_root;
173  if (unlikely(currNode.m_loc == NullTupLoc)) {
174  // empty tree
175  thrjam(ctx.jamBuffer);
176  return true;
177  }
178  findNodeToUpdate(ctx, frag, searchKey, searchEnt, currNode);
179  treePos.m_loc = currNode.m_loc;
180  if (! findPosToAdd(ctx, frag, searchKey, searchEnt, currNode, treePos)) {
181  thrjam(ctx.jamBuffer);
182  return false;
183  }
184  return true;
185 }
186 
187 /*
188  * Search for entry to remove.
189  */
190 bool
191 Dbtux::searchToRemove(TuxCtx& ctx, Frag& frag, const KeyDataC& searchKey, TreeEnt searchEnt, TreePos& treePos)
192 {
193  const TreeHead& tree = frag.m_tree;
194  NodeHandle currNode(frag);
195  currNode.m_loc = tree.m_root;
196  if (unlikely(currNode.m_loc == NullTupLoc)) {
197  // empty tree - failed
198  thrjam(ctx.jamBuffer);
199  return false;
200  }
201  findNodeToUpdate(ctx, frag, searchKey, searchEnt, currNode);
202  treePos.m_loc = currNode.m_loc;
203  if (! findPosToRemove(ctx, frag, searchKey, searchEnt, currNode, treePos)) {
204  thrjam(ctx.jamBuffer);
205  return false;
206  }
207  return true;
208 }
209 
210 /*
211  * Search down non-empty tree for node to start scan from. Similar to
212  * findNodeToUpdate(). Direction is 0-ascending or 1-descending.
213  * Search within the found node is done by caller.
214  */
215 void
216 Dbtux::findNodeToScan(Frag& frag, unsigned idir, const KeyBoundC& searchBound, NodeHandle& currNode)
217 {
218  const int jdir = 1 - 2 * int(idir);
219  const Index& index = *c_indexPool.getPtr(frag.m_indexId);
220  const Uint32 numAttrs = searchBound.get_data().get_cnt();
221  const Uint32 prefAttrs = min(index.m_prefAttrs, numAttrs);
222  const Uint32 prefBytes = index.m_prefBytes;
223  KeyData entryKey(index.m_keySpec, false, 0);
224  entryKey.set_buf(c_ctx.c_entryKey, MaxAttrDataSize << 2);
225  KeyDataC prefKey(index.m_keySpec, false);
226  NodeHandle glbNode(frag); // potential g.l.b of final node
227  while (true) {
228  jam();
229  selectNode(currNode, currNode.m_loc);
230  prefKey.set_buf(currNode.getPref(), prefBytes, prefAttrs);
231  int ret = 0;
232  if (numAttrs > 0) {
233  if (prefAttrs > 0) {
234  jam();
235  // compare node prefix - result 0 implies bound is longer
236  ret = cmpSearchBound(c_ctx, searchBound, prefKey, prefAttrs);
237  }
238  if (ret == 0) {
239  jam();
240  // read and compare all attributes
241  readKeyAttrs(c_ctx, frag, currNode.getEnt(0), entryKey, numAttrs);
242  ret = cmpSearchBound(c_ctx, searchBound, entryKey, numAttrs);
243  ndbrequire(ret != 0);
244  }
245  } else {
246  jam();
247  ret = (-1) * jdir;
248  }
249  if (ret < 0) {
250  // bound is left of this node
251  jam();
252  const TupLoc loc = currNode.getLink(0);
253  if (loc != NullTupLoc) {
254  jam();
255  // continue to left subtree
256  currNode.m_loc = loc;
257  continue;
258  }
259  if (! glbNode.isNull()) {
260  jam();
261  // move up to the g.l.b
262  currNode = glbNode;
263  }
264  break;
265  }
266  if (ret > 0) {
267  // bound is at or right of this node
268  jam();
269  const TupLoc loc = currNode.getLink(1);
270  if (loc != NullTupLoc) {
271  jam();
272  // save potential g.l.b
273  glbNode = currNode;
274  // continue to right subtree
275  currNode.m_loc = loc;
276  continue;
277  }
278  break;
279  }
280  // ret == 0 never
281  ndbrequire(false);
282  }
283 }
284 
285 /*
286  * Search across final node for position to start scan from. Use binary
287  * search similar to findPosToAdd().
288  */
289 void
290 Dbtux::findPosToScan(Frag& frag, unsigned idir, const KeyBoundC& searchBound, NodeHandle& currNode, Uint16* pos)
291 {
292  const int jdir = 1 - 2 * int(idir);
293  const Index& index = *c_indexPool.getPtr(frag.m_indexId);
294  const Uint32 numAttrs = searchBound.get_data().get_cnt();
295  int lo = -1;
296  int hi = (int)currNode.getOccup();
297  KeyData entryKey(index.m_keySpec, false, 0);
298  entryKey.set_buf(c_ctx.c_entryKey, MaxAttrDataSize << 2);
299  while (hi - lo > 1) {
300  jam();
301  // hi - lo > 1 implies lo < j < hi
302  int j = (hi + lo) / 2;
303  int ret = (-1) * jdir;
304  if (numAttrs != 0) {
305  // read and compare all attributes
306  readKeyAttrs(c_ctx, frag, currNode.getEnt(j), entryKey, numAttrs);
307  ret = cmpSearchBound(c_ctx, searchBound, entryKey, numAttrs);
308  ndbrequire(ret != 0);
309  }
310  if (ret < 0) {
311  jam();
312  hi = j;
313  } else if (ret > 0) {
314  jam();
315  lo = j;
316  } else {
317  // ret == 0 never
318  ndbrequire(false);
319  }
320  }
321  // return hi pos, caller handles ascending vs descending
322  *pos = hi;
323 }
324 
325 /*
326  * Search for scan start position.
327  */
328 void
329 Dbtux::searchToScan(Frag& frag, unsigned idir, const KeyBoundC& searchBound, TreePos& treePos)
330 {
331  const TreeHead& tree = frag.m_tree;
332  NodeHandle currNode(frag);
333  currNode.m_loc = tree.m_root;
334  if (unlikely(currNode.m_loc == NullTupLoc)) {
335  // empty tree
336  jam();
337  return;
338  }
339  findNodeToScan(frag, idir, searchBound, currNode);
340  treePos.m_loc = currNode.m_loc;
341  Uint16 pos;
342  findPosToScan(frag, idir, searchBound, currNode, &pos);
343  const unsigned occup = currNode.getOccup();
344  if (idir == 0) {
345  if (pos < occup) {
346  jam();
347  treePos.m_pos = pos;
348  treePos.m_dir = 3;
349  } else {
350  // start scan after node end i.e. proceed to right child
351  treePos.m_pos = ZNIL;
352  treePos.m_dir = 5;
353  }
354  } else {
355  if (pos > 0) {
356  jam();
357  // start scan from previous entry
358  treePos.m_pos = pos - 1;
359  treePos.m_dir = 3;
360  } else {
361  treePos.m_pos = ZNIL;
362  treePos.m_dir = 0;
363  }
364  }
365 }