GRASS 8 Programmer's Manual 8.6.0dev(2026)-c83afef6d3
Loading...
Searching...
No Matches
io.c
Go to the documentation of this file.
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 * SPDX-FileCopyrightText: 2001 GRASS Development Team
12 * SPDX-License-Identifier: GPL-2.0-or-later
13 *****************************************************************************/
14
15#include <stdlib.h>
16#include <stdio.h>
17#include <string.h>
18#include <sys/types.h>
19#include <unistd.h>
20#include <assert.h>
21#include <errno.h>
22
23#include <grass/gis.h>
24#include <grass/glocale.h>
25
26#include "index.h"
27
28/* #define USAGE_SWAP */
29
30/* add new free node position for recycling */
31void RTreeAddNodePos(off_t pos, int level, struct RTree *t)
32{
33 int which, i;
34
35 if (t->free_nodes.avail >= t->free_nodes.alloc) {
36 size_t size;
37
38 t->free_nodes.alloc += 100;
39 size = t->free_nodes.alloc * sizeof(off_t);
40 t->free_nodes.pos = (off_t *)realloc((void *)t->free_nodes.pos, size);
41 assert(t->free_nodes.pos);
42 }
43 t->free_nodes.pos[t->free_nodes.avail++] = pos;
44
45 /* check mru first */
46 i = 0;
47 while (t->nb[level][t->used[level][i]].pos != pos && i < NODE_BUFFER_SIZE)
48 i++;
49
50 /* is it possible that this node is not in the buffer? */
52 which = t->used[level][i];
53 t->nb[level][which].pos = -1;
54 t->nb[level][which].dirty = 0;
55
56 /* make it lru */
57 if (i < NODE_BUFFER_SIZE -
58 1) { /* which != t->used[level][NODE_BUFFER_SIZE - 1] */
59 /* simple swap does not work here */
60 while (i < NODE_BUFFER_SIZE - 1 &&
61 t->nb[level][t->used[level][i + 1]].pos != -1) {
62 t->used[level][i] = t->used[level][i + 1];
63 i++;
64 }
66 t->used[level][i] = which;
67 }
68}
69
70/* look for free node position, set file pointer, return position */
72{
73 if (t->free_nodes.avail > 0) {
74 t->free_nodes.avail--;
75 return lseek(t->fd, t->free_nodes.pos[t->free_nodes.avail], SEEK_SET);
76 }
77 else {
78 return lseek(t->fd, 0, SEEK_END);
79 }
80}
81
82/* read branch from file */
83size_t RTreeReadBranch(struct RTree_Branch *b, struct RTree *t)
84{
85 size_t size = 0;
86
87 size += read(t->fd, b->rect.boundary, t->rectsize);
88 size += read(t->fd, &(b->child), sizeof(union RTree_Child));
89
90 return size;
91}
92
93/* read node from file */
94size_t RTreeReadNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
95{
96 int i;
97 size_t size = 0;
98
99 if (lseek(t->fd, nodepos, SEEK_SET) == -1) {
100 int err = errno;
101 G_fatal_error(_("File read/write operation failed: %s (%d)"),
102 strerror(err), err);
103 }
104 size += read(t->fd, &(n->count), sizeof(int));
105 size += read(t->fd, &(n->level), sizeof(int));
106
107 for (i = 0; i < MAXCARD; i++) {
108 size += RTreeReadBranch(&(n->branch[i]), t);
109 }
110
111 return size;
112}
113
114/* get node from buffer or file */
116{
117 int which, i = 0;
118
119 /* check mru first */
120 while (t->nb[level][t->used[level][i]].pos != nodepos &&
121 t->nb[level][t->used[level][i]].pos >= 0 && i < NODE_BUFFER_SIZE - 1)
122 i++;
123
124 which = t->used[level][i];
125
126 if (t->nb[level][which].pos != nodepos) {
127 /* rewrite node in buffer */
128 if (t->nb[level][which].dirty) {
129 RTreeRewriteNode(&(t->nb[level][which].n), t->nb[level][which].pos,
130 t);
131 t->nb[level][which].dirty = 0;
132 }
133 RTreeReadNode(&(t->nb[level][which].n), nodepos, t);
134 t->nb[level][which].pos = nodepos;
135 }
136 /* make it mru */
137 if (i) { /* t->used[level][0] != which */
138#ifdef USAGE_SWAP
139 t->used[level][i] = t->used[level][0];
140 t->used[level][0] = which;
141#else
142 while (i) {
143 t->used[level][i] = t->used[level][i - 1];
144 i--;
145 }
146 t->used[level][0] = which;
147#endif
148 }
149
150 /* RTreeCopyNode(n, &(t->nb[level][which].n), t); */
151
152 return &(t->nb[level][which].n);
153}
154
155/* write branch to file */
156size_t RTreeWriteBranch(struct RTree_Branch *b, struct RTree *t)
157{
158 size_t size = 0;
159
160 if (write(t->fd, b->rect.boundary, t->rectsize) != t->rectsize)
161 G_fatal_error("RTreeWriteBranch(): Unable to write (%s)",
162 strerror(errno));
163 size += t->rectsize;
164 if (write(t->fd, &(b->child), sizeof(union RTree_Child)) !=
165 sizeof(union RTree_Child))
166 G_fatal_error("RTreeWriteBranch(): Unable to write (%s)",
167 strerror(errno));
168 size += sizeof(union RTree_Child);
169
170 return size;
171}
172
173/* write new node to file */
174size_t RTreeWriteNode(struct RTree_Node *n, struct RTree *t)
175{
176 int i;
177 size_t size = 0;
178
179 /* file position must be set first with RTreeGetFNodePos() */
180 if (write(t->fd, &(n->count), sizeof(int)) != sizeof(int))
181 G_fatal_error("RTreeWriteNode(): Unable to write (%s)",
182 strerror(errno));
183 size += sizeof(int);
184 if (write(t->fd, &(n->level), sizeof(int)) != sizeof(int))
185 G_fatal_error("RTreeWriteNode(): Unable to write (%s)",
186 strerror(errno));
187 size += sizeof(int);
188
189 for (i = 0; i < MAXCARD; i++) {
190 size += RTreeWriteBranch(&(n->branch[i]), t);
191 }
192
193 return size;
194}
195
196/* rewrite updated node to file */
197size_t RTreeRewriteNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
198{
199 if (lseek(t->fd, nodepos, SEEK_SET) == -1) {
200 int err = errno;
201 G_fatal_error(_("File read/write operation failed: %s (%d)"),
202 strerror(err), err);
203 }
204
205 return RTreeWriteNode(n, t);
206}
207
208/* mark node in buffer as changed */
210{
211 int which, i = 0;
212
213 /* check mru first */
214 while (t->nb[n->level][t->used[n->level][i]].pos != nodepos &&
216 i++;
217
219 /* as it is used, it should always be mru */
220 assert(i == 0);
221 which = t->used[n->level][i];
222
223 t->nb[n->level][which].dirty = 1;
224
225 /* make it mru */
226 if (i) { /* t->used[level][0] != which */
227#ifdef USAGE_SWAP
228 t->used[n->level][i] = t->used[n->level][0];
229 t->used[n->level][0] = which;
230#else
231 while (i) {
232 t->used[n->level][i] = t->used[n->level][i - 1];
233 i--;
234 }
235 t->used[n->level][0] = which;
236#endif
237 }
238}
239
240/* flush pending changes to file */
242{
243 int i, j;
244
245 for (i = 0; i <= t->rootlevel; i++) {
246 for (j = 0; j < NODE_BUFFER_SIZE; j++) {
247 if (t->nb[i][j].dirty) {
248 RTreeRewriteNode(&(t->nb[i][j].n), t->nb[i][j].pos, t);
249 t->nb[i][j].dirty = 0;
250 }
251 }
252 }
253}
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define _(str)
Definition glocale.h:10
off_t RTreeGetNodePos(struct RTree *t)
Definition io.c:71
void RTreeNodeChanged(struct RTree_Node *n, off_t nodepos, struct RTree *t)
Definition io.c:209
size_t RTreeWriteBranch(struct RTree_Branch *b, struct RTree *t)
Definition io.c:156
size_t RTreeReadNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
Definition io.c:94
void RTreeFlushBuffer(struct RTree *t)
Definition io.c:241
size_t RTreeWriteNode(struct RTree_Node *n, struct RTree *t)
Definition io.c:174
size_t RTreeRewriteNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
Definition io.c:197
struct RTree_Node * RTreeGetNode(off_t nodepos, int level, struct RTree *t)
Definition io.c:115
void RTreeAddNodePos(off_t pos, int level, struct RTree *t)
Definition io.c:31
size_t RTreeReadBranch(struct RTree_Branch *b, struct RTree *t)
Definition io.c:83
#define assert(condition)
Definition lz4.c:291
double b
Definition r_raster.c:37
double t
Definition r_raster.c:37
#define MAXCARD
Definition rtree.h:41
#define NODE_BUFFER_SIZE
Definition rtree.h:49
int count
Definition rtree.h:71
int level
Definition rtree.h:72
struct RTree_Branch * branch
Definition rtree.h:73
Definition rtree.h:120
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
#define read
Definition unistd.h:5
#define write
Definition unistd.h:6