Author: stefan2
Date: Wed Jan  9 04:16:12 2013
New Revision: 1430676

URL: http://svn.apache.org/viewvc?rev=1430676&view=rev
Log:
On the fsfs-format7 branch: Initial implementation of the logical id <->
physical offset indexes.  Work in progress.

* subversion/include/svn_error_codes.h
  (SVN_ERR_FS_ITEM_INDEX_CORRUPTION,
   SVN_ERR_FS_ITEM_INDEX_REVISION,
   SVN_ERR_FS_ITEM_INDEX_OVERFLOW): declare new error codes

* subversion/libsvn_fs_fs/index.h
  (new internal API header file)
* subversion/libsvn_fs_fs/index.c
  (new implementation file)

Added:
    subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c
    subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h
Modified:
    subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h

Modified: subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h?rev=1430676&r1=1430675&r2=1430676&view=diff
==============================================================================
--- subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h 
(original)
+++ subversion/branches/fsfs-format7/subversion/include/svn_error_codes.h Wed 
Jan  9 04:16:12 2013
@@ -792,6 +792,21 @@ SVN_ERROR_START
              SVN_ERR_FS_CATEGORY_START + 52,
              "Could not initialize the revprop caching infrastructure.")
 
+  /** @since New in 1.9. */
+  SVN_ERRDEF(SVN_ERR_FS_ITEM_INDEX_CORRUPTION,
+             SVN_ERR_FS_CATEGORY_START + 53,
+             "Corrupt index file.")
+
+  /** @since New in 1.9. */
+  SVN_ERRDEF(SVN_ERR_FS_ITEM_INDEX_REVISION,
+             SVN_ERR_FS_CATEGORY_START + 54,
+             "Revision not covered by index.")
+
+  /** @since New in 1.9. */
+  SVN_ERRDEF(SVN_ERR_FS_ITEM_INDEX_OVERFLOW,
+             SVN_ERR_FS_CATEGORY_START + 55,
+             "Item index too large for this revision.")
+
   /* repos errors */
 
   SVN_ERRDEF(SVN_ERR_REPOS_LOCKED,

Added: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c
URL: 
http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c?rev=1430676&view=auto
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c (added)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.c Wed Jan  9 
04:16:12 2013
@@ -0,0 +1,713 @@
+/* index.c indexing support for FSFS support
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#include "svn_io.h"
+#include "svn_pools.h"
+
+#include "index.h"
+#include "util.h"
+
+#include "private/svn_subr_private.h"
+#include "private/svn_temp_serializer.h"
+
+#include "svn_private_config.h"
+#include "temp_serializer.h"
+#include <apr_poll.h>
+
+#define ENCODED_INT_LENGTH 10
+
+typedef struct l2_index_page_table_entry_t
+{
+  apr_uint64_t offset;
+  apr_uint32_t entry_count;
+  apr_uint32_t size;
+} l2_index_page_table_entry_t;
+
+typedef struct l2p_index_header_t
+{
+  svn_revnum_t first_revision;
+  apr_size_t revision_count;
+  l2_index_page_table_entry_t ** page_tables;
+  l2_index_page_table_entry_t * page_table;
+} l2p_index_header_t;
+
+typedef struct l2p_index_page_t
+{
+  apr_uint32_t entry_count;
+  apr_off_t *offsets;
+} l2p_index_page_t;
+
+typedef struct p2l_index_header_t
+{
+  svn_revnum_t first_revision;
+  apr_size_t page_count;
+  apr_off_t *offsets;
+} p2l_index_header_t;
+
+svn_error_t *
+svn_fs_fs__l2p_proto_index_open(apr_file_t **proto_index,
+                                const char *file_name,
+                                apr_pool_t *pool)
+{
+  SVN_ERR(svn_io_file_open(proto_index, file_name,
+                           APR_READ | APR_WRITE
+                           | APR_CREATE | APR_APPEND | APR_BUFFERED,
+                           APR_OS_DEFAULT, pool));
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+write_number_to_proto_index(apr_file_t *proto_index,
+                            apr_uint64_t value,
+                            apr_pool_t *pool)
+{
+  apr_size_t written = sizeof(value);
+
+  SVN_ERR(svn_io_file_write(proto_index, &value, &written, pool));
+  SVN_ERR_ASSERT(written == sizeof(value));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__l2p_proto_index_add_revision(apr_file_t *proto_index,
+                                        apr_pool_t *pool)
+{
+  return write_number_to_proto_index(proto_index, (apr_uint64_t)(-1), pool);
+}
+
+svn_error_t *
+svn_fs_fs__l2p_proto_index_add_offset(apr_file_t *proto_index,
+                                      apr_off_t offset,
+                                      apr_pool_t *pool)
+{
+  SVN_ERR_ASSERT(offset >= 0);
+  return write_number_to_proto_index(proto_index, (apr_uint64_t)offset, pool);
+}
+
+static apr_size_t
+encode_uint(unsigned char *p, apr_uint64_t value)
+{
+  unsigned char *start = p;
+  while (value >= 0x80)
+    {
+      *p = (unsigned char)((value % 0x80) + 0x80);
+      value /= 0x80;
+      ++p;
+    }
+
+  *p = (unsigned char)(value % 0x80);
+  return (p - start) + 1;
+}
+
+svn_error_t *
+svn_fs_fs__l2p_index_create(apr_file_t *proto_index,
+                            svn_fs_t *fs,
+                            svn_revnum_t revision,
+                            apr_pool_t *pool)
+{
+  apr_off_t offset = 0;
+  int i;
+  apr_uint64_t entry;
+  svn_boolean_t eof = FALSE;
+  apr_file_t *index_file;
+  unsigned char encoded[ENCODED_INT_LENGTH];
+
+  apr_uint64_t page_start = 0;      /* first source entry number of the
+                                       current page */
+  int last_page_count = 0;          /* total page count at the start of
+                                       the current revision */
+  apr_size_t last_buffer_size = 0;  /* byte offset in the spill buffer at
+                                       the begin of the current revision */
+
+  /* temporary data structures that collect the data which will be moved
+     to the target file in a second step */
+  apr_pool_t *local_pool = svn_pool_create(pool);
+  apr_array_header_t *page_counts
+     = apr_array_make(local_pool, 16, sizeof(apr_uint64_t));
+  apr_array_header_t *page_sizes
+     = apr_array_make(local_pool, 16, sizeof(apr_uint64_t));
+  apr_array_header_t *entry_counts
+     = apr_array_make(local_pool, 16, sizeof(apr_uint64_t));
+
+  /* 64k blocks, spill after 16MB */
+  svn_spillbuf_t *buffer
+     = svn_spillbuf__create(0x10000, 0x1000000, local_pool);
+
+  /* start at the beginning of the source file */
+  offset = 0;
+  SVN_ERR(svn_io_file_seek(proto_index, SEEK_SET, &offset, local_pool));
+
+  /* process all entries until we fail due to EOF */
+  for (entry = 0; !eof; ++entry)
+    {
+      apr_uint64_t value = 0;
+      apr_size_t read = 0;
+      svn_boolean_t revision_boundary;
+      svn_boolean_t page_full;
+
+      /* (attempt to) read the next entry from the source */
+      SVN_ERR(svn_io_file_read_full2(proto_index, &value, sizeof(value),
+                                     &read, &eof, local_pool));
+      SVN_ERR_ASSERT(read == sizeof(value));
+
+      /* end the page after 8k entries */
+      page_full = (entry - page_start) > 0x2000;
+      revision_boundary = value == -1 || eof;
+
+      /* end the page after 4k entries or after */
+      if (revision_boundary || page_full)
+        {
+          /* store prev. page's dimensions, iff that exists */
+          if (entry > 0)
+            {
+              APR_ARRAY_PUSH(entry_counts, apr_uint64_t)
+                = entry - page_start;
+              APR_ARRAY_PUSH(page_sizes, apr_uint64_t)
+                = svn_spillbuf__get_size(buffer) - last_buffer_size;
+            }
+
+          last_buffer_size = svn_spillbuf__get_size(buffer);
+          page_start = entry;
+        }
+
+      /* handle new revision */
+      if (revision_boundary)
+        {
+          /* store number of pages in previous rev, iff that exists */
+          if (entry > 0)
+            APR_ARRAY_PUSH(page_counts, apr_uint64_t)
+              = page_sizes->nelts - last_page_count;
+
+          last_page_count = page_sizes->nelts;
+          page_start = entry + 1;
+        }
+      else
+        {
+          SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded,
+                                      encode_uint(encoded, value),
+                                      local_pool));
+        }
+    }
+
+  /* create the target file */
+  SVN_ERR(svn_io_file_open(&index_file,
+                           path_l2p_index(fs, revision, local_pool),
+                           APR_WRITE | APR_CREATE | APR_TRUNCATE
+                           | APR_BUFFERED,
+                           APR_OS_DEFAULT, local_pool));
+
+  /* write the start revision */
+  SVN_ERR(svn_io_file_write_full(index_file, encoded,
+                                 encode_uint(encoded, revision),
+                                 NULL, local_pool));
+
+  /* write the revision table */
+  SVN_ERR(svn_io_file_write_full(index_file, encoded,
+                                 encode_uint(encoded, page_counts->nelts),
+                                 NULL, local_pool));
+  for (i = 0; i < page_counts->nelts; ++i)
+    {
+      apr_uint64_t value = APR_ARRAY_IDX(page_counts, i, apr_uint64_t);
+      SVN_ERR(svn_io_file_write_full(index_file, encoded,
+                                     encode_uint(encoded, value),
+                                     NULL, local_pool));
+    }
+    
+  /* write the page table */
+  SVN_ERR(svn_io_file_write_full(index_file, encoded,
+                                 encode_uint(encoded, page_sizes->nelts),
+                                 NULL, local_pool));
+  for (i = 0; i < page_sizes->nelts; ++i)
+    {
+      apr_uint64_t value = APR_ARRAY_IDX(page_sizes, i, apr_uint64_t);
+      SVN_ERR(svn_io_file_write_full(index_file, encoded,
+                                     encode_uint(encoded, value),
+                                     NULL, local_pool));
+      value = APR_ARRAY_IDX(entry_counts, i, apr_uint64_t);
+      SVN_ERR(svn_io_file_write_full(index_file, encoded,
+                                     encode_uint(encoded, value),
+                                     NULL, local_pool));
+    }
+
+  /* append page contents */
+  SVN_ERR(svn_stream_copy3(svn_stream__from_spillbuf(buffer, local_pool),
+                           svn_stream_from_aprfile2(index_file, TRUE,
+                                                    local_pool),
+                           NULL, NULL, local_pool));
+  
+  svn_pool_destroy(local_pool);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+read_number(apr_uint64_t *value,
+            apr_file_t *file,
+            apr_pool_t *pool)
+{
+  unsigned char byte;
+  apr_uint64_t shift = 0;
+  
+  *value = 0;
+  do
+    {
+      if (shift > 8 * sizeof(value))
+        return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_CORRUPTION, NULL,
+                                 _("Corrupt index: number too large"));
+
+      SVN_ERR(svn_io_file_getc((char*)&byte, file, pool));
+      *value += ((apr_uint64_t)byte) << shift;
+      shift += 7;
+    }
+  while (byte >= 0x80);
+
+  return SVN_NO_ERROR;
+}            
+
+static svn_error_t *
+get_l2p_header(l2p_index_header_t **header,
+               svn_fs_t *fs,
+               svn_revnum_t revision,
+               apr_pool_t *pool)
+{
+  apr_uint64_t value;
+  int i;
+  apr_size_t page, page_count;
+  apr_off_t offset;
+  l2p_index_header_t *result = apr_pcalloc(pool, sizeof(*result));
+  
+  apr_file_t *file = NULL;
+  SVN_ERR(svn_io_file_open(&file, path_l2p_index(fs, revision, pool),
+                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
+
+  SVN_ERR(read_number(&value, file, pool));
+  result->first_revision = (svn_revnum_t)value;
+  SVN_ERR(read_number(&value, file, pool));
+  result->revision_count = (int)value;
+  SVN_ERR(read_number(&value, file, pool));
+  page_count = (apr_size_t)value;
+
+  result->page_table
+    = apr_pcalloc(pool, page_count * sizeof(*result->page_table));
+  result->page_tables
+    = apr_pcalloc(pool, (result->revision_count + 1)
+                      * sizeof(*result->page_tables));
+
+  result->page_tables[0] = result->page_table;
+  for (i = 0; i < result->revision_count; ++i)
+    {
+      SVN_ERR(read_number(&value, file, pool));
+      result->page_tables[i+1] = result->page_tables[i] + (apr_size_t)value;
+    }
+
+  for (page = 0; page < page_count; ++page)
+    {
+      SVN_ERR(read_number(&value, file, pool));
+      result->page_table[page].size = (apr_uint32_t)value;
+      SVN_ERR(read_number(&value, file, pool));
+      result->page_table[page].entry_count = (apr_uint32_t)value;
+    }
+
+  offset = 0;
+  SVN_ERR(svn_io_file_seek(file, SEEK_CUR, &offset, pool));
+  for (page = 0; page < page_count; ++page)
+    {
+      result->page_table[page].offset = offset;
+      offset += result->page_table[page].size;
+    }
+
+  SVN_ERR(svn_io_file_close(file, pool));
+  *header = result;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+get_l2p_page(l2p_index_page_t **page,
+             svn_fs_t *fs,
+             svn_revnum_t start_revision,
+             l2_index_page_table_entry_t *table_entry,
+             apr_pool_t *pool)
+{
+  apr_uint64_t value;
+  apr_uint32_t i;
+  apr_off_t offset;
+  l2p_index_page_t *result = apr_pcalloc(pool, sizeof(*result));
+
+  apr_file_t *file = NULL;
+  SVN_ERR(svn_io_file_open(&file, path_l2p_index(fs, start_revision, pool),
+                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
+
+  offset = table_entry->offset;
+  SVN_ERR(svn_io_file_seek(file, SEEK_SET, &offset, pool));
+
+  result->entry_count = table_entry->entry_count;
+  result->offsets = apr_pcalloc(pool, (result->entry_count + 1)
+                                    * sizeof(*result->offsets));
+  for (i = 0; i < result->entry_count; ++i)
+    {
+      result->offsets[i] = offset;
+      SVN_ERR(read_number(&value, file, pool));
+      offset += (apr_off_t)value;
+    }
+
+  SVN_ERR(svn_io_file_close(file, pool));
+  *page = result;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__l2p_index_lookup(apr_off_t *offset,
+                            svn_fs_t *fs,
+                            svn_revnum_t revision,
+                            apr_uint64_t item_index,
+                            apr_pool_t *pool)
+{
+  l2p_index_header_t *header = NULL;
+  l2p_index_page_t *page = NULL;
+  l2_index_page_table_entry_t *entry, *first_entry, *last_entry;
+
+  SVN_ERR(get_l2p_header(&header, fs, revision, pool));
+  if (   (header->first_revision > revision)
+      || (header->first_revision + header->revision_count <= revision))
+    return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_REVISION , NULL,
+                             _("Revision %ld not covered by item index"),
+                             revision);
+
+  first_entry = header->page_tables[revision - header->first_revision];
+  last_entry = header->page_tables[revision + 1 - header->first_revision];
+  for (entry = first_entry; entry < last_entry; ++entry)
+    if (entry->entry_count > item_index)
+      break;
+    else
+      item_index -= entry->entry_count;
+
+  SVN_ERR(get_l2p_page(&page, fs, header->first_revision, entry, pool));
+  if (page->entry_count <= item_index)
+    return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                             _("Item index %" APR_UINT64_T_FMT
+                               " too large in revision %ld"),
+                             item_index, revision);
+
+  *offset = page->offsets[item_index];
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__p2l_proto_index_open(apr_file_t **proto_index,
+                                const char *file_name,
+                                apr_pool_t *pool)
+{
+  SVN_ERR(svn_io_file_open(proto_index, file_name,
+                           APR_READ | APR_WRITE
+                           | APR_CREATE | APR_APPEND | APR_BUFFERED,
+                           APR_OS_DEFAULT, pool));
+
+  return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_fs_fs__p2l_proto_index_add_entry(apr_file_t *proto_index,
+                                     svn_fs_fs__p2l_entry_t *entry,
+                                     apr_pool_t *pool)
+{
+  apr_size_t written = sizeof(*entry);
+
+  SVN_ERR(svn_io_file_write_full(proto_index, entry, sizeof(*entry),
+                                 &written, pool));
+  SVN_ERR_ASSERT(written == sizeof(*entry));
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__p2l_index_create(apr_file_t *proto_index,
+                            svn_fs_t *fs,
+                            svn_revnum_t revision,
+                            apr_pool_t *pool)
+{
+  apr_off_t offset = 0;
+  int i;
+  svn_boolean_t eof = FALSE;
+  apr_file_t *index_file;
+  unsigned char encoded[ENCODED_INT_LENGTH];
+  apr_uint64_t page_size = 0x10000;
+
+  apr_uint64_t last_entry_end = 0;
+  apr_uint64_t last_page_end = 0;
+  apr_size_t last_buffer_size = 0;  /* byte offset in the spill buffer at
+                                       the begin of the current revision */
+
+  /* temporary data structures that collect the data which will be moved
+     to the target file in a second step */
+  apr_pool_t *local_pool = svn_pool_create(pool);
+  apr_array_header_t *table_sizes
+     = apr_array_make(local_pool, 16, sizeof(apr_uint64_t));
+
+  /* 64k blocks, spill after 16MB */
+  svn_spillbuf_t *buffer
+     = svn_spillbuf__create(0x10000, 0x1000000, local_pool);
+
+  /* start at the beginning of the source file */
+  offset = 0;
+  SVN_ERR(svn_io_file_seek(proto_index, SEEK_SET, &offset, local_pool));
+
+  /* process all entries until we fail due to EOF */
+  while (!eof)
+    {
+      svn_fs_fs__p2l_entry_t entry;
+      apr_size_t read = 0;
+      apr_uint64_t entry_end;
+      svn_boolean_t new_page = table_sizes->nelts > 0;
+
+      /* (attempt to) read the next entry from the source */
+      SVN_ERR(svn_io_file_read_full2(proto_index, &entry, sizeof(entry),
+                                     &read, &eof, local_pool));
+      SVN_ERR_ASSERT(read == sizeof(entry));
+
+      /* "unused" (and usually non-existent) section to cover the offsets
+         at the end the of the last page. */
+      if (eof)
+        {
+          entry.offset = last_entry_end;
+          entry.size = APR_ALIGN(entry.offset, page_size) - entry.offset;
+          entry.type = 0;
+          entry.revision = 0;
+          entry.item_index = 0;
+        }
+
+      /* end tables while entry is extending behind them */
+      entry_end = entry.offset + entry.size;
+      while (entry_end - last_page_end > page_size)
+        {
+          apr_uint64_t buffer_size = svn_spillbuf__get_size(buffer);
+          APR_ARRAY_PUSH(table_sizes, apr_uint64_t)
+             = buffer_size - last_buffer_size;
+
+          last_buffer_size = buffer_size;
+          last_page_end += page_size;
+          new_page = TRUE;
+        }
+
+      /* this entry starts a new table -> store its offset
+         (all following entries in the same table will store sizes only) */
+      if (new_page)
+        SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded,
+                                    encode_uint(encoded, entry.offset),
+                                    local_pool));
+
+      /* write entry */
+      SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded,
+                                  encode_uint(encoded, entry.size),
+                                  local_pool));
+      SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded,
+                                  encode_uint(encoded, entry.type),
+                                  local_pool));
+      SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded,
+                                  encode_uint(encoded, entry.revision),
+                                  local_pool));
+      SVN_ERR(svn_spillbuf__write(buffer, (const char *)encoded,
+                                  encode_uint(encoded, entry.item_index),
+                                  local_pool));
+
+      last_entry_end = entry_end;
+    }
+
+  /* store length of last table */
+  APR_ARRAY_PUSH(table_sizes, apr_uint64_t)
+      = svn_spillbuf__get_size(buffer) - last_buffer_size;
+
+  /* write the start revision */
+  SVN_ERR(svn_io_file_write_full(index_file, encoded,
+                                 encode_uint(encoded, revision),
+                                 NULL, local_pool));
+
+  /* create the target file */
+  SVN_ERR(svn_io_file_open(&index_file,
+                           path_l2p_index(fs, revision, local_pool),
+                           APR_WRITE | APR_CREATE | APR_TRUNCATE
+                           | APR_BUFFERED,
+                           APR_OS_DEFAULT, local_pool));
+
+  /* write the page table (actually, the sizes of each page description) */
+  SVN_ERR(svn_io_file_write_full(index_file, encoded,
+                                 encode_uint(encoded, table_sizes->nelts),
+                                 NULL, local_pool));
+  for (i = 0; i < table_sizes->nelts; ++i)
+    {
+      apr_uint64_t value = APR_ARRAY_IDX(table_sizes, i, apr_uint64_t);
+      SVN_ERR(svn_io_file_write_full(index_file, encoded,
+                                     encode_uint(encoded, value),
+                                     NULL, local_pool));
+    }
+
+  /* append page contents */
+  SVN_ERR(svn_stream_copy3(svn_stream__from_spillbuf(buffer, local_pool),
+                           svn_stream_from_aprfile2(index_file, TRUE,
+                                                    local_pool),
+                           NULL, NULL, local_pool));
+
+  svn_pool_destroy(local_pool);
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+get_p2l_header(p2l_index_header_t **header,
+               svn_fs_t *fs,
+               svn_revnum_t revision,
+               apr_pool_t *pool)
+{
+  apr_uint64_t value;
+  apr_size_t i;
+  apr_off_t offset;
+  p2l_index_header_t *result = apr_pcalloc(pool, sizeof(*result));
+
+  apr_file_t *file = NULL;
+  SVN_ERR(svn_io_file_open(&file, path_p2l_index(fs, revision, pool),
+                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
+
+  SVN_ERR(read_number(&value, file, pool));
+  result->first_revision = (svn_revnum_t)value;
+  SVN_ERR(read_number(&value, file, pool));
+  result->page_count = (apr_size_t)value;
+  result->offsets
+    = apr_pcalloc(pool, (result->page_count + 1) * sizeof(*result->offsets));
+
+  result->offsets[0] = 0;
+  for (i = 0; i < result->page_count; ++i)
+    {
+      SVN_ERR(read_number(&value, file, pool));
+      result->offsets[i+1] = result->offsets[i] + (apr_off_t)value;
+    }
+
+  offset = 0;
+  SVN_ERR(svn_io_file_seek(file, SEEK_CUR, &offset, pool));
+  for (i = 0; i < result->page_count; ++i)
+    result->offsets[i] += offset;
+
+  SVN_ERR(svn_io_file_close(file, pool));
+  *header = result;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+read_entry(apr_file_t *file,
+           apr_off_t *item_offset,
+           apr_array_header_t *result,
+           apr_pool_t *pool)
+{
+  apr_uint64_t value;
+
+  svn_fs_fs__p2l_entry_t entry;
+
+  entry.offset = *item_offset;
+  SVN_ERR(read_number(&value, file, pool));
+  entry.size = (apr_off_t)value;
+  SVN_ERR(read_number(&value, file, pool));
+  entry.type = (int)value;
+  SVN_ERR(read_number(&value, file, pool));
+  entry.revision = (svn_revnum_t)value;
+  SVN_ERR(read_number(&value, file, pool));
+  entry.item_index = value;
+
+  APR_ARRAY_PUSH(result, svn_fs_fs__p2l_entry_t) = entry;
+  *item_offset += entry.size;
+
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+get_p2l_page(apr_array_header_t **entries,
+             svn_fs_t *fs,
+             svn_revnum_t start_revision,
+             apr_off_t start_offset,
+             apr_off_t next_offset,
+             apr_off_t page_start,
+             apr_pool_t *pool)
+{
+  apr_uint64_t value;
+  apr_array_header_t *result
+    = apr_array_make(pool, 16, sizeof(svn_fs_fs__p2l_entry_t));
+  apr_off_t item_offset;
+  apr_uint64_t page_size = 0x10000;
+  apr_off_t offset;
+
+  apr_file_t *file = NULL;
+  SVN_ERR(svn_io_file_open(&file, path_p2l_index(fs, start_revision, pool),
+                           APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool));
+  SVN_ERR(svn_io_file_seek(file, SEEK_SET, &start_offset, pool));
+
+  SVN_ERR(read_number(&value, file, pool));
+  item_offset = (apr_off_t)value;
+
+  do
+    {
+      SVN_ERR(read_entry(file, &item_offset, result, pool));
+      SVN_ERR(svn_io_file_seek(file, SEEK_CUR, &offset, pool));
+    }
+  while (offset < next_offset);
+
+  if (item_offset < page_start + page_size)
+    {
+      SVN_ERR(read_number(&value, file, pool));
+      SVN_ERR(read_entry(file, &item_offset, result, pool));
+    }
+
+  SVN_ERR(svn_io_file_close(file, pool));
+  *entries = result;
+
+  return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_fs_fs__p2l_index_lookup(apr_array_header_t **entries,
+                            svn_fs_t *fs,
+                            svn_revnum_t revision,
+                            apr_off_t offset,
+                            apr_pool_t *pool)
+{
+  p2l_index_header_t *header = NULL;
+  apr_uint64_t page_size = 0x10000;
+  apr_size_t page_no = offset / page_size;
+
+  SVN_ERR(get_p2l_header(&header, fs, revision, pool));
+  if (header->page_count <= page_no)
+    return svn_error_createf(SVN_ERR_FS_ITEM_INDEX_OVERFLOW , NULL,
+                             _("Offset %" APR_OFF_T_FMT
+                               " too large in revision %ld"),
+                             offset, revision);
+
+  SVN_ERR(get_p2l_page(entries, fs, header->first_revision,
+                       header->offsets[page_no],
+                       header->offsets[page_no + 1],
+                       (apr_off_t)(page_no * page_size), pool));
+
+  return SVN_NO_ERROR;
+}
+

Added: subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h
URL: 
http://svn.apache.org/viewvc/subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h?rev=1430676&view=auto
==============================================================================
--- subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h (added)
+++ subversion/branches/fsfs-format7/subversion/libsvn_fs_fs/index.h Wed Jan  9 
04:16:12 2013
@@ -0,0 +1,87 @@
+/* index.h : interface to FSFS indexing functionality
+ *
+ * ====================================================================
+ *    Licensed to the Apache Software Foundation (ASF) under one
+ *    or more contributor license agreements.  See the NOTICE file
+ *    distributed with this work for additional information
+ *    regarding copyright ownership.  The ASF licenses this file
+ *    to you under the Apache License, Version 2.0 (the
+ *    "License"); you may not use this file except in compliance
+ *    with the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing,
+ *    software distributed under the License is distributed on an
+ *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ *    KIND, either express or implied.  See the License for the
+ *    specific language governing permissions and limitations
+ *    under the License.
+ * ====================================================================
+ */
+
+#ifndef SVN_LIBSVN_FS__INDEX_H
+#define SVN_LIBSVN_FS__INDEX_H
+
+#include "fs.h"
+
+svn_error_t *
+svn_fs_fs__l2p_proto_index_open(apr_file_t **proto_index,
+                                const char *file_name,
+                                apr_pool_t *pool);
+
+svn_error_t *
+svn_fs_fs__l2p_proto_index_add_revision(apr_file_t *proto_index,
+                                        apr_pool_t *pool);
+
+svn_error_t *
+svn_fs_fs__l2p_proto_index_add_offset(apr_file_t *proto_index,
+                                      apr_off_t offset,
+                                      apr_pool_t *pool);
+
+svn_error_t *
+svn_fs_fs__l2p_index_create(apr_file_t *proto_index,
+                            svn_fs_t *fs,
+                            svn_revnum_t revision,
+                            apr_pool_t *pool);
+
+svn_error_t *
+svn_fs_fs__l2p_index_lookup(apr_off_t *offset,
+                            svn_fs_t *fs,
+                            svn_revnum_t revision,
+                            apr_uint64_t item_index,
+                            apr_pool_t *pool);
+
+typedef struct svn_fs_fs__p2l_entry_t
+{
+  apr_off_t offset;
+  apr_off_t size;
+  unsigned type;
+  svn_revnum_t revision;
+  apr_uint64_t item_index;
+} svn_fs_fs__p2l_entry_t;
+
+svn_error_t *
+svn_fs_fs__p2l_proto_index_open(apr_file_t **proto_index,
+                                const char *file_name,
+                                apr_pool_t *pool);
+
+svn_error_t *
+svn_fs_fs__p2l_proto_index_add_entry(apr_file_t *proto_index,
+                                     svn_fs_fs__p2l_entry_t *entry,
+                                     apr_pool_t *pool);
+
+svn_error_t *
+svn_fs_fs__p2l_index_create(apr_file_t *proto_index,
+                            svn_fs_t *fs,
+                            svn_revnum_t revision,
+                            apr_pool_t *pool);
+
+svn_error_t *
+svn_fs_fs__p2l_index_lookup(apr_array_header_t **entries,
+                            svn_fs_t *fs,
+                            svn_revnum_t revision,
+                            apr_off_t offset,
+                            apr_pool_t *pool);
+
+#endif


Reply via email to