FreeBSD/contrib/subversion/subversion/libsvn_fs_fs/cached_data.c
/* Read the whole (e.g. 64kB) block containing ITEM_INDEX of REVISION in FS
 * and put all data into cache.  If necessary and depending on heuristics,
 * neighboring blocks may also get read.  The data is being read from
 * already open REVISION_FILE, which must be the correct rev / pack file
 * w.r.t. REVISION.
 *
 * For noderevs and changed path lists, the item fetched can be allocated
 * RESULT_POOL and returned in *RESULT.  Otherwise, RESULT must be NULL.
 */
Read the whole  block containing ITEM_INDEX of REVISION in FS
and put all data into cache.  If necessary and depending on heuristics,
neighboring blocks may also get read.  The data is being read from
already open REVISION_FILE, which must be the correct rev / pack file
w.r.t. REVISION.

For noderevs and changed path lists, the item fetched can be allocated
RESULT_POOL and returned in *RESULT.  Otherwise, RESULT must be NULL.
Read the whole block containing ITEM_INDEX of REVISION in FS and put all data into cache . If necessary and depending on heuristics neighboring blocks may also get read . The data is being read from already open REVISION_FILE which must be the correct rev / pack file w . r . t . REVISION . For noderevs and changed path lists the item fetched can be allocated RESULT_POOL and returned in * RESULT . Otherwise RESULT must be NULL .
static svn_error_t *
block_read(void **result,
           svn_fs_t *fs,
           svn_revnum_t revision,
           apr_uint64_t item_index,
           svn_fs_fs__revision_file_t *revision_file,
           apr_pool_t *result_pool,
           apr_pool_t *scratch_pool)
{
  fs_fs_data_t *ffd = fs->fsap_data;
  apr_off_t offset, wanted_offset = 0;
  apr_off_t block_start = 0;
  apr_array_header_t *entries;
  int run_count = 0;
  int i;
  apr_pool_t *iterpool;
  if (!result)
    return SVN_NO_ERROR;
  iterpool = svn_pool_create(scratch_pool);
  SVN_ERR_ASSERT(SVN_IS_VALID_REVNUM(revision));
  SVN_ERR(svn_fs_fs__item_offset(&wanted_offset, fs, revision_file,
                                 revision, NULL, item_index, iterpool));
  offset = wanted_offset;
  do
    {
      block_start = offset - (offset % ffd->block_size);
      SVN_ERR(svn_fs_fs__p2l_index_lookup(&entries, fs, revision_file,
                                          revision, block_start,
                                          ffd->block_size, scratch_pool,
                                          scratch_pool));
      SVN_ERR(aligned_seek(fs, revision_file->file, &block_start, offset,
                           iterpool));
      for (i = 0; i < entries->nelts; ++i)
        {
          svn_boolean_t is_result, is_wanted;
          apr_pool_t *pool;
          svn_fs_fs__p2l_entry_t* entry;
          svn_pool_clear(iterpool);
          entry = &APR_ARRAY_IDX(entries, i, svn_fs_fs__p2l_entry_t);
          if (entry->type == SVN_FS_FS__ITEM_TYPE_UNUSED)
            continue;
          is_wanted =    entry->offset == wanted_offset
                      && entry->item.revision == revision
                      && entry->item.number == item_index;
          is_result = result && is_wanted;
          pool = is_result ? result_pool : iterpool;
          if (is_result || (   entry->offset >= block_start
                            && entry->size < ffd->block_size))
            {
              void *item = NULL;
              SVN_ERR(svn_io_file_seek(revision_file->file, APR_SET,
                                       &entry->offset, iterpool));
              switch (entry->type)
                {
                  case SVN_FS_FS__ITEM_TYPE_FILE_REP:
                  case SVN_FS_FS__ITEM_TYPE_DIR_REP:
                  case SVN_FS_FS__ITEM_TYPE_FILE_PROPS:
                  case SVN_FS_FS__ITEM_TYPE_DIR_PROPS:
                    SVN_ERR(block_read_contents(fs, revision_file, entry,
                                                is_wanted
                                                  ? -1
                                                  : block_start + ffd->block_size,
                                                pool, iterpool));
                    break;
                  case SVN_FS_FS__ITEM_TYPE_NODEREV:
                    if (ffd->node_revision_cache || is_result)
                      SVN_ERR(block_read_noderev((node_revision_t **)&item,
                                                 fs, revision_file,
                                                 entry, is_result, pool,
                                                 iterpool));
                    break;
                  case SVN_FS_FS__ITEM_TYPE_CHANGES:
                    SVN_ERR(block_read_changes((apr_array_header_t **)&item,
                                               fs, revision_file,
                                               entry, is_result,
                                               pool, iterpool));
                    break;
                  default:
                    break;
                }
              if (is_result)
                *result = item;
              offset = entry->offset + entry->size;
              if (offset > block_start + ffd->block_size)
                ++run_count;
            }
        }
    }
  while(run_count++ == 1); 
  assert(!result || *result);
  svn_pool_destroy(iterpool);
  return SVN_NO_ERROR;
}
static svn_error_t * block_read ( void * * result , svn_fs_t * fs , svn_revnum_t revision , apr_uint64_t item_index , svn_fs_fs__revision_file_t * revision_file , apr_pool_t * result_pool , apr_pool_t * scratch_pool ) { fs_fs_data_t * ffd = fs -> fsap_data ; apr_off_t offset , wanted_offset = 0 ; apr_off_t block_start = 0 ; apr_array_header_t * entries ; int run_count = 0 ; int i ; apr_pool_t * iterpool ; if ( ! result ) return SVN_NO_ERROR ; iterpool = svn_pool_create ( scratch_pool ) ; SVN_ERR_ASSERT ( SVN_IS_VALID_REVNUM ( revision ) ) ; SVN_ERR ( svn_fs_fs__item_offset ( & wanted_offset , fs , revision_file , revision , NULL , item_index , iterpool ) ) ; offset = wanted_offset ; do { block_start = offset - ( offset % ffd -> block_size ) ; SVN_ERR ( svn_fs_fs__p2l_index_lookup ( & entries , fs , revision_file , revision , block_start , ffd -> block_size , scratch_pool , scratch_pool ) ) ; SVN_ERR ( aligned_seek ( fs , revision_file -> file , & block_start , offset , iterpool ) ) ; for ( i = 0 ; i < entries -> nelts ; ++ i ) { svn_boolean_t is_result , is_wanted ; apr_pool_t * pool ; svn_fs_fs__p2l_entry_t * entry ; svn_pool_clear ( iterpool ) ; entry = & APR_ARRAY_IDX ( entries , i , svn_fs_fs__p2l_entry_t ) ; if ( entry -> type == SVN_FS_FS__ITEM_TYPE_UNUSED ) continue ; is_wanted = entry -> offset == wanted_offset && entry -> item . revision == revision && entry -> item . number == item_index ; is_result = result && is_wanted ; pool = is_result ? result_pool : iterpool ; if ( is_result || ( entry -> offset >= block_start && entry -> size < ffd -> block_size ) ) { void * item = NULL ; SVN_ERR ( svn_io_file_seek ( revision_file -> file , APR_SET , & entry -> offset , iterpool ) ) ; switch ( entry -> type ) { case SVN_FS_FS__ITEM_TYPE_FILE_REP : case SVN_FS_FS__ITEM_TYPE_DIR_REP : case SVN_FS_FS__ITEM_TYPE_FILE_PROPS : case SVN_FS_FS__ITEM_TYPE_DIR_PROPS : SVN_ERR ( block_read_contents ( fs , revision_file , entry , is_wanted ? -1 : block_start + ffd -> block_size , pool , iterpool ) ) ; break ; case SVN_FS_FS__ITEM_TYPE_NODEREV : if ( ffd -> node_revision_cache || is_result ) SVN_ERR ( block_read_noderev ( ( node_revision_t * * ) & item , fs , revision_file , entry , is_result , pool , iterpool ) ) ; break ; case SVN_FS_FS__ITEM_TYPE_CHANGES : SVN_ERR ( block_read_changes ( ( apr_array_header_t * * ) & item , fs , revision_file , entry , is_result , pool , iterpool ) ) ; break ; default : break ; } if ( is_result ) * result = item ; offset = entry -> offset + entry -> size ; if ( offset > block_start + ffd -> block_size ) ++ run_count ; } } } while ( run_count ++ == 1 ) ; assert ( ! result || * result ) ; svn_pool_destroy ( iterpool ) ; return SVN_NO_ERROR ; }
Read the whole (e.g.
Read the whole ( e . g .
/* Block read is an optional feature. If the caller does not want anything
   * specific we may not have to read anything. */ /* don't try this on transaction protorev files */ /* index lookup: find the OFFSET of the item we *must* read plus (in the
   * "do-while" block) the list of items in the same block. */ /* Heuristics:
   *
   * Read this block.  If the last item crosses the block boundary, read
   * the next block but stop there.  Because cross-boundary items cause
   * blocks to be read twice, this heuristics will limit this effect to
   * approx. 50% of blocks, probably less, while providing a sensible
   * amount of read-ahead.
   */ /* fetch list of items in the block surrounding OFFSET */ /* read all items from the block */ /* skip empty sections */ /* the item / container we were looking for? */ /* select the pool that we want the item to be allocated in */ /* handle all items that start within this block and are relatively
           * small (i.e. < block size).  Always read the item we need to return.
           */ /* if we crossed a block boundary, read the remainder of
               * the last block as well */ /* can only be true once and only if a block
                            * boundary got crossed */ /* if the caller requested a result, we must have provided one by now */