File: io.c

package info (click to toggle)
grass 8.4.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 277,040 kB
  • sloc: ansic: 460,798; python: 227,732; cpp: 42,026; sh: 11,262; makefile: 7,007; xml: 3,637; sql: 968; lex: 520; javascript: 484; yacc: 450; asm: 387; perl: 157; sed: 25; objc: 6; ruby: 4
file content (245 lines) | stat: -rw-r--r-- 6,956 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
/****************************************************************************
 * MODULE:       R-Tree library
 *
 * AUTHOR(S):    Antonin Guttman - original code
 *               Daniel Green (green@superliminal.com) - major clean-up
 *                               and implementation of bounding spheres
 *               Markus Metz - file-based and memory-based R*-tree
 *
 * PURPOSE:      Multidimensional index
 *
 * COPYRIGHT:    (C) 2001 by the GRASS Development Team
 *
 *               This program is free software under the GNU General Public
 *               License (>=v2). Read the file COPYING that comes with GRASS
 *               for details.
 *****************************************************************************/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <assert.h>
#include <errno.h>
#include <grass/gis.h>
#include "index.h"

/* #define USAGE_SWAP */

/* add new free node position for recycling */
void RTreeAddNodePos(off_t pos, int level, struct RTree *t)
{
    int which, i;

    if (t->free_nodes.avail >= t->free_nodes.alloc) {
        size_t size;

        t->free_nodes.alloc += 100;
        size = t->free_nodes.alloc * sizeof(off_t);
        t->free_nodes.pos = (off_t *)realloc((void *)t->free_nodes.pos, size);
        assert(t->free_nodes.pos);
    }
    t->free_nodes.pos[t->free_nodes.avail++] = pos;

    /* check mru first */
    i = 0;
    while (t->nb[level][t->used[level][i]].pos != pos && i < NODE_BUFFER_SIZE)
        i++;

    /* is it possible that this node is not in the buffer? */
    assert(i < NODE_BUFFER_SIZE);
    which = t->used[level][i];
    t->nb[level][which].pos = -1;
    t->nb[level][which].dirty = 0;

    /* make it lru */
    if (i < NODE_BUFFER_SIZE -
                1) { /* which != t->used[level][NODE_BUFFER_SIZE - 1] */
        /* simple swap does not work here */
        while (i < NODE_BUFFER_SIZE - 1 &&
               t->nb[level][t->used[level][i + 1]].pos != -1) {
            t->used[level][i] = t->used[level][i + 1];
            i++;
        }
        assert(i < NODE_BUFFER_SIZE);
        t->used[level][i] = which;
    }
}

/* look for free node position, set file pointer, return position */
off_t RTreeGetNodePos(struct RTree *t)
{
    if (t->free_nodes.avail > 0) {
        t->free_nodes.avail--;
        return lseek(t->fd, t->free_nodes.pos[t->free_nodes.avail], SEEK_SET);
    }
    else {
        return lseek(t->fd, 0, SEEK_END);
    }
}

/* read branch from file */
size_t RTreeReadBranch(struct RTree_Branch *b, struct RTree *t)
{
    size_t size = 0;

    size += read(t->fd, b->rect.boundary, t->rectsize);
    size += read(t->fd, &(b->child), sizeof(union RTree_Child));

    return size;
}

/* read node from file */
size_t RTreeReadNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
{
    int i;
    size_t size = 0;

    lseek(t->fd, nodepos, SEEK_SET);
    size += read(t->fd, &(n->count), sizeof(int));
    size += read(t->fd, &(n->level), sizeof(int));

    for (i = 0; i < MAXCARD; i++) {
        size += RTreeReadBranch(&(n->branch[i]), t);
    }

    return size;
}

/* get node from buffer or file */
struct RTree_Node *RTreeGetNode(off_t nodepos, int level, struct RTree *t)
{
    int which, i = 0;

    /* check mru first */
    while (t->nb[level][t->used[level][i]].pos != nodepos &&
           t->nb[level][t->used[level][i]].pos >= 0 && i < NODE_BUFFER_SIZE - 1)
        i++;

    which = t->used[level][i];

    if (t->nb[level][which].pos != nodepos) {
        /* rewrite node in buffer */
        if (t->nb[level][which].dirty) {
            RTreeRewriteNode(&(t->nb[level][which].n), t->nb[level][which].pos,
                             t);
            t->nb[level][which].dirty = 0;
        }
        RTreeReadNode(&(t->nb[level][which].n), nodepos, t);
        t->nb[level][which].pos = nodepos;
    }
    /* make it mru */
    if (i) { /* t->used[level][0] != which */
#ifdef USAGE_SWAP
        t->used[level][i] = t->used[level][0];
        t->used[level][0] = which;
#else
        while (i) {
            t->used[level][i] = t->used[level][i - 1];
            i--;
        }
        t->used[level][0] = which;
#endif
    }

    /* RTreeCopyNode(n, &(t->nb[level][which].n), t); */

    return &(t->nb[level][which].n);
}

/* write branch to file */
size_t RTreeWriteBranch(struct RTree_Branch *b, struct RTree *t)
{
    size_t size = 0;

    if (write(t->fd, b->rect.boundary, t->rectsize) != t->rectsize)
        G_fatal_error("RTreeWriteBranch(): Unable to write (%s)",
                      strerror(errno));
    size += t->rectsize;
    if (write(t->fd, &(b->child), sizeof(union RTree_Child)) !=
        sizeof(union RTree_Child))
        G_fatal_error("RTreeWriteBranch(): Unable to write (%s)",
                      strerror(errno));
    size += sizeof(union RTree_Child);

    return size;
}

/* write new node to file */
size_t RTreeWriteNode(struct RTree_Node *n, struct RTree *t)
{
    int i;
    size_t size = 0;

    /* file position must be set first with RTreeGetFNodePos() */
    if (write(t->fd, &(n->count), sizeof(int)) != sizeof(int))
        G_fatal_error("RTreeWriteNode(): Unable to write (%s)",
                      strerror(errno));
    size += sizeof(int);
    if (write(t->fd, &(n->level), sizeof(int)) != sizeof(int))
        G_fatal_error("RTreeWriteNode(): Unable to write (%s)",
                      strerror(errno));
    size += sizeof(int);

    for (i = 0; i < MAXCARD; i++) {
        size += RTreeWriteBranch(&(n->branch[i]), t);
    }

    return size;
}

/* rewrite updated node to file */
size_t RTreeRewriteNode(struct RTree_Node *n, off_t nodepos, struct RTree *t)
{
    lseek(t->fd, nodepos, SEEK_SET);

    return RTreeWriteNode(n, t);
}

/* mark node in buffer as changed */
void RTreeNodeChanged(struct RTree_Node *n, off_t nodepos, struct RTree *t)
{
    int which, i = 0;

    /* check mru first */
    while (t->nb[n->level][t->used[n->level][i]].pos != nodepos &&
           i < NODE_BUFFER_SIZE)
        i++;

    assert(i < NODE_BUFFER_SIZE);
    /* as it is used, it should always be mru */
    assert(i == 0);
    which = t->used[n->level][i];

    t->nb[n->level][which].dirty = 1;

    /* make it mru */
    if (i) { /* t->used[level][0] != which */
#ifdef USAGE_SWAP
        t->used[n->level][i] = t->used[n->level][0];
        t->used[n->level][0] = which;
#else
        while (i) {
            t->used[n->level][i] = t->used[n->level][i - 1];
            i--;
        }
        t->used[n->level][0] = which;
#endif
    }
}

/* flush pending changes to file */
void RTreeFlushBuffer(struct RTree *t)
{
    int i, j;

    for (i = 0; i <= t->rootlevel; i++) {
        for (j = 0; j < NODE_BUFFER_SIZE; j++) {
            if (t->nb[i][j].dirty) {
                RTreeRewriteNode(&(t->nb[i][j].n), t->nb[i][j].pos, t);
                t->nb[i][j].dirty = 0;
            }
        }
    }
}