BRL-CAD
db5_alloc.c
Go to the documentation of this file.
1 /* D B 5 _ A L L O C . C
2  * BRL-CAD
3  *
4  * Copyright (c) 2004-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  */
20 /** @addtogroup db5 */
21 /** @{ */
22 /** @file librt/db5_alloc.c
23  *
24  * Handle disk space allocation in the BRL-CAD v5 database.
25  *
26  */
27 
28 #include "common.h"
29 
30 #include <string.h>
31 #include "bio.h"
32 
33 
34 #include "bu/parse.h"
35 #include "vmath.h"
36 #include "db5.h"
37 #include "raytrace.h"
38 
39 int
40 db5_write_free(struct db_i *dbip, struct directory *dp, size_t length)
41 {
42  struct bu_external ext;
43 
44  RT_CK_DBI(dbip);
45  RT_CK_DIR(dp);
46 
47  if (length <= 8192) {
48 
49  BU_EXTERNAL_INIT(&ext);
50  db5_make_free_object(&ext, length);
51 
52  if (dp->d_flags & RT_DIR_INMEM) {
53  memcpy(dp->d_un.ptr, (char *)ext.ext_buf, ext.ext_nbytes);
54  bu_free_external(&ext);
55  return 0;
56  }
57 
58  if (db_write(dbip, (char *)ext.ext_buf, ext.ext_nbytes, dp->d_addr) < 0) {
59  bu_free_external(&ext);
60  return -1;
61  }
62  bu_free_external(&ext);
63  return 0;
64  }
65 
66  /* Free object is "large", only write the header and trailer bytes. */
67 
68  BU_EXTERNAL_INIT(&ext);
69  db5_make_free_object_hdr(&ext, length);
70 
71  if (dp->d_flags & RT_DIR_INMEM) {
72  memcpy(dp->d_un.ptr, (char *)ext.ext_buf, ext.ext_nbytes);
73  ((char *)ext.ext_buf)[length-1] = DB5HDR_MAGIC2;
74  bu_free_external(&ext);
75  return 0;
76  }
77 
78  /* Write header */
79  if (db_write(dbip, (char *)ext.ext_buf, ext.ext_nbytes, dp->d_addr) < 0) {
80  bu_free_external(&ext);
81  return -1;
82  }
83 
84  /* Write trailer byte */
85  *((char *)ext.ext_buf) = DB5HDR_MAGIC2;
86  if (db_write(dbip, (char *)ext.ext_buf, 1, (size_t)dp->d_addr+length-1) < 0) {
87  bu_free_external(&ext);
88  return -1;
89  }
90  bu_free_external(&ext);
91  return 0;
92 }
93 
94 
95 int
96 db5_realloc(struct db_i *dbip, struct directory *dp, struct bu_external *ep)
97 {
98  off_t baseaddr;
99  size_t baselen;
100 
101  RT_CK_DBI(dbip);
102  RT_CK_DIR(dp);
103  BU_CK_EXTERNAL(ep);
104  if (RT_G_DEBUG & DEBUG_DB)
105  bu_log("db5_realloc(%s) dbip=%p, dp=%p, ext_nbytes=%ld\n",
106  dp->d_namep, (void *)dbip, (void *)dp, ep->ext_nbytes);
107 
108  BU_ASSERT_LONG(ep->ext_nbytes&7, ==, 0);
109 
110  if (dp->d_addr != RT_DIR_PHONY_ADDR && ep->ext_nbytes == dp->d_len) {
111  if (RT_G_DEBUG&DEBUG_DB)
112  bu_log("db5_realloc(%s) current allocation is exactly right.\n", dp->d_namep);
113  return 0;
114  }
115  if (dp->d_addr == RT_DIR_PHONY_ADDR) BU_ASSERT_LONG(dp->d_len, ==, 0);
116 
117  baseaddr = dp->d_addr;
118  baselen = dp->d_len;
119 
120  if (dp->d_flags & RT_DIR_INMEM) {
121  if (dp->d_un.ptr) {
122  if (RT_G_DEBUG&DEBUG_DB)
123  bu_log("db5_realloc(%s) bu_realloc()ing memory resident object\n", dp->d_namep);
124  dp->d_un.ptr = bu_realloc(dp->d_un.ptr,
125  ep->ext_nbytes, "db5_realloc() d_un.ptr");
126  } else {
127  if (RT_G_DEBUG&DEBUG_DB)
128  bu_log("db5_realloc(%s) bu_malloc()ing memory resident object\n", dp->d_namep);
129  dp->d_un.ptr = bu_malloc(ep->ext_nbytes, "db5_realloc() d_un.ptr");
130  }
131  dp->d_len = ep->ext_nbytes;
132  return 0;
133  }
134 
135  /* make sure the database directory is initialized */
136  if (dbip->dbi_eof == RT_DIR_PHONY_ADDR) {
137  int ret = db_dirbuild(dbip);
138  if (ret) {
139  return -1;
140  }
141  }
142 
143  if (dbip->dbi_read_only) {
144  bu_log("db5_realloc(%s) on READ-ONLY file\n", dp->d_namep);
145  return -1;
146  }
147 
148  /* If the object is getting smaller... */
149  if (ep->ext_nbytes < dp->d_len) {
150  if (RT_G_DEBUG&DEBUG_DB)
151  bu_log("db5_realloc(%s) object is getting smaller\n", dp->d_namep);
152 
153  /* First, erase front half of storage to desired size. */
154  dp->d_len = ep->ext_nbytes;
155  if (db5_write_free(dbip, dp, dp->d_len) < 0) return -1;
156 
157  /* Second, erase back half of storage to remainder. */
158  dp->d_addr = baseaddr + (off_t)ep->ext_nbytes;
159  dp->d_len = baselen - ep->ext_nbytes;
160  if (db5_write_free(dbip, dp, dp->d_len) < 0) return -1;
161 
162  /* Finally, update tables */
163  rt_memfree(&(dbip->dbi_freep), dp->d_len, dp->d_addr);
164  dp->d_addr = baseaddr;
165  dp->d_len = ep->ext_nbytes;
166  return 0;
167  }
168 
169  /* The object is getting larger... */
170 
171  /* Start by zapping existing database object into a free object */
172  if (dp->d_addr != RT_DIR_PHONY_ADDR) {
173  if (RT_G_DEBUG & DEBUG_DB)
174  bu_log("db5_realloc(%s) releasing storage at %ld, len=%zu\n",
175  dp->d_namep, dp->d_addr, dp->d_len);
176 
177  rt_memfree(&(dbip->dbi_freep), dp->d_len, dp->d_addr);
178  if (db5_write_free(dbip, dp, dp->d_len) < 0) return -1;
179  baseaddr = dp->d_addr = RT_DIR_PHONY_ADDR; /* sanity */
180  }
181 
182  /*
183  * Can we obtain a free block somewhere else? Keep in mind that
184  * free blocks may be very large (e.g. 50 MBytes).
185  */
186  {
187  struct mem_map *mmp;
188  off_t newaddr;
189 
190  if ((mmp = rt_memalloc_nosplit(&(dbip->dbi_freep), ep->ext_nbytes)) != MAP_NULL) {
191  if (RT_G_DEBUG&DEBUG_DB)
192  bu_log("db5_realloc(%s) obtained free block at %ld, len=%zu\n",
193  dp->d_namep, mmp->m_addr, mmp->m_size);
194  BU_ASSERT_LONG((size_t)mmp->m_size, >=, (size_t)ep->ext_nbytes);
195  if ((size_t)mmp->m_size == (size_t)ep->ext_nbytes) {
196  /* No need to reformat, existing free object is perfect */
197  dp->d_addr = mmp->m_addr;
198  dp->d_len = ep->ext_nbytes;
199  return 0;
200  }
201  newaddr = mmp->m_addr;
202  if ((size_t)mmp->m_size > (size_t)ep->ext_nbytes) {
203  /* Reformat and free the surplus */
204  dp->d_addr = mmp->m_addr + (off_t)ep->ext_nbytes;
205  dp->d_len = mmp->m_size - ep->ext_nbytes;
206  if (RT_G_DEBUG&DEBUG_DB)
207  bu_log("db5_realloc(%s) returning surplus at %ld, len=%zu\n",
208  dp->d_namep, dp->d_addr, dp->d_len);
209  if (db5_write_free(dbip, dp, dp->d_len) < 0) return -1;
210  rt_memfree(&(dbip->dbi_freep), dp->d_len, dp->d_addr);
211  /* mmp is invalid beyond here! */
212  }
213  dp->d_addr = newaddr;
214  dp->d_len = ep->ext_nbytes;
215  /* Erase the new place */
216  if (RT_G_DEBUG&DEBUG_DB)
217  bu_log("db5_realloc(%s) utilizing free block at addr=%ld, len=%zu\n",
218  dp->d_namep, dp->d_addr, dp->d_len);
219  if (db5_write_free(dbip, dp, dp->d_len) < 0) return -1;
220  return 0;
221  }
222  }
223 
224  /* No free storage of the desired size, extend the database */
225  dp->d_addr = dbip->dbi_eof;
226  dbip->dbi_eof += (off_t)ep->ext_nbytes;
227  dp->d_len = ep->ext_nbytes;
228  if (RT_G_DEBUG & DEBUG_DB)
229  bu_log("db5_realloc(%s) extending database addr=%ld, len=%zu\n",
230  dp->d_namep, dp->d_addr, dp->d_len);
231  return 0;
232 }
233 
234 
235 /** @} */
236 /*
237  * Local Variables:
238  * mode: C
239  * tab-width: 8
240  * indent-tabs-mode: t
241  * c-file-style: "stroustrup"
242  * End:
243  * ex: shiftwidth=4 tabstop=8
244  */
char * d_namep
pointer to name string
Definition: raytrace.h:859
Definition: raytrace.h:800
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
size_t d_len
of db granules used
Definition: raytrace.h:867
#define RT_DIR_INMEM
object is in memory (only)
Definition: raytrace.h:889
#define BU_ASSERT_LONG(_lhs, _relation, _rhs)
Definition: defines.h:240
#define MAP_NULL
Definition: raytrace.h:742
void bu_free_external(struct bu_external *ep)
Header file for the BRL-CAD common definitions.
void * bu_malloc(size_t siz, const char *str)
Definition: malloc.c:314
if(share_geom)
Definition: nmg_mod.c:3829
int db5_realloc(struct db_i *dbip, struct directory *dp, struct bu_external *ep)
Definition: db5_alloc.c:96
#define RT_G_DEBUG
Definition: raytrace.h:1718
void db5_make_free_object_hdr(struct bu_external *ep, size_t length)
Definition: db5_io.c:572
#define RT_CK_DIR(_dp)
Definition: raytrace.h:876
off_t dbi_eof
PRIVATE: End+1 pos after db_scan()
Definition: raytrace.h:816
uint8_t * ext_buf
Definition: parse.h:216
#define RT_DIR_PHONY_ADDR
Special marker for d_addr field.
Definition: raytrace.h:879
void * bu_realloc(void *ptr, size_t siz, const char *str)
struct mem_map * dbi_freep
PRIVATE: map of free granules.
Definition: raytrace.h:819
void db5_make_free_object(struct bu_external *ep, size_t length)
Definition: db5_io.c:601
size_t m_size
Size of this free element.
Definition: raytrace.h:739
#define RT_CK_DBI(_p)
Definition: raytrace.h:829
int dbi_read_only
!0 => read only file
Definition: raytrace.h:806
union directory::@8 d_un
#define DEBUG_DB
5 Database debugging
Definition: raytrace.h:88
#define BU_EXTERNAL_INIT(_p)
Definition: parse.h:229
void * ptr
ptr to in-memory-only obj
Definition: raytrace.h:862
struct mem_map * rt_memalloc_nosplit(struct mem_map **pp, size_t size)
int db_write(struct db_i *dbip, const void *addr, size_t count, off_t offset)
Definition: db_io.c:170
#define BU_CK_EXTERNAL(_p)
Definition: parse.h:224
int db_dirbuild(struct db_i *dbip)
Definition: db5_scan.c:301
void rt_memfree(struct mem_map **pp, size_t size, off_t addr)
Definition: memalloc.c:228
off_t m_addr
Address of start of this element.
Definition: raytrace.h:740
size_t ext_nbytes
Definition: parse.h:210
int d_flags
flags
Definition: raytrace.h:869
int db5_write_free(struct db_i *dbip, struct directory *dp, size_t length)
Definition: db5_alloc.c:40