db5_alloc.c

Go to the documentation of this file.
00001 /*                     D B 5 _ A L L O C . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 2004-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup db5 */
00023 
00024 /*@{*/
00025 /** @file db5_alloc.c
00026  *  Handle disk space allocation in the BRL-CAD v5 database.
00027  *
00028  *  @Author
00029  *      Michael John Muuss
00030  *
00031  *  @par Source -
00032  *      The U. S. Army Research Laboratory
00033  *@n    Aberdeen Proving Ground, Maryland  21005-5068  USA
00034  *
00035  */
00036 
00037 #ifndef lint
00038 static const char RCSid[] = "@(#)$Header: /cvsroot/brlcad/brlcad/src/librt/db5_alloc.c,v 14.10 2006/09/16 02:04:24 lbutler Exp $ (BRL)";
00039 #endif
00040 
00041 #include "common.h"
00042 
00043 
00044 
00045 #include <stdio.h>
00046 #ifdef HAVE_STRING_H
00047 #include <string.h>
00048 #else
00049 #include <strings.h>
00050 #endif
00051 
00052 #include "machine.h"
00053 #include "bu.h"
00054 #include "vmath.h"
00055 #include "db5.h"
00056 #include "raytrace.h"
00057 
00058 #include "./debug.h"
00059 
00060 /**
00061  *                      D B 5 _ W R I T E _ F R E E
00062  *
00063  *  Create a v5 database "free" object of the specified size,
00064  *  and place it at the indicated location in the database.
00065  *
00066  *  There are two interesting cases:
00067  *      -  The free object is "small".  Just write it all at once.
00068  *      -  The free object is "large".  Write header and trailer
00069  *          separately
00070  *
00071  *
00072  *  @return     0       OK
00073  *  @return     -1      Fail.  This is a horrible error.
00074  */
00075 int
00076 db5_write_free( struct db_i *dbip, struct directory *dp, long length )
00077 {
00078         struct bu_external      ext;
00079 
00080         RT_CK_DBI(dbip);
00081         RT_CK_DIR(dp);
00082 
00083         if( length <= 8192 )  {
00084 
00085                 BU_INIT_EXTERNAL( &ext );
00086                 db5_make_free_object( &ext, length );
00087 
00088                 if( dp->d_flags & RT_DIR_INMEM )  {
00089                         bcopy( (char *)ext.ext_buf, dp->d_un.ptr, ext.ext_nbytes );
00090                         bu_free_external( &ext );
00091                         return 0;
00092                 }
00093 
00094                 if( db_write( dbip, (char *)ext.ext_buf, ext.ext_nbytes, dp->d_addr ) < 0 )  {
00095                         bu_free_external( &ext );
00096                         return -1;
00097                 }
00098                 bu_free_external( &ext );
00099                 return 0;
00100         }
00101 
00102         /* Free object is "large", only write the header and trailer bytes. */
00103 
00104         BU_INIT_EXTERNAL( &ext );
00105         db5_make_free_object_hdr( &ext, length );
00106 
00107         if( dp->d_flags & RT_DIR_INMEM )  {
00108                 bcopy( (char *)ext.ext_buf, dp->d_un.ptr, ext.ext_nbytes );
00109                 ((char *)ext.ext_buf)[length-1] = DB5HDR_MAGIC2;
00110                 bu_free_external( &ext );
00111                 return 0;
00112         }
00113 
00114         /* Write header */
00115         if( db_write( dbip, (char *)ext.ext_buf, ext.ext_nbytes, dp->d_addr ) < 0 )  {
00116                 bu_free_external( &ext );
00117                 return -1;
00118         }
00119 
00120         /* Write trailer byte */
00121         *((char *)ext.ext_buf) = DB5HDR_MAGIC2;
00122         if( db_write( dbip, (char *)ext.ext_buf, 1, dp->d_addr+length-1 ) < 0 )  {
00123                 bu_free_external( &ext );
00124                 return -1;
00125         }
00126         bu_free_external( &ext );
00127         return 0;
00128 }
00129 
00130 /**
00131  *                      D B 5 _ R E A L L O C
00132  *
00133  *  Change the size of a v5 database object.
00134  *
00135  *  If the object is getting smaller, break it into two pieces,
00136  *  and write out free objects for both.
00137  *  The caller is expected to re-write new data on the first one.
00138  *
00139  *  If the object is getting larger, seek a suitable "hole" large enough
00140  *  to hold it, throwing back any surplus, properly marked.
00141  *
00142  *  If the object is getting larger and there is no suitable "hole"
00143  *  in the database, extend the file, write a free object in the
00144  *  new space, and write a free object in the old space.
00145  *
00146  *  There is no point to trying to extend in place, that would require
00147  *  two searches through the memory map, and doesn't save any disk I/O.
00148  *
00149  *  Returns -
00150  *      0       OK
00151  *      -1      Failure
00152  */
00153 int
00154 db5_realloc( struct db_i *dbip, struct directory *dp, struct bu_external *ep )
00155 {
00156         long    baseaddr;
00157         long    baselen;
00158 
00159         RT_CK_DBI(dbip);
00160         RT_CK_DIR(dp);
00161         BU_CK_EXTERNAL(ep);
00162         if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) dbip=x%x, dp=x%x, ext_nbytes=%ld\n",
00163                 dp->d_namep, dbip, dp, ep->ext_nbytes );
00164 
00165         BU_ASSERT_LONG( ep->ext_nbytes&7, ==, 0 );
00166 
00167         if( dp->d_addr != -1L && ep->ext_nbytes == dp->d_len )  {
00168                 if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) current allocation is exactly right.\n", dp->d_namep);
00169                 return 0;
00170         }
00171         if( dp->d_addr == -1L )  BU_ASSERT_LONG( dp->d_len, ==, 0 );
00172 
00173         baseaddr = dp->d_addr;
00174         baselen = dp->d_len;
00175 
00176         if( dp->d_flags & RT_DIR_INMEM )  {
00177                 if( dp->d_un.ptr )  {
00178                         if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) bu_realloc()ing memory resident object\n", dp->d_namep);
00179                         dp->d_un.ptr = bu_realloc( dp->d_un.ptr,
00180                                 ep->ext_nbytes, "db5_realloc() d_un.ptr" );
00181                 } else {
00182                         if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) bu_malloc()ing memory resident object\n", dp->d_namep);
00183                         dp->d_un.ptr = bu_malloc( ep->ext_nbytes, "db5_realloc() d_un.ptr" );
00184                 }
00185                 dp->d_len = ep->ext_nbytes;
00186                 return 0;
00187         }
00188 
00189         if( dbip->dbi_read_only )  {
00190                 bu_log("db5_realloc(%s) on READ-ONLY file\n", dp->d_namep);
00191                 return(-1);
00192         }
00193 
00194         /* If the object is getting smaller... */
00195         if( ep->ext_nbytes < dp->d_len )  {
00196                 if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) object is getting smaller\n", dp->d_namep);
00197 
00198                 /* First, erase front half of storage to desired size. */
00199                 dp->d_len = ep->ext_nbytes;
00200                 if( db5_write_free( dbip, dp, dp->d_len ) < 0 )  return -1;
00201 
00202                 /* Second, erase back half of storage to remainder. */
00203                 dp->d_addr = baseaddr + ep->ext_nbytes;
00204                 dp->d_len = baselen - ep->ext_nbytes;
00205                 if( db5_write_free( dbip, dp, dp->d_len ) < 0 )  return -1;
00206 
00207                 /* Finally, update tables */
00208                 rt_memfree( &(dbip->dbi_freep), dp->d_len, dp->d_addr );
00209                 dp->d_addr = baseaddr;
00210                 dp->d_len = ep->ext_nbytes;
00211                 return 0;
00212         }
00213 
00214         /* The object is getting larger... */
00215 
00216         /* Start by zapping existing database object into a free object */
00217         if( dp->d_addr != -1L )  {
00218                 if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) releasing storage at x%x, len=%d\n", dp->d_namep, dp->d_addr, dp->d_len);
00219 
00220                 rt_memfree( &(dbip->dbi_freep), dp->d_len, dp->d_addr );
00221                 if( db5_write_free( dbip, dp, dp->d_len ) < 0 )  return -1;
00222                 baseaddr = dp->d_addr = -1L;    /* sanity */
00223         }
00224 
00225         /*
00226          *  Can we obtain a free block somewhere else?
00227          *  Keep in mind that free blocks may be very large (e.g. 50 MBytes).
00228          */
00229         {
00230                 struct mem_map  *mmp;
00231                 long            newaddr;
00232 
00233                 if( (mmp = rt_memalloc_nosplit( &(dbip->dbi_freep), ep->ext_nbytes )) != MAP_NULL )  {
00234                         if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) obtained free block at x%x, len=%d\n", dp->d_namep, mmp->m_addr, mmp->m_size );
00235                         BU_ASSERT_LONG( mmp->m_size, >=, ep->ext_nbytes );
00236                         if( mmp->m_size == ep->ext_nbytes )  {
00237                                 /* No need to reformat, existing free object is perfect */
00238                                 dp->d_addr = mmp->m_addr;
00239                                 dp->d_len = ep->ext_nbytes;
00240                                 return 0;
00241                         }
00242                         newaddr = mmp->m_addr;
00243                         if( mmp->m_size > ep->ext_nbytes )  {
00244                                 /* Reformat and free the surplus */
00245                                 dp->d_addr = mmp->m_addr + ep->ext_nbytes;
00246                                 dp->d_len = mmp->m_size - ep->ext_nbytes;
00247                                 if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) returning surplus at x%x, len=%d\n", dp->d_namep, dp->d_addr, dp->d_len );
00248                                 if( db5_write_free( dbip, dp, dp->d_len ) < 0 )  return -1;
00249                                 rt_memfree( &(dbip->dbi_freep), dp->d_len, dp->d_addr );
00250                                 /* mmp is invalid beyond here! */
00251                         }
00252                         dp->d_addr = newaddr;
00253                         dp->d_len = ep->ext_nbytes;
00254                         /* Erase the new place */
00255                         if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) utilizing free block at addr=x%x, len=%d\n", dp->d_namep, dp->d_addr, dp->d_len);
00256                         if( db5_write_free( dbip, dp, dp->d_len ) < 0 )  return -1;
00257                         return 0;
00258                 }
00259         }
00260 
00261         /* No free storage of the desired size, extend the database */
00262         dp->d_addr = dbip->dbi_eof;
00263         dbip->dbi_eof += ep->ext_nbytes;
00264         dp->d_len = ep->ext_nbytes;
00265         if(RT_G_DEBUG&DEBUG_DB) bu_log("db5_realloc(%s) extending database addr=x%x, len=%d\n", dp->d_namep, dp->d_addr, dp->d_len);
00266 #if 0
00267         /* Extending db with free record isn't necessary even to
00268          * provide "stable-store" capability.
00269          * If program or system aborts before caller write new object,
00270          * there is no problem.
00271          */
00272         if( db5_write_free( dbip, dp, dp->d_len ) < 0 )  return -1;
00273 #endif
00274         return 0;
00275 }
00276 
00277 /*@}*/
00278 /*
00279  * Local Variables:
00280  * mode: C
00281  * tab-width: 8
00282  * c-basic-offset: 4
00283  * indent-tabs-mode: t
00284  * End:
00285  * ex: shiftwidth=4 tabstop=8
00286  */

Generated on Mon Sep 18 01:24:48 2006 for BRL-CAD by  doxygen 1.4.6