ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Tree-M/MT/BulkLoad.cpp
Revision: 1.2
Committed: Wed May 23 02:11:14 2001 UTC (23 years ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.1: +4 -2 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 /*********************************************************************
2     * *
3     * Copyright (c) 1997,1998, 1999 *
4     * Multimedia DB Group and DEIS - CSITE-CNR, *
5     * University of Bologna, Bologna, ITALY. *
6     * *
7     * All Rights Reserved. *
8     * *
9     * Permission to use, copy, and distribute this software and its *
10     * documentation for NON-COMMERCIAL purposes and without fee is *
11     * hereby granted provided that this copyright notice appears in *
12     * all copies. *
13     * *
14     * THE AUTHORS MAKE NO REPRESENTATIONS OR WARRANTIES ABOUT THE *
15     * SUITABILITY OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING *
16     * BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, *
17     * FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. THE AUTHOR *
18     * SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A *
19     * RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS *
20     * DERIVATIVES. *
21     * *
22     *********************************************************************/
23    
24     #ifdef UNIX
25     #include <unistd.h>
26     #endif
27     #include "MT.h"
28    
29     extern double MIN_UTIL;
30    
31     // find the node having the minimum number of children
32     // this is used in the redistributing phase of the BulkLoad algorithm
33     int
34     FindMin(int *children, int max)
35     {
36     int j, jmin=0;
37    
38     for(j=1; j<max; j++)
39     if(children[j]<children[jmin]) jmin=j;
40     return jmin;
41     }
42    
43     // return root level+1 (the height of the tree)
44     // this is used in the "splitting" phase of the BulkLoad algorithm
45     int
46     MT::MaxLevel() const
47     {
48     GiSTnode *root;
49     GiSTpath path;
50     int i;
51    
52     path.MakeRoot();
53     root=ReadNode(path);
54     i=root->Level();
55     delete root;
56     return i+1;
57     }
58    
59     // split this M-tree into a list of trees having height level
60     // this is used in the "splitting" phase of the BulkLoad algorithm
61     GiSTlist<char *> *
62     MT::SplitTree(int *ncreated, int level, GiSTlist<MTentry *> *children, char *name)
63     // ncreated is the number of created sub-trees,
64     // level is the split level for the tree,
65     // children is the list of the parents of each sub-tree,
66     // name is the root for the sub-trees names
67     // the return value is the list of splitted sub-trees
68     {
69     GiSTlist<char *> *trees=new GiSTlist<char *>; // this is the results list
70     GiSTlist<MTnode *> *oldList=new GiSTlist<MTnode *>; // this is the nodes list
71     GiSTpath path;
72     MTnode *node=new MTnode; // this is because the first operation on node is a delete
73     char newname[50];
74    
75     path.MakeRoot();
76     oldList->Append((MTnode *)ReadNode(path));
77     do { // build the roots list
78     GiSTlist<MTnode *> *newList=new GiSTlist<MTnode *>; // this is the list of the current level nodes
79    
80     while(!oldList->IsEmpty()) {
81     delete node; // delete the old node created by ReadNode
82     node=oldList->RemoveFront(); // retrieve next node to be examined
83     path=node->Path();
84     for(int i=0; i<node->NumEntries(); i++) { // append all its children to the new list
85     MTentry *e=(MTentry *)(*node)[i].Ptr();
86    
87     path.MakeChild(e->Ptr());
88     newList->Append((MTnode *)ReadNode(path));
89     path.MakeParent();
90     }
91     }
92     delete oldList;
93     oldList=newList;
94     } while(node->Level()>level); // stop if we're at the split level
95     delete node;
96     while(!oldList->IsEmpty()) { // now append each sub-tree to its root
97 root 1.2 MT *subtree=new MT (4096);
98     assert (!"fixme: pagesize above taken wherefrom?");
99 root 1.1 MTnode *newnode;
100    
101     node=oldList->RemoveFront();
102     sprintf(newname, "%s.%i", name, ++(*ncreated));
103     unlink(newname); // if this M-tree already exists, delete it
104     subtree->Create(newname); // create a new M-tree
105     path.MakeRoot();
106     newnode=(MTnode *)subtree->ReadNode(path); // read the root of the tree
107     subtree->Append(newnode, (MTnode *)node->Copy()); // append the sub-tree of current node to the root of this M-tree
108     children->Append(node->Entry()); // insert the root entry into the list
109     trees->Append(strdup(newname)); // insert the new M-tree name into the list
110     delete node;
111     delete newnode;
112     delete subtree;
113     }
114     delete oldList;
115     return trees;
116     }
117    
118     // load this M-tree with n data using the BulkLoad algorithm [CP98]
119     void
120     MT::BulkLoad(MTentry **data, int n, double padFactor, char *name)
121     // data is an array of n entries
122     // padFactor is the maximum node utilization (use 1)
123     // name is the name of the tree
124     {
125     int i, Size=0, totSize, addEntrySize=(sizeofEntry()? sizeof(GiSTpage): sizeof(GiSTlte)+sizeof(GiSTpage)), minSize=(int)(Store()->PageSize()*MIN_UTIL), NumEntries; // this is the total size of entries
126    
127     if(sizeofEntry()) Size=n*(sizeof(GiSTpage)+sizeofEntry()); // (only valid if we've fixed size entries)
128     else for(i=0; i<n; i++) Size+=sizeof(GiSTlte)+sizeof(GiSTpage)+data[i]->CompressedLength();
129     totSize=Size+GIST_PAGE_HEADER_SIZE+sizeof(GiSTlte);
130     NumEntries=(int)(Store()->PageSize()*padFactor*n)/totSize;
131     // cout << "exp. size=" << totSize << endl;
132     if(totSize>Store()->PageSize()) { // we need to split the entries into several sub-trees
133     GiSTlist<char *> nameslist, othernameslist; // list of the sub-trees names
134     GiSTlist<MTentry *> plist, parentslist; // lists of the root entries of each sub-tree
135     GiSTlist<int> *lists=NULL; // list of entries for each sub-tree
136     GiSTlist<double> *dists=NULL; // list of distances for each sub-tree
137     char **trees; // array of the sub-trees names
138     GiSTlist<MTnode *> *oldList=new GiSTlist<MTnode *>;
139     GiSTpath path;
140     MTentry ***arrays; // array of the entries for each sub-tree
141     MTentry **parents; // array of the root entries for each sub-tree
142     MTnode *node=NULL;
143     GiSTlist<double *> *distm; // distance matrix
144     int s=(int)MAX(MIN(NumEntries, ceil(((float)n)/NumEntries)), NumEntries*MIN_UTIL); // initial number of samples
145     int j, nsamples, *samples=new int[s], *sizes=NULL, *ns=NULL, ncreated=0, minLevel=MAXINT, nInit, l, iters=0, MAXITER=s*s;
146     char newname[50];
147     BOOL *sampled=new BOOL[n]; // is this entry in the samples set?
148    
149     // cout << "NE*pF=" << NumEntries*padFactor << ", n/NE*pF=" << n/floor(NumEntries*padFactor) << ", s=" << s << endl;
150     distm=(GiSTlist<double *> *)calloc(s,sizeof(GiSTlist<double *>));
151     do { // sampling phase
152     iters++;
153     if(iters>1) { // this is a new sampling phase
154     // cout << "Re-sampling: " << iters << "/" << MAXITER << endl;
155     while(!lists[0].IsEmpty()) {
156     lists[0].RemoveFront();
157     dists[0].RemoveFront();
158     }
159     delete []lists;
160     delete []dists;
161     delete []sizes;
162     delete []ns;
163     while(!distm[0].IsEmpty()) delete []distm[0].RemoveFront(); // empty the distance list
164     for(i=1; i<s; i++) distm[i].front=distm[i].rear=NULL;
165     }
166     // if(iters>=MAXITER) minSize=0;
167     if(iters>=MAXITER) {
168     cout << "Too many loops in BulkLoad!\nPlease select a lower minimum node utilization or a bigger node size.\n";
169     exit(1);
170     }
171     nsamples=0;
172     for(i=0; i<n; i++) sampled[i]=FALSE;
173     // pick samples to create parents
174     while(nsamples<s) {
175     do i=PickRandom(0, n);
176     while(sampled[i]);
177     sampled[i]=TRUE;
178     samples[nsamples++]=i;
179     }
180     // cout << "Samples:\n";
181     // for(i=0; i<s; i++) cout << "\t" << i << ":\t" << data[samples[i]];
182     lists=new GiSTlist<int>[s];
183     dists=new GiSTlist<double>[s];
184     sizes=new int[s];
185     ns=new int[s];
186     for(i=0; i<s; i++) {
187     sizes[i]=GIST_PAGE_HEADER_SIZE+sizeof(GiSTlte);
188     ns[i]=1;
189     }
190     for(i=0; i<s; i++) distm[i].Prepend(new double[s]);
191     for(i=0; i<s; i++) { // compute the relative distances between samples
192     for(j=0; j<i; j++)
193     distm[j].front->entry[i]=(distm[i].front->entry[j]=data[samples[j]]->object().distance(data[samples[i]]->object()));
194     distm[i].front->entry[i]=0;
195     }
196     for(i=0; i<n; i++) { // assign each entry to its nearest parent
197     // cout << "Now assigning " << data[i];
198     if(sampled[i]) {
199     for(j=0; samples[j]!=i; j++);
200     lists[j].Prepend(i); // insert the entry in the right list
201     dists[j].Prepend(0);
202     sizes[j]+=addEntrySize+data[i]->CompressedLength();
203     // cout << "\tAssigned (0) to " << j << ", " << data[samples[j]];
204     }
205     else { // here we optimize the distance computations (like we do in the insert algorithm)
206     double *dist=new double[s];
207     int minindex=0;
208    
209     dist[0]=data[samples[0]]->object().distance(data[i]->object());
210     for(j=1; j<s; j++) {
211     BOOL cont=TRUE;
212    
213     dist[j]=-1;
214     if(fabs(data[samples[j]]->Key()->distance-data[i]->Key()->distance)>dist[minindex]) continue; // pruning for reference point (parent)
215     for(int k=0; (k<j)&&cont; k++) // pruning for reference points (other samples)
216     if(dist[k]<0) continue;
217     else cont=(fabs(dist[k]-distm[j].front->entry[k])<dist[minindex]);
218     if(!cont) continue;
219     dist[j]=data[samples[j]]->object().distance(data[i]->object()); // we have to compute this distance
220     if(dist[j]<dist[minindex]) minindex=j;
221     }
222     // cout << "\tAssigned (" << dist[minindex] << ") to " << minindex << ", " << data[samples[minindex]];
223     lists[minindex].Append(i);
224     dists[minindex].Append(dist[minindex]);
225     sizes[minindex]+=addEntrySize+data[i]->CompressedLength();
226     ns[minindex]++;
227     if(sizes[minindex]>=minSize) delete []dist;
228     else distm[minindex].Append(dist);
229     }
230     }
231     // redistribute underfilled parents
232     // cout << "Underfilled parents redistribution...\n";
233     while(sizes[i=FindMin(sizes, nsamples)]<minSize) {
234     GiSTlist<int> list=lists[i];
235     GiSTlist<double *> dlist=distm[i];
236    
237     while(!dists[i].IsEmpty()) dists[i].RemoveFront();
238     // cout << "Redistributing " << i << "' set (" << sizes[i] << "/" << minSize << ")...\n";
239     for(j=0; j<nsamples; j++)
240     for(GiSTlistnode<double *> *lnode=distm[j].front; lnode; lnode=lnode->next) lnode->entry[i]=lnode->entry[nsamples-1];
241     // substitute this set with last set
242     distm[i]=distm[nsamples-1];
243     lists[i]=lists[nsamples-1];
244     dists[i]=dists[nsamples-1];
245     samples[i]=samples[nsamples-1];
246     sizes[i]=sizes[nsamples-1];
247     ns[i]=ns[nsamples-1];
248     nsamples--;
249     while(!list.IsEmpty()) { // assign each entry to its nearest parent
250     double *d=dlist.RemoveFront();
251     int k=list.RemoveFront(), index, minindex=-1;
252     // cout << "Now assigning " << data[k];
253    
254     for(index=0; (index<nsamples)&&(minindex<0); index++) // search for a computed distance
255     if(d[index]>0) minindex=index;
256     if(minindex<0) { // no distance was computed (i.e. all distances were pruned)
257     d[0]=data[samples[0]]->object().distance(data[k]->object());
258     minindex=0;
259     }
260     for(index=0; index<nsamples; index++) {
261     BOOL cont=TRUE;
262    
263     if(index==minindex) continue;
264     if(d[index]<0) { // distance wasn't computed
265     if(fabs(data[samples[index]]->Key()->distance-data[k]->Key()->distance)>d[minindex]) continue; // pruning for reference point (parent)
266     for(l=0; (l<index)&&cont; l++) // pruning for reference points (other samples)
267     if(d[l]<0) continue;
268     else cont=(fabs(d[l]-distm[index].front->entry[l])<d[minindex]);
269     if(!cont) continue;
270     d[index]=data[samples[index]]->object().distance(data[k]->object()); // we have to compute this distance
271     }
272     if(d[index]<d[minindex]) minindex=index;
273     }
274     // cout << "\tAssigned (" << d[minindex] << ") to " << minindex << ", " << data[samples[minindex]];
275     lists[minindex].Append(k);
276     dists[minindex].Append(d[minindex]);
277     sizes[minindex]+=addEntrySize+data[k]->CompressedLength();
278     ns[minindex]++;
279     if(sizes[minindex]>=minSize) delete []d;
280     else distm[minindex].Append(d);
281     }
282     assert(dlist.IsEmpty());
283     }
284     } while(nsamples==1); // if there's only one child, repeat the sampling phase
285     // cout << "Samples:\n";
286     // for(i=0; i<nsamples; i++) cout << "\t" << i << ": " << data[samples[i]];
287     arrays=new MTentry **[nsamples];
288     for(i=0; i<nsamples; i++) { // convert the lists into arrays
289     arrays[i]=new MTentry *[ns[i]];
290     for(j=0; j<ns[i]; j++) {
291     int k=lists[i].RemoveFront();
292    
293     arrays[i][j]=(MTentry *)data[k]->Copy();
294     arrays[i][j]->Key()->distance=dists[i].RemoveFront();
295     }
296     assert(lists[i].IsEmpty());
297     assert(dists[i].IsEmpty());
298     }
299     delete []dists;
300     delete []lists;
301     for(i=0; i<nsamples; i++)
302     while(!distm[i].IsEmpty())
303     delete [](distm[i].RemoveFront());
304     free(distm);
305     // build an M-tree under each parent
306     nInit=nsamples;
307     // cout << "Now building " << nsamples << " sub-trees...\n";
308 root 1.2 MT *tree=new MT (4096);
309     assert (!"fixme: pagesize above taken wherefrom?");
310 root 1.1
311     // for(i=0; i<nsamples; i++) cout << i+1 << "' set: " << ns[i] << endl;
312     for(i=0; i<nInit; i++) {
313     MTnode *root;
314     GiSTpath path;
315    
316     sprintf(newname, "%s.%i", name, ++ncreated);
317     unlink(newname);
318     tree->Create(newname); // create the new sub-tree
319     // cout << "Now building sub-tree " << newname << " on " << ns[i] << " data (exp. size=" << sizes[i] << ")...\n";
320     tree->BulkLoad(arrays[i], ns[i], padFactor, newname); // insert the data into the sub-tree
321     // cout << "Tree level=" << tree->MaxLevel() << endl;
322     // if the root node is underfilled, we have to split the tree
323     path.MakeRoot();
324     root=(MTnode *)tree->ReadNode(path);
325     if(root->IsUnderFull(*Store())) {
326     GiSTlist<MTentry *> *roots=new GiSTlist<MTentry *>;
327     GiSTlist<char *> *list=tree->SplitTree(&ncreated, tree->MaxLevel()-1, roots, name); // split the tree
328    
329     nsamples--;
330     while(!list->IsEmpty()) { // insert all the new trees in the sub-trees list
331     MTentry *e=roots->RemoveFront();
332    
333     othernameslist.Append(list->RemoveFront());
334     for(j=0; j<n; j++) if(data[j]->object()==e->object()) { // append also the root entry to the parents list
335     // cout << "parent=" << data[j];
336     plist.Append(data[j]);
337     j=n;
338     }
339     delete e;
340     nsamples++;
341     }
342     delete list;
343     delete roots;
344     minLevel=MIN(minLevel, tree->MaxLevel()-1);
345     }
346     else {
347     char *tmp=new char[50];
348    
349     strcpy(tmp, newname);
350     othernameslist.Append(tmp);
351     plist.Append(data[samples[i]]);
352     minLevel=MIN(minLevel, tree->MaxLevel());
353     }
354     delete root;
355     tree->Close();
356     delete tree->Store(); // it was created in tree->Create()
357     }
358     for(i=0; i<nInit; i++) {
359     for(j=0; j<ns[i]; j++) delete arrays[i][j];
360     delete []arrays[i];
361     }
362     delete []arrays;
363     while(!plist.IsEmpty()) { // insert the trees in the list (splitting if necessary)
364     MTentry *parent=plist.RemoveFront();
365     char *tmp=othernameslist.RemoveFront();
366    
367     strcpy(newname, tmp);
368     delete []tmp;
369     tree->Open(newname);
370     // cout << ": Tree level=" << tree->MaxLevel() << " (" << minLevel << ")\n";
371     if(tree->MaxLevel()>minLevel) { // we have to split the tree to reduce its height
372     // cout << "level too high!!! (min=" << minLevel << ") Splitting the tree...\n";
373     GiSTlist<MTentry *> *roots=new GiSTlist<MTentry *>;
374     GiSTlist<char *> *list=tree->SplitTree(&ncreated, minLevel, roots, name); // split the tree
375    
376     nsamples--;
377     while(!list->IsEmpty()) { // insert all the new trees in the sub-trees list
378     MTentry *e=roots->RemoveFront();
379    
380     nameslist.Append(list->RemoveFront());
381     for(j=0; j<n; j++) if(data[j]->object()==e->object()) { // append also the root entry to the parents list
382     // cout << "parent=" << data[j];
383     parentslist.Append(data[j]);
384     j=n;
385     }
386     delete e;
387     nsamples++;
388     }
389     delete list;
390     delete roots;
391     }
392     else { // simply insert the tree and its root to the lists
393     char *tmp=new char[50];
394    
395     strcpy(tmp, newname);
396     nameslist.Append(tmp);
397     // cout << "parent=" << data[samples[i]];
398     parentslist.Append(parent);
399     }
400     tree->Close();
401     delete tree->Store(); // it was created in tree->Open()
402     }
403     parents=new MTentry *[nsamples];
404     trees=new char *[nsamples];
405     for(i=0; i<nsamples; i++) { // convert the lists into arrays
406     trees[i]=nameslist.RemoveFront();
407     parents[i]=parentslist.RemoveFront();
408     }
409     // build the super-tree upon the parents
410     sprintf(newname, "%s.0", name);
411     // cout << "Now building super-tree " << newname << " on " << nsamples << " data...\n";
412     BulkLoad(parents, nsamples, padFactor, newname);
413     // attach each sub-tree to the leaves of the super-tree
414     path.MakeRoot();
415     node=(MTnode *)ReadNode(path);
416     oldList->Append(node);
417     // cout << "super-tree built!\n";
418     l=node->Level();
419     while(l>0) { // build the leaves list for super-tree
420     GiSTlist<MTnode *> *newList=new GiSTlist<MTnode *>;
421    
422     while(!oldList->IsEmpty()) {
423     node=oldList->RemoveFront();
424     path=node->Path();
425     node->SetLevel(node->Level()+minLevel); // update level of the upper nodes of the super-tree
426     WriteNode(node);
427     for(i=0; i<node->NumEntries(); i++) {
428     MTentry *e=(MTentry *)(*node)[i].Ptr();
429    
430     path.MakeChild(e->Ptr());
431     newList->Append((MTnode *)ReadNode(path));
432     path.MakeParent();
433     }
434     delete node;
435     }
436     delete oldList;
437     oldList=newList;
438     l--;
439     }
440     // cout << "Finished " << newname << endl;
441     while(!oldList->IsEmpty()) { // attach each sub-tree to its leaf
442     GiSTpath rootpath;
443    
444     rootpath.MakeRoot();
445     node=oldList->RemoveFront(); // retrieve next leaf (root of sub tree)
446     node->SetLevel(minLevel); // update level of the root of the sub-tree
447     path=node->Path();
448     for(i=0; i<node->NumEntries(); i++) {
449     MTnode *newnode=(MTnode *)CreateNode();
450     MTentry *e=(MTentry *)(*node)[i].Ptr();
451     GiSTpath newpath;
452    
453     path.MakeChild(Store()->Allocate());
454     newnode->Path()=path;
455     e->SetPtr(path.Page());
456     path.MakeParent();
457     for(j=0; e->object()!=parents[j]->object(); j++); // search the tree to append
458     tree->Open(trees[j]);
459     // cout << "Now appending sub-tree " << trees[j] << endl;
460     Append(newnode, (MTnode *)tree->ReadNode(rootpath)); // append this sub-tree to the super-tree
461     tree->Close();
462     delete tree->Store(); // it was created in tree->Open()
463     newpath=newnode->Path();
464     delete newnode;
465     }
466     WriteNode(node);
467     delete node;
468     }
469     tree->Open(trees[0]); // in order to destroy the object tree
470     delete tree;
471     for(i=0; i<nsamples; i++) delete []trees[i];
472     delete []trees;
473     // update radii of the upper nodes of the result M-tree
474     path.MakeRoot();
475     node=(MTnode *)ReadNode(path);
476     oldList->Append(node);
477     l=node->Level();
478     while(l>=minLevel) { // build the list of the nodes which radii should be recomputed
479     GiSTlist<MTnode *> *newList=new GiSTlist<MTnode *>;
480    
481     while(!oldList->IsEmpty()) {
482    
483     node=oldList->RemoveFront();
484     path=node->Path();
485     for(i=0; i<node->NumEntries(); i++) {
486     MTentry *e=(MTentry *)(*node)[i].Ptr();
487    
488     path.MakeChild(e->Ptr());
489     newList->Append((MTnode *)ReadNode(path));
490     path.MakeParent();
491     }
492     delete node;
493     }
494     delete oldList;
495     oldList=newList;
496     l--;
497     }
498     while(!oldList->IsEmpty()) { // adjust the radii of the nodes
499     MTnode *node=oldList->RemoveFront();
500    
501     AdjKeys(node);
502     delete node;
503     }
504     // be tidy...
505     delete oldList;
506     delete []parents;
507     delete []sizes;
508     delete []ns;
509     delete []sampled;
510     delete []samples;
511     for(i=0; i<=ncreated; i++) { // delete all temporary sub-trees
512     sprintf(newname, "%s.%i", name, i);
513     unlink(newname);
514     }
515     }
516     else { // we can insert all the entries in a single node
517     GiSTpath path;
518     GiSTnode *node;
519    
520     path.MakeRoot();
521     node=ReadNode(path);
522     for(i=0; i<n; i++)
523     node->Insert(*(data[i]));
524     assert(!node->IsOverFull(*Store()));
525     // cout << "real size=" << node->Size() << endl;
526     WriteNode(node);
527     delete node;
528     }
529     }
530    
531     // append the sub-tree rooted at from to the node to
532     // this is used in the "append" phase of the BulkLoad algorithm
533     void
534     MT::Append(MTnode *to, MTnode *from)
535     {
536     GiSTlist<MTnode *> *oldList=new GiSTlist<MTnode *>; // list of the nodes to append
537     GiSTlist<GiSTpath> pathList;
538     MT *fromtree=(MT *)from->Tree();
539     MTnode *node=new MTnode, *newnode;
540    
541     // cout << "Appending " << from;
542     oldList->Append(from);
543     pathList.Append(to->Path());
544     do {
545     GiSTlist<MTnode *> *newList=new GiSTlist<MTnode *>;
546    
547     while(!oldList->IsEmpty()) {
548     GiSTpath newpath=pathList.RemoveFront();
549    
550     delete node;
551     node=oldList->RemoveFront();
552     newnode=(MTnode *)ReadNode(newpath);
553     // cout << "Inserting " << node->NumEntries() << " entries:\n";
554     for(int i=0; i<node->NumEntries(); i++) {
555     MTentry *e=(MTentry *)(*node)[i].Ptr()->Copy();
556    
557     if(node->Level()>0) { // if node isn't a leaf, we've to allocate its children
558     GiSTpath nodepath=node->Path();
559     MTnode *childnode=(MTnode *)CreateNode(), *fromnode;
560    
561     nodepath.MakeChild(e->Ptr());
562     fromnode=(MTnode *)fromtree->ReadNode(nodepath);
563     newList->Append(fromnode);
564     e->SetPtr(Store()->Allocate());
565     newpath.MakeChild(e->Ptr());
566     childnode->Path()=newpath;
567     childnode->SetTree(this);
568     WriteNode(childnode); // write the empty node
569     pathList.Append(newpath);
570     newpath.MakeParent();
571     nodepath.MakeParent();
572     delete childnode;
573     }
574     newnode->Insert(*e);
575     // cout << "\tInserted " << e;
576     delete e;
577     }
578     newnode->SetLevel(node->Level());
579     WriteNode(newnode); // write the node
580     // cout << "Created " << newnode;
581     delete newnode;
582     }
583     delete oldList;
584     oldList=newList;
585     } while(node->Level()>0); // until we reach the leaves' level
586     // cout << node;
587     delete node;
588     delete oldList;
589     }
590    
591     // adjust the keys of node
592     // this is used during the final phase of the BulkLoad algorithm
593     void
594     MT::AdjKeys(GiSTnode *node)
595     {
596     GiSTnode *P;
597     GiSTpath parent_path=node->Path();
598     GiSTentry *entry, *actual;
599    
600     if(node->Path().IsRoot()) return;
601     parent_path.MakeParent();
602     P=ReadNode(parent_path);
603     entry=P->SearchPtr(node->Path().Page());
604     assert(entry!=NULL);
605     actual=node->Union();
606     actual->SetPtr(node->Path().Page());
607     ((MTkey *)actual->Key())->distance=((MTkey *)entry->Key())->distance; // necessary to keep track of the distance from the parent
608     if(!entry->IsEqual(*actual)) { // replace this entry
609     int pos=entry->Position();
610    
611     P->DeleteEntry(pos);
612     P->Insert(*actual);
613     /* if(P->IsOverFull(*Store())) { // this code should be unnecessary (if we have fixed length entries)
614     GiSTpage page=node->Path().Page();
615    
616     Split(&P, *actual);
617     node->Path()=P->Path();
618     node->Path().MakeChild(page);
619     }
620     else {
621     WriteNode(P);
622     AdjKeys(P);
623     } */
624     WriteNode(P);
625     AdjKeys(P);
626     }
627     delete P;
628     delete actual;
629     delete entry;
630     }