io.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. /****************************************************************************
  2. * MODULE: R-Tree library
  3. *
  4. * AUTHOR(S): Antonin Guttman - original code
  5. * Daniel Green (green@superliminal.com) - major clean-up
  6. * and implementation of bounding spheres
  7. * Markus Metz - file-based and memory-based R*-tree
  8. *
  9. * PURPOSE: Multidimensional index
  10. *
  11. * COPYRIGHT: (C) 2001 by the GRASS Development Team
  12. *
  13. * This program is free software under the GNU General Public
  14. * License (>=v2). Read the file COPYING that comes with GRASS
  15. * for details.
  16. *****************************************************************************/
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <sys/types.h>
  20. #include <unistd.h>
  21. #include <assert.h>
  22. #include <grass/config.h>
  23. #include "index.h"
  24. /* #define USAGE_SWAP */
  25. /* add new free node position for recycling */
  26. void RTreeAddNodePos(off_t pos, int level, struct RTree *t)
  27. {
  28. int which, i;
  29. if (t->free_nodes.avail >= t->free_nodes.alloc) {
  30. size_t size;
  31. t->free_nodes.alloc += 100;
  32. size = t->free_nodes.alloc * sizeof(off_t);
  33. t->free_nodes.pos = (off_t *)realloc((void *)t->free_nodes.pos, size);
  34. assert(t->free_nodes.pos);
  35. }
  36. t->free_nodes.pos[t->free_nodes.avail++] = pos;
  37. /* check mru first */
  38. i = 0;
  39. while (t->nb[level][t->used[level][i]].pos != pos &&
  40. i < NODE_BUFFER_SIZE)
  41. i++;
  42. /* is it possible that this node is not in the buffer? */
  43. assert(i < NODE_BUFFER_SIZE);
  44. which = t->used[level][i];
  45. t->nb[level][which].pos = -1;
  46. t->nb[level][which].dirty = 0;
  47. /* make it lru */
  48. if (i < NODE_BUFFER_SIZE - 1) { /* which != t->used[level][NODE_BUFFER_SIZE - 1] */
  49. /* simple swap does not work here */
  50. while (i < NODE_BUFFER_SIZE - 1 &&
  51. t->nb[level][t->used[level][i + 1]].pos != -1) {
  52. t->used[level][i] = t->used[level][i + 1];
  53. i++;
  54. }
  55. assert(i < NODE_BUFFER_SIZE);
  56. t->used[level][i] = which;
  57. }
  58. }
  59. /* look for free node position, set file pointer, return position */
  60. off_t RTreeGetNodePos(struct RTree *t)
  61. {
  62. if (t->free_nodes.avail > 0) {
  63. t->free_nodes.avail--;
  64. return lseek(t->fd, t->free_nodes.pos[t->free_nodes.avail], SEEK_SET);
  65. }
  66. else {
  67. return lseek(t->fd, 0, SEEK_END);
  68. }
  69. }
  70. /* read branch from file */
  71. size_t RTreeReadBranch(struct RTree_Branch *b, struct RTree *t)
  72. {
  73. size_t size = 0;
  74. size += read(t->fd, b->rect.boundary, t->rectsize);
  75. size += read(t->fd, &(b->child), sizeof(union RTree_Child));
  76. return size;
  77. }
  78. /* read node from file */
  79. size_t RTreeReadNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
  80. {
  81. int i;
  82. size_t size = 0;
  83. lseek(t->fd, nodepos, SEEK_SET);
  84. size += read(t->fd, &(n->count), sizeof(int));
  85. size += read(t->fd, &(n->level), sizeof(int));
  86. for (i = 0; i < MAXCARD; i++) {
  87. size += RTreeReadBranch(&(n->branch[i]), t);
  88. }
  89. return size;
  90. }
  91. /* get node from buffer or file */
  92. struct RTree_Node *RTreeGetNode(off_t nodepos, int level, struct RTree *t)
  93. {
  94. int which, i = 0;
  95. /* check mru first */
  96. while (t->nb[level][t->used[level][i]].pos != nodepos &&
  97. t->nb[level][t->used[level][i]].pos >= 0 &&
  98. i < NODE_BUFFER_SIZE - 1)
  99. i++;
  100. which = t->used[level][i];
  101. if (t->nb[level][which].pos != nodepos) {
  102. /* rewrite node in buffer */
  103. if (t->nb[level][which].dirty) {
  104. RTreeRewriteNode(&(t->nb[level][which].n),
  105. t->nb[level][which].pos, t);
  106. t->nb[level][which].dirty = 0;
  107. }
  108. RTreeReadNode(&(t->nb[level][which].n), nodepos, t);
  109. t->nb[level][which].pos = nodepos;
  110. }
  111. /* make it mru */
  112. if (i) { /* t->used[level][0] != which */
  113. #ifdef USAGE_SWAP
  114. t->used[level][i] = t->used[level][0];
  115. t->used[level][0] = which;
  116. #else
  117. while (i) {
  118. t->used[level][i] = t->used[level][i - 1];
  119. i--;
  120. }
  121. t->used[level][0] = which;
  122. #endif
  123. }
  124. /* RTreeCopyNode(n, &(t->nb[level][which].n), t); */
  125. return &(t->nb[level][which].n);
  126. }
  127. /* write branch to file */
  128. size_t RTreeWriteBranch(struct RTree_Branch *b, struct RTree *t)
  129. {
  130. size_t size = 0;
  131. size += write(t->fd, b->rect.boundary, t->rectsize);
  132. size += write(t->fd, &(b->child), sizeof(union RTree_Child));
  133. return size;
  134. }
  135. /* write new node to file */
  136. size_t RTreeWriteNode(struct RTree_Node *n, struct RTree *t)
  137. {
  138. int i;
  139. size_t size = 0;
  140. /* file position must be set first with RTreeGetFNodePos() */
  141. size += write(t->fd, &(n->count), sizeof(int));
  142. size += write(t->fd, &(n->level), sizeof(int));
  143. for (i = 0; i < MAXCARD; i++) {
  144. size += RTreeWriteBranch(&(n->branch[i]), t);
  145. }
  146. return size;
  147. }
  148. /* rewrite updated node to file */
  149. size_t RTreeRewriteNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
  150. {
  151. lseek(t->fd, nodepos, SEEK_SET);
  152. return RTreeWriteNode(n, t);
  153. }
  154. /* mark node in buffer as changed */
  155. void RTreeNodeChanged(struct RTree_Node *n, off_t nodepos, struct RTree *t)
  156. {
  157. int which, i = 0;
  158. /* check mru first */
  159. while (t->nb[n->level][t->used[n->level][i]].pos != nodepos &&
  160. i < NODE_BUFFER_SIZE)
  161. i++;
  162. assert(i < NODE_BUFFER_SIZE);
  163. /* as it is used, it should always be mru */
  164. assert(i == 0);
  165. which = t->used[n->level][i];
  166. t->nb[n->level][which].dirty = 1;
  167. /* make it mru */
  168. if (i) { /* t->used[level][0] != which */
  169. #ifdef USAGE_SWAP
  170. t->used[n->level][i] = t->used[n->level][0];
  171. t->used[n->level][0] = which;
  172. #else
  173. while (i) {
  174. t->used[n->level][i] = t->used[n->level][i - 1];
  175. i--;
  176. }
  177. t->used[n->level][0] = which;
  178. #endif
  179. }
  180. }
  181. /* flush pending changes to file */
  182. void RTreeFlushBuffer(struct RTree *t)
  183. {
  184. int i, j;
  185. for (i = 0; i <= t->rootlevel; i++) {
  186. for (j = 0; j < NODE_BUFFER_SIZE; j++) {
  187. if (t->nb[i][j].dirty) {
  188. RTreeRewriteNode(&(t->nb[i][j].n), t->nb[i][j].pos, t);
  189. t->nb[i][j].dirty = 0;
  190. }
  191. }
  192. }
  193. }