io.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 <string.h>
  20. #include <sys/types.h>
  21. #include <unistd.h>
  22. #include <assert.h>
  23. #include <errno.h>
  24. #include <grass/gis.h>
  25. #include "index.h"
  26. /* #define USAGE_SWAP */
  27. /* add new free node position for recycling */
  28. void RTreeAddNodePos(off_t pos, int level, struct RTree *t)
  29. {
  30. int which, i;
  31. if (t->free_nodes.avail >= t->free_nodes.alloc) {
  32. size_t size;
  33. t->free_nodes.alloc += 100;
  34. size = t->free_nodes.alloc * sizeof(off_t);
  35. t->free_nodes.pos = (off_t *)realloc((void *)t->free_nodes.pos, size);
  36. assert(t->free_nodes.pos);
  37. }
  38. t->free_nodes.pos[t->free_nodes.avail++] = pos;
  39. /* check mru first */
  40. i = 0;
  41. while (t->nb[level][t->used[level][i]].pos != pos &&
  42. i < NODE_BUFFER_SIZE)
  43. i++;
  44. /* is it possible that this node is not in the buffer? */
  45. assert(i < NODE_BUFFER_SIZE);
  46. which = t->used[level][i];
  47. t->nb[level][which].pos = -1;
  48. t->nb[level][which].dirty = 0;
  49. /* make it lru */
  50. if (i < NODE_BUFFER_SIZE - 1) { /* which != t->used[level][NODE_BUFFER_SIZE - 1] */
  51. /* simple swap does not work here */
  52. while (i < NODE_BUFFER_SIZE - 1 &&
  53. t->nb[level][t->used[level][i + 1]].pos != -1) {
  54. t->used[level][i] = t->used[level][i + 1];
  55. i++;
  56. }
  57. assert(i < NODE_BUFFER_SIZE);
  58. t->used[level][i] = which;
  59. }
  60. }
  61. /* look for free node position, set file pointer, return position */
  62. off_t RTreeGetNodePos(struct RTree *t)
  63. {
  64. if (t->free_nodes.avail > 0) {
  65. t->free_nodes.avail--;
  66. return lseek(t->fd, t->free_nodes.pos[t->free_nodes.avail], SEEK_SET);
  67. }
  68. else {
  69. return lseek(t->fd, 0, SEEK_END);
  70. }
  71. }
  72. /* read branch from file */
  73. size_t RTreeReadBranch(struct RTree_Branch *b, struct RTree *t)
  74. {
  75. size_t size = 0;
  76. size += read(t->fd, b->rect.boundary, t->rectsize);
  77. size += read(t->fd, &(b->child), sizeof(union RTree_Child));
  78. return size;
  79. }
  80. /* read node from file */
  81. size_t RTreeReadNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
  82. {
  83. int i;
  84. size_t size = 0;
  85. lseek(t->fd, nodepos, SEEK_SET);
  86. size += read(t->fd, &(n->count), sizeof(int));
  87. size += read(t->fd, &(n->level), sizeof(int));
  88. for (i = 0; i < MAXCARD; i++) {
  89. size += RTreeReadBranch(&(n->branch[i]), t);
  90. }
  91. return size;
  92. }
  93. /* get node from buffer or file */
  94. struct RTree_Node *RTreeGetNode(off_t nodepos, int level, struct RTree *t)
  95. {
  96. int which, i = 0;
  97. /* check mru first */
  98. while (t->nb[level][t->used[level][i]].pos != nodepos &&
  99. t->nb[level][t->used[level][i]].pos >= 0 &&
  100. i < NODE_BUFFER_SIZE - 1)
  101. i++;
  102. which = t->used[level][i];
  103. if (t->nb[level][which].pos != nodepos) {
  104. /* rewrite node in buffer */
  105. if (t->nb[level][which].dirty) {
  106. RTreeRewriteNode(&(t->nb[level][which].n),
  107. t->nb[level][which].pos, t);
  108. t->nb[level][which].dirty = 0;
  109. }
  110. RTreeReadNode(&(t->nb[level][which].n), nodepos, t);
  111. t->nb[level][which].pos = nodepos;
  112. }
  113. /* make it mru */
  114. if (i) { /* t->used[level][0] != which */
  115. #ifdef USAGE_SWAP
  116. t->used[level][i] = t->used[level][0];
  117. t->used[level][0] = which;
  118. #else
  119. while (i) {
  120. t->used[level][i] = t->used[level][i - 1];
  121. i--;
  122. }
  123. t->used[level][0] = which;
  124. #endif
  125. }
  126. /* RTreeCopyNode(n, &(t->nb[level][which].n), t); */
  127. return &(t->nb[level][which].n);
  128. }
  129. /* write branch to file */
  130. size_t RTreeWriteBranch(struct RTree_Branch *b, struct RTree *t)
  131. {
  132. size_t size = 0;
  133. if (write(t->fd, b->rect.boundary, t->rectsize) != t->rectsize)
  134. G_fatal_error("RTreeWriteBranch(): Unable to write (%s)", strerror(errno));
  135. size += t->rectsize;
  136. if (write(t->fd, &(b->child), sizeof(union RTree_Child)) != sizeof(union RTree_Child))
  137. G_fatal_error("RTreeWriteBranch(): Unable to write (%s)", strerror(errno));
  138. size += sizeof(union RTree_Child);
  139. return size;
  140. }
  141. /* write new node to file */
  142. size_t RTreeWriteNode(struct RTree_Node *n, struct RTree *t)
  143. {
  144. int i;
  145. size_t size = 0;
  146. /* file position must be set first with RTreeGetFNodePos() */
  147. if (write(t->fd, &(n->count), sizeof(int)) != sizeof(int))
  148. G_fatal_error("RTreeWriteNode(): Unable to write (%s)", strerror(errno));
  149. size += sizeof(int);
  150. if (write(t->fd, &(n->level), sizeof(int)) != sizeof(int))
  151. G_fatal_error("RTreeWriteNode(): Unable to write (%s)", strerror(errno));
  152. size += sizeof(int);
  153. for (i = 0; i < MAXCARD; i++) {
  154. size += RTreeWriteBranch(&(n->branch[i]), t);
  155. }
  156. return size;
  157. }
  158. /* rewrite updated node to file */
  159. size_t RTreeRewriteNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
  160. {
  161. lseek(t->fd, nodepos, SEEK_SET);
  162. return RTreeWriteNode(n, t);
  163. }
  164. /* mark node in buffer as changed */
  165. void RTreeNodeChanged(struct RTree_Node *n, off_t nodepos, struct RTree *t)
  166. {
  167. int which, i = 0;
  168. /* check mru first */
  169. while (t->nb[n->level][t->used[n->level][i]].pos != nodepos &&
  170. i < NODE_BUFFER_SIZE)
  171. i++;
  172. assert(i < NODE_BUFFER_SIZE);
  173. /* as it is used, it should always be mru */
  174. assert(i == 0);
  175. which = t->used[n->level][i];
  176. t->nb[n->level][which].dirty = 1;
  177. /* make it mru */
  178. if (i) { /* t->used[level][0] != which */
  179. #ifdef USAGE_SWAP
  180. t->used[n->level][i] = t->used[n->level][0];
  181. t->used[n->level][0] = which;
  182. #else
  183. while (i) {
  184. t->used[n->level][i] = t->used[n->level][i - 1];
  185. i--;
  186. }
  187. t->used[n->level][0] = which;
  188. #endif
  189. }
  190. }
  191. /* flush pending changes to file */
  192. void RTreeFlushBuffer(struct RTree *t)
  193. {
  194. int i, j;
  195. for (i = 0; i <= t->rootlevel; i++) {
  196. for (j = 0; j < NODE_BUFFER_SIZE; j++) {
  197. if (t->nb[i][j].dirty) {
  198. RTreeRewriteNode(&(t->nb[i][j].n), t->nb[i][j].pos, t);
  199. t->nb[i][j].dirty = 0;
  200. }
  201. }
  202. }
  203. }