LTP GCOV extension - code coverage report
Current view: directory - frmts/pcidsk/sdk/core - sysvirtualfile.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 132
Code covered: 39.4 % Executed lines: 52

       1                 : /******************************************************************************
       2                 :  *
       3                 :  * Purpose:  Implementation of the SysVirtualFile class.
       4                 :  *
       5                 :  * This class is used to manage access to a single virtual file stored in
       6                 :  * SysBData segments based on a block map stored in the SysBMDir segment 
       7                 :  * (and managed by SysBlockMap class). 
       8                 :  *
       9                 :  * The virtual files are allocated in 8K chunks (block_size) in segments.
      10                 :  * To minimize IO requests, other overhead, we keep one such 8K block in
      11                 :  * our working cache for the virtual file stream.  
      12                 :  *
      13                 :  * This class is primarily used by the CTiledChannel class for access to 
      14                 :  * tiled images.
      15                 :  * 
      16                 :  ******************************************************************************
      17                 :  * Copyright (c) 2009
      18                 :  * PCI Geomatics, 50 West Wilmot Street, Richmond Hill, Ont, Canada
      19                 :  *
      20                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      21                 :  * copy of this software and associated documentation files (the "Software"),
      22                 :  * to deal in the Software without restriction, including without limitation
      23                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      24                 :  * and/or sell copies of the Software, and to permit persons to whom the
      25                 :  * Software is furnished to do so, subject to the following conditions:
      26                 :  *
      27                 :  * The above copyright notice and this permission notice shall be included
      28                 :  * in all copies or substantial portions of the Software.
      29                 :  *
      30                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
      31                 :  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      32                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
      33                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      34                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      35                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      36                 :  * DEALINGS IN THE SOFTWARE.
      37                 :  ****************************************************************************/
      38                 : #include "pcidsk_config.h"
      39                 : #include "pcidsk_types.h"
      40                 : #include "pcidsk_buffer.h"
      41                 : #include "pcidsk_exception.h"
      42                 : #include "core/sysvirtualfile.h"
      43                 : #include "core/cpcidskfile.h"
      44                 : #include "segment/sysblockmap.h"
      45                 : #include <cassert>
      46                 : #include <cstring>
      47                 : #if 0
      48                 : #include <cstdio>
      49                 : #endif
      50                 : 
      51                 : using namespace PCIDSK;
      52                 : 
      53                 : 
      54                 : const int SysVirtualFile::block_size = SYSVIRTUALFILE_BLOCKSIZE;
      55                 : 
      56                 : /************************************************************************/
      57                 : /*                           SysVirtualFile()                           */
      58                 : /************************************************************************/
      59                 : 
      60                 : SysVirtualFile::SysVirtualFile( CPCIDSKFile *file, int start_block, 
      61                 :                                 uint64 image_length, 
      62                 :                                 PCIDSKBuffer &block_map_data,
      63                 :                                 SysBlockMap *sysblockmap,
      64               3 :                                 int image_index )
      65                 : 
      66                 : {
      67               3 :     file_length = image_length;
      68               3 :     this->file = file;
      69               3 :     this->sysblockmap = sysblockmap;
      70               3 :     this->image_index = image_index;
      71                 : 
      72               3 :     loaded_block = -1;
      73               3 :     loaded_block_dirty = false;
      74                 :     
      75               3 :     last_bm_index = -1;
      76                 : 
      77               3 :     int next_block = start_block;
      78                 : 
      79                 :     // perhaps we should defer all this work till the first request is made?
      80               9 :     while( next_block != -1 )
      81                 :     {
      82               3 :         int offset = 512 + next_block * 28;
      83                 : 
      84               3 :         block_segment.push_back( block_map_data.GetInt( offset+0, 4 ) );
      85               3 :         block_index.push_back( block_map_data.GetInt( offset+4, 8 ) );
      86                 : 
      87               3 :         last_bm_index = next_block;
      88               3 :         next_block = block_map_data.GetInt( offset + 20, 8 );
      89                 :     }
      90                 : 
      91               3 :     assert( block_index.size() * block_size >= file_length );
      92               3 : }
      93                 : 
      94                 : /************************************************************************/
      95                 : /*                          ~SysVirtualFile()                           */
      96                 : /************************************************************************/
      97                 : 
      98               3 : SysVirtualFile::~SysVirtualFile()
      99                 : 
     100                 : {
     101               3 :     Synchronize();
     102               3 : }
     103                 : 
     104                 : /************************************************************************/
     105                 : /*                            Synchronize()                             */
     106                 : /************************************************************************/
     107                 : 
     108               3 : void SysVirtualFile::Synchronize()
     109                 : 
     110                 : {
     111               3 :     if( loaded_block_dirty )
     112                 :     {
     113                 :         PCIDSKSegment *data_seg_obj =
     114               0 :             file->GetSegment( block_segment[loaded_block] );
     115                 : 
     116                 :         data_seg_obj->WriteToFile( block_data,
     117                 :                                    block_size * (uint64) block_index[loaded_block],
     118               0 :                                    block_size );
     119               0 :         loaded_block_dirty = false;
     120                 :     }
     121               3 : }
     122                 : 
     123                 : /************************************************************************/
     124                 : /*                            WriteToFile()                             */
     125                 : /************************************************************************/
     126                 : 
     127                 : void 
     128               0 : SysVirtualFile::WriteToFile( const void *buffer, uint64 offset, uint64 size )
     129                 : 
     130                 : {
     131               0 :     uint64 buffer_offset = 0;
     132                 : 
     133               0 :     while( buffer_offset < size )
     134                 :     {
     135               0 :         int request_block = (int) ((offset + buffer_offset) / block_size);
     136               0 :         int offset_in_block = (int) ((offset + buffer_offset) % block_size);
     137               0 :         int amount_to_copy = block_size - offset_in_block;
     138                 : 
     139               0 :         if (offset_in_block != 0 || (size - buffer_offset) < (uint64)block_size) {
     140                 :             // we need to read in the block for update
     141               0 :             LoadBlock( request_block );
     142               0 :             if( amount_to_copy > (int) (size - buffer_offset) )
     143               0 :                 amount_to_copy = (int) (size - buffer_offset);
     144                 : 
     145                 :             // fill in the block
     146                 :             memcpy( block_data + offset_in_block,
     147                 :                     ((uint8 *) buffer) + buffer_offset,
     148               0 :                     amount_to_copy );
     149                 : 
     150               0 :             loaded_block_dirty = true;
     151                 :         } else {
     152               0 :             int num_full_blocks = (size - buffer_offset) / block_size;
     153                 :             
     154               0 :             WriteBlocks(request_block, num_full_blocks, (uint8*)buffer + buffer_offset);
     155                 :             
     156               0 :             amount_to_copy = num_full_blocks * block_size;
     157                 :         }
     158                 : 
     159               0 :         buffer_offset += amount_to_copy;
     160                 :     }
     161                 : 
     162               0 :     if( offset+size > file_length )
     163                 :     {
     164               0 :         file_length = offset+size;
     165               0 :         sysblockmap->SetVirtualFileSize( image_index, file_length );
     166                 :     }
     167               0 : }
     168                 : 
     169                 : /************************************************************************/
     170                 : /*                            ReadFromFile()                            */
     171                 : /************************************************************************/
     172                 : 
     173               7 : void SysVirtualFile::ReadFromFile( void *buffer, uint64 offset, uint64 size )
     174                 : 
     175                 : {
     176               7 :     uint64 buffer_offset = 0;
     177                 : #if 0
     178                 :     printf("Requesting region at %llu of size %llu\n", offset, size);
     179                 : #endif
     180              21 :     while( buffer_offset < size )
     181                 :     {
     182               7 :         int request_block = (int) ((offset + buffer_offset) / block_size);
     183               7 :         int offset_in_block = (int) ((offset + buffer_offset) % block_size);
     184               7 :         int amount_to_copy = block_size - offset_in_block;
     185                 :         
     186                 : 
     187                 : 
     188              14 :         if (offset_in_block != 0 || (size - buffer_offset) < (uint64)block_size) {
     189                 :             // Deal with the case where we need to load a partial block. Hopefully
     190                 :             // this doesn't happen often
     191               7 :             LoadBlock( request_block );
     192               7 :             if( amount_to_copy > (int) (size - buffer_offset) )
     193               7 :                 amount_to_copy = (int) (size - buffer_offset);
     194                 : #if 0
     195                 :             printf("Requested block: %d Offset: %d copying %d bytes\n",
     196                 :                 request_block, offset_in_block, amount_to_copy);
     197                 : #endif
     198                 :             memcpy( ((uint8 *) buffer) + buffer_offset,
     199               7 :                     block_data + offset_in_block, amount_to_copy );
     200                 :         } else {
     201                 :             // Use the bulk loading of blocks. First, compute the range
     202                 :             // of full blocks we need to load
     203               0 :             int num_full_blocks = (size - buffer_offset)/block_size;
     204                 :             
     205                 : #if 0
     206                 :             printf("Attempting a coalesced read of %d blocks (from %d) in buffer at %d\n", 
     207                 :                 num_full_blocks, request_block, buffer_offset);
     208                 : #endif
     209                 : 
     210               0 :             LoadBlocks(request_block, num_full_blocks, ((uint8*)buffer) + buffer_offset);
     211               0 :             amount_to_copy = num_full_blocks * block_size;
     212                 :         }
     213                 : 
     214                 : 
     215               7 :         buffer_offset += amount_to_copy;
     216                 :     }
     217               7 : }
     218                 : 
     219                 : /************************************************************************/
     220                 : /*                             LoadBlock()                              */
     221                 : /************************************************************************/
     222                 : /**
     223                 :  * Loads the requested_block block from the system virtual file. Extends
     224                 :  * the file if necessary
     225                 :  */
     226               7 : void SysVirtualFile::LoadBlock( int requested_block )
     227                 : 
     228                 : {
     229                 : /* -------------------------------------------------------------------- */
     230                 : /*      Do we already have this block?                                  */
     231                 : /* -------------------------------------------------------------------- */
     232               7 :     if( requested_block == loaded_block )
     233               4 :         return;
     234                 : 
     235                 : /* -------------------------------------------------------------------- */
     236                 : /*      Do we need to grow the virtual file by one block?               */
     237                 : /* -------------------------------------------------------------------- */
     238               3 :     GrowVirtualFile(requested_block);
     239                 : 
     240                 : /* -------------------------------------------------------------------- */
     241                 : /*      Does this block exist in the virtual file?                      */
     242                 : /* -------------------------------------------------------------------- */
     243               3 :     if( requested_block < 0 || requested_block >= (int) block_index.size() )
     244                 :         ThrowPCIDSKException( "SysVirtualFile::LoadBlock(%d) - block out of range.",
     245               0 :                               requested_block );
     246                 : 
     247                 : /* -------------------------------------------------------------------- */
     248                 : /*      Do we have a dirty block loaded that needs to be saved?         */
     249                 : /* -------------------------------------------------------------------- */
     250               3 :     FlushDirtyBlock();
     251                 : 
     252                 : /* -------------------------------------------------------------------- */
     253                 : /*      Load the requested block.                                       */
     254                 : /* -------------------------------------------------------------------- */
     255                 :     PCIDSKSegment *data_seg_obj =
     256               3 :         file->GetSegment( block_segment[requested_block] );
     257                 : 
     258                 :     data_seg_obj->ReadFromFile( block_data,
     259                 :                                 block_size * (uint64) block_index[requested_block],
     260               3 :                                 block_size );
     261                 : 
     262               3 :     loaded_block = requested_block;
     263               3 :     loaded_block_dirty = false;
     264                 : }
     265                 : 
     266                 : /************************************************************************/
     267                 : /*                         FlushDirtyBlock()                            */
     268                 : /************************************************************************/
     269                 : /**
     270                 :  * If the block currently loaded is dirty, flush it to the file
     271                 :  */
     272               3 : void SysVirtualFile::FlushDirtyBlock(void)
     273                 : {
     274               3 :     if (loaded_block_dirty) {
     275                 :         PCIDSKSegment *data_seg_obj =
     276               0 :             file->GetSegment( block_segment[loaded_block] );
     277                 :         
     278                 :         data_seg_obj->WriteToFile( block_data,
     279                 :                                    block_size * (uint64) block_index[loaded_block],
     280               0 :                                    block_size );
     281               0 :         loaded_block_dirty = false;
     282                 :     }
     283               3 : }
     284                 : 
     285               3 : void SysVirtualFile::GrowVirtualFile(std::ptrdiff_t requested_block)
     286                 : {
     287               3 :     if( requested_block == (int) block_index.size() )
     288                 :     {
     289                 :         int new_seg;
     290                 : 
     291                 :         block_index.push_back( 
     292                 :             sysblockmap->GrowVirtualFile( image_index,
     293               0 :                                           last_bm_index, new_seg ) );
     294               0 :         block_segment.push_back( new_seg );
     295                 :     }
     296               3 : }
     297                 : 
     298                 : /**
     299                 :  * \brief Writes a group of blocks
     300                 :  * Attempts to create a group of blocks (if the SysVirtualFile
     301                 :  * is not already large enough to hold them) and then write them
     302                 :  * out contiguously
     303                 :  */
     304                 : void SysVirtualFile::WriteBlocks(int first_block,
     305                 :                                  int block_count,
     306               0 :                                  void* const buffer)
     307                 : {
     308               0 :     FlushDirtyBlock();
     309                 :     // Iterate through all the blocks to be written, first, then
     310                 :     // grow the virtual file
     311               0 :     for (unsigned int i = 0; i <= (unsigned int) block_count; i++) {
     312               0 :         GrowVirtualFile(first_block + i);
     313                 :     }
     314                 :     
     315                 :     // Using a similar algorithm to the LoadBlocks() function,
     316                 :     // attempt to coalesce writes
     317               0 :     std::size_t buffer_off = 0;
     318               0 :     std::size_t blocks_written = 0;
     319               0 :     std::size_t current_first_block = first_block;
     320               0 :     while (blocks_written < (std::size_t) block_count) {
     321               0 :         unsigned int cur_segment = block_segment[current_first_block];
     322               0 :         unsigned int cur_block = current_first_block;
     323               0 :         while (cur_block < (unsigned int)block_count + first_block &&
     324                 :             (unsigned int)block_segment[cur_block + 1] == cur_segment)
     325                 :         {
     326               0 :             cur_block++;
     327                 :         }
     328                 :         
     329                 :         // Find largest span of contiguous blocks we can write
     330               0 :         uint64 write_start = block_index[current_first_block];
     331               0 :         uint64 write_cur = write_start * block_size;
     332               0 :         unsigned int count_to_write = 1;
     333               0 :         while (write_cur + block_size ==
     334                 :             (uint64)block_index[count_to_write + current_first_block - 1] * block_size &&
     335                 :             count_to_write < (cur_block - current_first_block))
     336                 :         {
     337               0 :             write_cur += block_size;
     338               0 :             count_to_write++;
     339                 :         }
     340                 :         
     341                 :         PCIDSKSegment *data_seg_obj =
     342               0 :             file->GetSegment( cur_segment );
     343                 :         
     344               0 :         std::size_t bytes_to_write = count_to_write * block_size;
     345                 :         
     346                 :         data_seg_obj->WriteToFile((uint8*)buffer + buffer_off,
     347                 :                                   block_size * write_start,
     348               0 :                                   bytes_to_write);
     349                 :     
     350               0 :         buffer_off += bytes_to_write;
     351               0 :         blocks_written += count_to_write;
     352               0 :         current_first_block += count_to_write;
     353                 :     }
     354               0 : }
     355                 : 
     356                 : /**
     357                 :  * \brief Load a group of blocks
     358                 :  * Attempts to coalesce reading of groups of blocks into a single
     359                 :  * filesystem I/O operation. Does not cache the loaded block, nor
     360                 :  * does it modify the state of the SysVirtualFile, other than to
     361                 :  * flush the loaded block if it is dirty.
     362                 :  */
     363                 : void SysVirtualFile::LoadBlocks(int requested_block_start,
     364                 :                                 int requested_block_count,
     365               0 :                                 void* const buffer)
     366                 : {
     367               0 :     FlushDirtyBlock();
     368               0 :     unsigned int blocks_read = 0;
     369               0 :     unsigned int current_start = requested_block_start;
     370                 :     
     371               0 :     std::size_t buffer_off = 0;
     372                 :     
     373               0 :     while (blocks_read < (unsigned int)requested_block_count) {
     374                 :         // Coalesce blocks that are in the same segment
     375               0 :         unsigned int cur_segment = block_segment[current_start]; // segment of current
     376                 :                 // first block
     377               0 :         unsigned int cur_block = current_start; // starting block ID
     378               0 :         while (cur_block < (unsigned int)requested_block_count + requested_block_start &&
     379                 :             (unsigned int)block_segment[cur_block + 1] == cur_segment) {
     380                 :             // this block is in the same segment as the previous one we
     381                 :             // wanted to read.
     382               0 :             cur_block++;
     383                 :         }
     384                 :         
     385                 :         // now attempt to determine if the region of blocks (from current_start
     386                 :         // to cur_block are contiguous
     387               0 :         uint64 read_start = block_index[current_start];
     388               0 :         uint64 read_cur = read_start * block_size;
     389               0 :         unsigned int count_to_read = 1; // we'll read at least one block
     390               0 :         while (read_cur + block_size ==
     391                 :             (uint64)block_index[count_to_read + current_start] * block_size && // compare count of blocks * offset with stored offset
     392                 :             count_to_read < (cur_block - current_start) ) // make sure we don't try to read more blocks than we determined fell in
     393                 :                                                             // this segment
     394                 :         {
     395               0 :             read_cur += block_size;
     396               0 :             count_to_read++;
     397                 :         }
     398                 : 
     399                 : #if 0
     400                 : 
     401                 :         // Check if we need to grow the virtual file for each of these blocks
     402                 :         for (unsigned int i = 0 ; i < count_to_read; i++) {
     403                 :             GrowVirtualFile(i + current_start);
     404                 :         }
     405                 :         
     406                 :         
     407                 :         printf("Coalescing the read of %d blocks\n", count_to_read);
     408                 : #endif
     409                 : 
     410                 :         // Perform the actual read
     411                 :         PCIDSKSegment *data_seg_obj =
     412               0 :             file->GetSegment( cur_segment );
     413                 :         
     414               0 :         std::size_t data_size = block_size * count_to_read;
     415                 : 
     416                 : #if 0
     417                 :         printf("Reading %d bytes at offset %d in buffer\n", data_size, buffer_off);
     418                 : #endif
     419                 : 
     420                 :         data_seg_obj->ReadFromFile( ((uint8*)buffer) + buffer_off,
     421                 :                                     block_size * read_start,
     422               0 :                                     data_size );
     423                 :                                     
     424               0 :         buffer_off += data_size; // increase buffer offset
     425                 :         
     426                 :         // Increment the current start by the number of blocks we jsut read
     427               0 :         current_start += count_to_read;
     428               0 :         blocks_read += count_to_read;
     429                 :     }
     430               0 : }
     431                 : 

Generated by: LTP GCOV extension version 1.5