HAMMER UTILITY - reorg cache, add -C, document blockmap and show command.
authorMatthew Dillon <dillon@apollo.backplane.com>
Sat, 20 Jun 2009 17:31:39 +0000 (10:31 -0700)
committerMatthew Dillon <dillon@apollo.backplane.com>
Sat, 20 Jun 2009 17:31:39 +0000 (10:31 -0700)
* Reorganize the way the local block cache works (in the utility, not the
  filesystem).  Add the -C option to specify cache size and read-ahead.

* Document the blockmap command and enhance the documentation for the show
  command.

sbin/hammer/cache.c
sbin/hammer/hammer.8
sbin/hammer/hammer.c
sbin/hammer/hammer_util.h
sbin/hammer/ondisk.c

index 1e9892e..ac7d41a 100644 (file)
@@ -59,7 +59,7 @@ hammer_cache_set(int bytes)
 void
 hammer_cache_add(struct cache_info *cache, enum cache_type type)
 {
-       TAILQ_INSERT_TAIL(&CacheList, cache, entry);
+       TAILQ_INSERT_HEAD(&CacheList, cache, entry);
        cache->type = type;
        CacheUse += HAMMER_BUFSIZE;
        ++NCache;
@@ -73,6 +73,13 @@ hammer_cache_del(struct cache_info *cache)
        --NCache;
 }
 
+void
+hammer_cache_used(struct cache_info *cache)
+{
+       TAILQ_REMOVE(&CacheList, cache, entry);
+       TAILQ_INSERT_TAIL(&CacheList, cache, entry);
+}
+
 void
 hammer_cache_flush(void)
 {
index ec3ea86..6da7e23 100644 (file)
@@ -47,7 +47,7 @@
 .\" .Op Fl s Ar linkpath
 .Op Fl i Ar delay
 .Op Fl t Ar seconds
-.Op Fl C Ar cachesize
+.Op Fl C Ar cachesize[:readahead]
 .Ar command
 .Op Ar argument ...
 .Sh DESCRIPTION
@@ -124,11 +124,13 @@ Increase verboseness.
 May be specified multiple times.
 .It Fl y
 Force "yes" for any interactive question.
-.It Fl C Ar cachesize
+.It Fl C Ar cachesize[:readahead]
 Set the memory cache size for any raw I/O.  The default is 16m.
 A suffix of 'k' for kilobytes and 'm' for megabytes is allowed,
 else the cache size is specified in bytes.
 .Pp
+The read-behind/read-ahead defaults to 4 hammer blocks.
+.Pp
 This option is typically only used with diagnostic commands
 as kernel-supported commands will use the kernel's buffer cache.
 .El
@@ -172,9 +174,52 @@ The default interval is one second.
 Show the modification history for
 .Nm HAMMER
 file's inode and data.
+.\" ==== blockmap ====
+.It Ar blockmap
+Dump the blockmap for the filesystem.  The HAMMER blockmap is two-layer
+blockmap representing the maximum possible filesystem size of 1 Exabyte.
+Needless to say the second layer is only present for blocks which exist.
+HAMMER's blockmap represents 8-Megabyte blocks.  Each block has an append
+point, a free byte count, and a typed zone id which allows content to be
+reverse engineered to some degree.
+.Pp
+In HAMMER allocations essentially appended to a selected big-block using
+the append offset and deducted from the free byte count.  When space is
+freed the free byte count is adjusted but HAMMER does not track holes in
+big-blocks for reallocation.  A big-block must be completely freed, either
+through normal filesystem operations or through reblocking, before
+it can be reused.
+.Pp
+Data blocks can be shared by deducting the space used from the free byte
+count for each shared references, though HAMMER does not yet make use of
+this feature.  This means the free byte count can legally go negative.
+.Pp
+This command needs the
+.Fl f
+flag.
 .\" ==== show ====
 .It Ar show
-Dump the B-tree.
+Dump the B-tree.  By default this command will validate all B-Tree
+linkages and CRCs, including data CRCs, and will report the most verbose
+information it can dig up.
+Any errors will show up with a 'B' in column 1 along with various
+other error flags.
+.Pp
+If you use
+.Fl q
+the command will report less information about the inode contents.
+.Pp
+If you use
+.Fl qq
+the command will not report the content of the inode or other typed
+data at all.
+.Pp
+If you use
+.Fl qqq
+the command will not report volume header information, big-block fill
+ratios, mirror TIDs, or report or check data CRCs.  B-Tree CRCs and
+linkages are still checked.
+.Pp
 This command needs the
 .Fl f
 flag.
index 8b7e1d7..8c2e609 100644 (file)
@@ -142,15 +142,27 @@ main(int ac, char **av)
                        case 'k':
                        case 'K':
                                cacheSize *= 1024;
+                               ++ptr;
                                break;
                        case '\0':
+                       case ':':
                                /* bytes if no suffix */
                                break;
                        default:
                                usage(1);
                        }
+                       if (*ptr == ':') {
+                               UseReadAhead = strtol(ptr + 1, NULL, 0);
+                               UseReadBehind = -UseReadAhead;
+                       }
                        if (cacheSize < 1024 * 1024)
                                cacheSize = 1024 * 1024;
+                       if (UseReadAhead < 0)
+                               usage(1);
+                       if (UseReadAhead * HAMMER_BUFSIZE / cacheSize / 16) {
+                               UseReadAhead = cacheSize / 16 / HAMMER_BUFSIZE;
+                               UseReadBehind = -UseReadAhead;
+                       }
                        hammer_cache_set(cacheSize);
                        break;
                default:
index b4c767b..dd86a40 100644 (file)
@@ -91,11 +91,15 @@ struct buffer_info {
        struct cache_info       cache;
        TAILQ_ENTRY(buffer_info) entry;
        hammer_off_t            buf_offset;     /* full hammer offset spec */
-       int64_t                 buf_disk_offset;/* relative to blkdev */
+       int64_t                 raw_offset;     /* physical offset */
+       int                     flags;          /* origination flags */
+       int                     use_count;      /* read count */
        struct volume_info      *volume;
        void                    *ondisk;
 };
 
+#define HAMMER_BUFINFO_READAHEAD       0x0001
+
 extern uuid_t Hammer_FSType;
 extern uuid_t Hammer_FSId;
 extern int64_t BootAreaSize;
@@ -105,6 +109,8 @@ extern int DebugOpt;
 extern int NumVolumes;
 extern int RootVolNo;
 extern struct volume_list VolList;
+extern int UseReadBehind;
+extern int UseReadAhead;
 
 uint32_t crc32(const void *buf, size_t size);
 uint32_t crc32_ext(const void *buf, size_t size, uint32_t ocrc);
@@ -146,6 +152,7 @@ void flush_buffer(struct buffer_info *buf);
 void hammer_cache_set(int bytes);
 void hammer_cache_add(struct cache_info *cache, enum cache_type type);
 void hammer_cache_del(struct cache_info *cache);
+void hammer_cache_used(struct cache_info *cache);
 void hammer_cache_flush(void);
 
 void panic(const char *ctl, ...);
index 7702b1c..9e71bc1 100644 (file)
@@ -49,6 +49,7 @@
 static void *alloc_blockmap(int zone, int bytes, hammer_off_t *result_offp,
                        struct buffer_info **bufferp);
 static hammer_off_t alloc_bigblock(struct volume_info *volume, int zone);
+static void get_buffer_readahead(struct buffer_info *base);
 #if 0
 static void init_fifo_head(hammer_fifo_head_t head, u_int16_t hdr_type);
 static hammer_off_t hammer_alloc_fifo(int32_t base_bytes, int32_t ext_bytes,
@@ -69,6 +70,8 @@ int64_t UndoBufferSize;
 int     UsingSuperClusters;
 int     NumVolumes;
 int    RootVolNo = -1;
+int    UseReadBehind = -4;
+int    UseReadAhead = 4;
 struct volume_list VolList = TAILQ_HEAD_INITIALIZER(VolList);
 
 static __inline
@@ -112,7 +115,7 @@ setup_volume(int32_t vol_no, const char *filename, int isnew, int oflags)
         * Read or initialize the volume header
         */
        vol->ondisk = ondisk = malloc(HAMMER_BUFSIZE);
-       if (isnew) {
+       if (isnew > 0) {
                bzero(ondisk, HAMMER_BUFSIZE);
        } else {
                n = pread(vol->fd, ondisk, HAMMER_BUFSIZE, 0);
@@ -142,7 +145,7 @@ setup_volume(int32_t vol_no, const char *filename, int isnew, int oflags)
        }
        vol->vol_no = vol_no;
 
-       if (isnew) {
+       if (isnew > 0) {
                /*init_fifo_head(&ondisk->head, HAMMER_HEAD_TYPE_VOL);*/
                vol->cache.modified = 1;
         }
@@ -196,6 +199,7 @@ get_buffer(hammer_off_t buf_offset, int isnew)
        int vol_no;
        int zone;
        int hi, n;
+       int dora = 0;
 
        zone = HAMMER_ZONE_DECODE(buf_offset);
        if (zone > HAMMER_ZONE_RAW_BUFFER_INDEX) {
@@ -217,39 +221,90 @@ get_buffer(hammer_off_t buf_offset, int isnew)
                bzero(buf, sizeof(*buf));
                if (DebugOpt) {
                        fprintf(stderr, "get_buffer %016llx %016llx\n",
-                               orig_offset, buf_offset);
+                               (long long)orig_offset, (long long)buf_offset);
                }
                buf->buf_offset = buf_offset;
-               buf->buf_disk_offset = volume->ondisk->vol_buf_beg +
-                                       (buf_offset & HAMMER_OFF_SHORT_MASK);
+               buf->raw_offset = volume->ondisk->vol_buf_beg +
+                                 (buf_offset & HAMMER_OFF_SHORT_MASK);
                buf->volume = volume;
                TAILQ_INSERT_TAIL(&volume->buffer_lists[hi], buf, entry);
                ++volume->cache.refs;
                buf->cache.u.buffer = buf;
                hammer_cache_add(&buf->cache, ISBUFFER);
+               dora = (isnew == 0);
+               if (isnew < 0)
+                       buf->flags |= HAMMER_BUFINFO_READAHEAD;
+       } else {
+               if (isnew >= 0) {
+                       buf->flags &= ~HAMMER_BUFINFO_READAHEAD;
+                       hammer_cache_used(&buf->cache);
+               }
+               ++buf->use_count;
        }
        ++buf->cache.refs;
        hammer_cache_flush();
        if ((ondisk = buf->ondisk) == NULL) {
                buf->ondisk = ondisk = malloc(HAMMER_BUFSIZE);
-               if (isnew == 0) {
+               if (isnew <= 0) {
                        n = pread(volume->fd, ondisk, HAMMER_BUFSIZE,
-                                 buf->buf_disk_offset);
+                                 buf->raw_offset);
                        if (n != HAMMER_BUFSIZE) {
                                err(1, "get_buffer: %s:%016llx Read failed at "
-                                      "offset %lld",
-                                   volume->name, buf->buf_offset,
-                                   buf->buf_disk_offset);
+                                      "offset %016llx",
+                                   volume->name,
+                                   (long long)buf->buf_offset,
+                                   (long long)buf->raw_offset);
                        }
                }
        }
-       if (isnew) {
+       if (isnew > 0) {
                bzero(ondisk, HAMMER_BUFSIZE);
                buf->cache.modified = 1;
        }
+       if (dora)
+               get_buffer_readahead(buf);
        return(buf);
 }
 
+static void
+get_buffer_readahead(struct buffer_info *base)
+{
+       struct buffer_info *buf;
+       struct volume_info *vol;
+       hammer_off_t buf_offset;
+       int64_t raw_offset;
+       int ri = UseReadBehind;
+       int re = UseReadAhead;
+       int hi;
+
+       raw_offset = base->raw_offset + ri * HAMMER_BUFSIZE;
+       vol = base->volume;
+
+       while (ri < re) {
+               if (raw_offset >= vol->ondisk->vol_buf_end)
+                       break;
+               if (raw_offset < vol->ondisk->vol_buf_beg) {
+                       ++ri;
+                       raw_offset += HAMMER_BUFSIZE;
+                       continue;
+               }
+               buf_offset = HAMMER_VOL_ENCODE(vol->vol_no) |
+                            HAMMER_ZONE_RAW_BUFFER |
+                            (raw_offset - vol->ondisk->vol_buf_beg);
+               hi = buffer_hash(raw_offset);
+               TAILQ_FOREACH(buf, &vol->buffer_lists[hi], entry) {
+                       if (buf->raw_offset == raw_offset)
+                               break;
+               }
+               if (buf == NULL) {
+                       buf = get_buffer(buf_offset, -1);
+                       rel_buffer(buf);
+               }
+               ++ri;
+               raw_offset += HAMMER_BUFSIZE;
+       }
+}
+
 void
 rel_buffer(struct buffer_info *buffer)
 {
@@ -279,7 +334,7 @@ get_buffer_data(hammer_off_t buf_offset, struct buffer_info **bufferp,
        struct buffer_info *buffer;
 
        if ((buffer = *bufferp) != NULL) {
-               if (isnew || 
+               if (isnew > 0 ||
                    ((buffer->buf_offset ^ buf_offset) & ~HAMMER_BUFMASK64)) {
                        rel_buffer(buffer);
                        buffer = *bufferp = NULL;
@@ -768,7 +823,7 @@ flush_volume(struct volume_info *volume)
 void
 flush_buffer(struct buffer_info *buffer)
 {
-       writehammerbuf(buffer->volume, buffer->ondisk, buffer->buf_disk_offset);
+       writehammerbuf(buffer->volume, buffer->ondisk, buffer->raw_offset);
        buffer->cache.modified = 0;
 }