HAMMER Utilities: Cleanup.
authorMatthew Dillon <dillon@dragonflybsd.org>
Mon, 12 May 2008 05:13:48 +0000 (05:13 +0000)
committerMatthew Dillon <dillon@dragonflybsd.org>
Mon, 12 May 2008 05:13:48 +0000 (05:13 +0000)
* Finish cleaning up the pruning and reblocking code.

* Add reblocking commands to reblock B-Tree, records, and data separately.

sbin/hammer/cmd_prune.c
sbin/hammer/cmd_reblock.c
sbin/hammer/hammer.8
sbin/hammer/hammer.c
sbin/hammer/hammer.h
sbin/hammer/hammer_util.h
sbin/hammer/ondisk.c

index 9b8fea4..996ce43 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sbin/hammer/Attic/cmd_prune.c,v 1.9 2008/05/11 20:44:44 dillon Exp $
+ * $DragonFly: src/sbin/hammer/Attic/cmd_prune.c,v 1.10 2008/05/12 05:13:47 dillon Exp $
  */
 
 #include "hammer.h"
@@ -73,8 +73,6 @@ hammer_cmd_prune(char **av, int ac)
        prune.beg_obj_id = HAMMER_MIN_OBJID;
        prune.end_obj_id = hammer_get_cycle(HAMMER_MAX_OBJID);
 
-       prune.cur_obj_id = prune.end_obj_id;    /* remove me */
-       prune.cur_key = HAMMER_MAX_KEY;         /* remove me */
        prune.stat_oldest_tid = HAMMER_MAX_TID;
 
        if (ac == 0)
index 2ff03ba..b6d392f 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sbin/hammer/cmd_reblock.c,v 1.4 2008/05/11 20:44:44 dillon Exp $
+ * $DragonFly: src/sbin/hammer/cmd_reblock.c,v 1.5 2008/05/12 05:13:47 dillon Exp $
  */
 
 #include "hammer.h"
@@ -42,7 +42,7 @@ static void reblock_usage(int exit_code);
  * reblock <filesystem> [compaction_precentage] (default 90%)
  */
 void
-hammer_cmd_reblock(char **av, int ac)
+hammer_cmd_reblock(char **av, int ac, int flags)
 {
        struct hammer_ioc_reblock reblock;
        const char *filesystem;
@@ -52,6 +52,7 @@ hammer_cmd_reblock(char **av, int ac)
        bzero(&reblock, sizeof(reblock));
        reblock.beg_obj_id = hammer_get_cycle(HAMMER_MIN_OBJID);
        reblock.end_obj_id = HAMMER_MAX_OBJID;
+       reblock.head.flags = flags & HAMMER_IOC_DO_FLAGS;
 
        if (ac == 0)
                reblock_usage(1);
@@ -63,10 +64,11 @@ hammer_cmd_reblock(char **av, int ac)
                if (perc < 0 || perc > 100)
                        reblock_usage(1);
        }
-       reblock.free_level = perc * (HAMMER_LARGEBLOCK_SIZE / 100);
+       reblock.free_level = (int)((int64_t)perc *
+                                  HAMMER_LARGEBLOCK_SIZE / 100);
        reblock.free_level = HAMMER_LARGEBLOCK_SIZE - reblock.free_level;
-       if (reblock.free_level < 128)
-               reblock.free_level = 128;
+       if (reblock.free_level < 0)
+               reblock.free_level = 0;
        printf("reblock free level %d\n", reblock.free_level);
 
        fd = open(filesystem, O_RDONLY);
index d7db793..53b11cb 100644 (file)
@@ -30,7 +30,7 @@
 .\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\" 
-.\" $DragonFly: src/sbin/hammer/hammer.8,v 1.14 2008/05/11 20:44:44 dillon Exp $
+.\" $DragonFly: src/sbin/hammer/hammer.8,v 1.15 2008/05/12 05:13:47 dillon Exp $
 .Dd December 31, 2007
 .Dt HAMMER 8
 .Os
@@ -72,8 +72,8 @@ When pruning a filesystem you can instruct HAMMER to create softlinks
 to available snapshots.
 .It Fl t Ar timeout
 When pruning and reblocking you can tell the utility to stop after a
-certain period of time.
-This option is typically used to limit the time spent reblocking.
+certain period of time.  This option is used along with the cycle file
+option to prune or reblock a portion of the filesystem incrementally.
 .It Fl v
 Increase verboseness.  May be specified multiple times.
 .It Fl x
@@ -112,6 +112,8 @@ if you wish to specify the time by some other means.
 Same as the
 .Ar stamp
 command but generates a 64 bit timestamp.
+.It Ar date
+Output a date equivalent given a transaction id or time stamp.
 .It Ar history Ar path
 Show the modification history for a HAMMER file's inode and data.
 .It Ar show Op vol_no[:clu_no]
@@ -172,6 +174,28 @@ from the filesystem.  The long keyword is designed to prevent accidental use.
 This option is not recommended.
 .Pp
 Example: "hammer prune /mnt from 1h to 1d every 30m"
+.Pp
+Note that pruning a filesystem does not necessarily immediately free space,
+though typically some space will be freed if a large number of records are
+pruned out.  The filesystem must be reblocked to completely recover all
+available space.
+.It Ar reblock Ar filesystem Op Ar fill_percentage
+.It Ar reblock-btree Ar filesystem Op Ar fill_percentage
+.It Ar reblock-data Ar filesystem Op Ar fill_percentage
+.It Ar reblock-recs Ar filesystem Op Ar fill_percentage
+Attempt to free space for reuse by reblocking a live HAMMER filesystem.
+Big blocks cannot be reused until they are completely free.  Scan the
+filesystem and move B-Tree nodes, records, and data from not-quite-full
+big blocks to new big blocks in an attempt to free up the not-quite-full
+big blocks.
+.Pp
+If unspecified a fill percentage of 90% is used.  B-Tree nodes, data,
+and records can be reblocked together or by separate invocations.
+.Pp
+A HAMMER filesystem can be defragmented by specifying a fill percentage
+of 100%.  Since this can potentially rewrite the entire contents of the
+disk it is best to do it incrementally from a cron job with a timeout.
+The filesystem would thus be defragmented over long period of time.
 .El
 .Sh EXAMPLES
 .Sh DIAGNOSTICS
index 732370b..1ccb6b7 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sbin/hammer/hammer.c,v 1.16 2008/05/11 20:44:44 dillon Exp $
+ * $DragonFly: src/sbin/hammer/hammer.c,v 1.17 2008/05/12 05:13:48 dillon Exp $
  */
 
 #include "hammer.h"
@@ -60,11 +60,14 @@ main(int ac, char **av)
        u_int32_t status;
        char *blkdevs = NULL;
 
-       while ((ch = getopt(ac, av, "c:hf:rs:t:vx")) != -1) {
+       while ((ch = getopt(ac, av, "c:dhf:rs:t:vx")) != -1) {
                switch(ch) {
                case 'c':
                        CyclePath = optarg;
                        break;
+               case 'd':
+                       ++DebugOpt;
+                       break;
                case 'h':
                        usage(0);
                        /* not reached */
@@ -131,6 +134,18 @@ main(int ac, char **av)
                printf("0x%016llx\n", tid);
                exit(0);
        }
+       if (strcmp(av[0], "date") == 0) {
+               time_t t;
+
+               if (av[1] == NULL)
+                       usage(1);
+               tid = strtoull(av[1], NULL, 16);
+               if (tid >= 0x100000000LLU)
+                       tid /= 1000000000LLU;
+               t = (time_t)tid;
+               printf("%s", ctime(&t));
+               exit(0);
+       }
        if (strcmp(av[0], "namekey") == 0) {
                int64_t key;
 
@@ -162,8 +177,17 @@ main(int ac, char **av)
                hammer_cmd_history(av[0] + 7, av + 1, ac - 1);
                exit(0);
        }
-       if (strcmp(av[0], "reblock") == 0) {
-               hammer_cmd_reblock(av + 1, ac - 1);
+       if (strncmp(av[0], "reblock", 7) == 0) {
+               if (strcmp(av[0], "reblock") == 0)
+                       hammer_cmd_reblock(av + 1, ac - 1, -1);
+               else if (strcmp(av[0], "reblock-btree") == 0)
+                       hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_BTREE);
+               else if (strcmp(av[0], "reblock-data") == 0)
+                       hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_DATA);
+               else if (strcmp(av[0], "reblock-recs") == 0)
+                       hammer_cmd_reblock(av + 1, ac - 1, HAMMER_IOC_DO_RECS);
+               else
+                       usage(1);
                exit(0);
        }
 
index 4f44800..000d1a2 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sbin/hammer/hammer.h,v 1.10 2008/05/11 20:44:44 dillon Exp $
+ * $DragonFly: src/sbin/hammer/hammer.h,v 1.11 2008/05/12 05:13:48 dillon Exp $
  */
 
 #include <sys/types.h>
@@ -66,7 +66,7 @@ void hammer_cmd_show(hammer_tid_t node_offset, int depth,
 void hammer_cmd_prune(char **av, int ac);
 void hammer_cmd_history(const char *offset_str, char **av, int ac);
 void hammer_cmd_blockmap(void);
-void hammer_cmd_reblock(char **av, int ac);
+void hammer_cmd_reblock(char **av, int ac, int flags);
 
 int64_t hammer_get_cycle(int64_t default_obj_id);
 void hammer_set_cycle(int64_t obj_id);
index e16e07d..ecab2f9 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sbin/hammer/hammer_util.h,v 1.13 2008/04/27 00:43:55 dillon Exp $
+ * $DragonFly: src/sbin/hammer/hammer_util.h,v 1.14 2008/05/12 05:13:48 dillon Exp $
  */
 
 #include <sys/types.h>
@@ -61,6 +61,9 @@ struct cache_info {
        int delete;     /* delete flag - delete on last ref */
 };
 
+#define HAMMER_BUFLISTS                64
+#define HAMMER_BUFLISTMASK     (HAMMER_BUFLISTS - 1)
+
 /*
  * These structures are used by newfs_hammer to track the filesystem
  * buffers it constructs while building the filesystem.  No attempt
@@ -81,7 +84,7 @@ struct volume_info {
 
        struct hammer_volume_ondisk *ondisk;
 
-       TAILQ_HEAD(, buffer_info) buffer_list;
+       TAILQ_HEAD(, buffer_info) buffer_lists[HAMMER_BUFLISTS];
 };
 
 struct buffer_info {
@@ -98,6 +101,7 @@ extern uuid_t Hammer_FSId;
 extern int64_t BootAreaSize;
 extern int64_t MemAreaSize;
 extern int64_t UndoBufferSize;
+extern int DebugOpt;
 extern int NumVolumes;
 extern int RootVolNo;
 extern struct volume_list VolList;
index 5c4ac94..0f378f6 100644 (file)
@@ -31,7 +31,7 @@
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  * 
- * $DragonFly: src/sbin/hammer/ondisk.c,v 1.17 2008/05/06 00:15:33 dillon Exp $
+ * $DragonFly: src/sbin/hammer/ondisk.c,v 1.18 2008/05/12 05:13:48 dillon Exp $
  */
 
 #include <sys/types.h>
@@ -60,6 +60,7 @@ static void readhammerbuf(struct volume_info *vol, void *data,
 static void writehammerbuf(struct volume_info *vol, const void *data,
                        int64_t offset);
 
+int DebugOpt;
 
 uuid_t Hammer_FSType;
 uuid_t Hammer_FSId;
@@ -71,6 +72,16 @@ int     NumVolumes;
 int    RootVolNo = -1;
 struct volume_list VolList = TAILQ_HEAD_INITIALIZER(VolList);
 
+static __inline
+int
+buffer_hash(hammer_off_t buf_offset)
+{
+       int hi;
+
+       hi = (int)(buf_offset / HAMMER_BUFSIZE) & HAMMER_BUFLISTMASK;
+       return(hi);
+}
+
 /*
  * Lookup the requested information structure and related on-disk buffer.
  * Missing structures are created.
@@ -81,14 +92,15 @@ setup_volume(int32_t vol_no, const char *filename, int isnew, int oflags)
        struct volume_info *vol;
        struct volume_info *scan;
        struct hammer_volume_ondisk *ondisk;
-       int n;
+       int i, n;
 
        /*
         * Allocate the volume structure
         */
        vol = malloc(sizeof(*vol));
        bzero(vol, sizeof(*vol));
-       TAILQ_INIT(&vol->buffer_list);
+       for (i = 0; i < HAMMER_BUFLISTS; ++i)
+               TAILQ_INIT(&vol->buffer_lists[i]);
        vol->name = strdup(filename);
        vol->fd = open(filename, oflags);
        if (vol->fd < 0) {
@@ -181,9 +193,10 @@ get_buffer(hammer_off_t buf_offset, int isnew)
        void *ondisk;
        struct buffer_info *buf;
        struct volume_info *volume;
+       hammer_off_t orig_offset = buf_offset;
        int vol_no;
        int zone;
-       int n;
+       int hi, n;
 
        zone = HAMMER_ZONE_DECODE(buf_offset);
        if (zone > HAMMER_ZONE_RAW_BUFFER_INDEX) {
@@ -194,18 +207,24 @@ get_buffer(hammer_off_t buf_offset, int isnew)
        volume = get_volume(vol_no);
        buf_offset &= ~HAMMER_BUFMASK64;
 
-       TAILQ_FOREACH(buf, &volume->buffer_list, entry) {
+       hi = buffer_hash(buf_offset);
+
+       TAILQ_FOREACH(buf, &volume->buffer_lists[hi], entry) {
                if (buf->buf_offset == buf_offset)
                        break;
        }
        if (buf == NULL) {
                buf = malloc(sizeof(*buf));
                bzero(buf, sizeof(*buf));
+               if (DebugOpt) {
+                       fprintf(stderr, "get_buffer %016llx %016llx\n",
+                               orig_offset, buf_offset);
+               }
                buf->buf_offset = buf_offset;
                buf->buf_disk_offset = volume->ondisk->vol_buf_beg +
                                        (buf_offset & HAMMER_OFF_SHORT_MASK);
                buf->volume = volume;
-               TAILQ_INSERT_TAIL(&volume->buffer_list, buf, entry);
+               TAILQ_INSERT_TAIL(&volume->buffer_lists[hi], buf, entry);
                ++volume->cache.refs;
                buf->cache.u.buffer = buf;
                hammer_cache_add(&buf->cache, ISBUFFER);
@@ -236,14 +255,16 @@ void
 rel_buffer(struct buffer_info *buffer)
 {
        struct volume_info *volume;
+       int hi;
 
        assert(buffer->cache.refs > 0);
        if (--buffer->cache.refs == 0) {
                if (buffer->cache.delete) {
+                       hi = buffer_hash(buffer->buf_offset);
                        volume = buffer->volume;
                        if (buffer->cache.modified)
                                flush_buffer(buffer);
-                       TAILQ_REMOVE(&volume->buffer_list, buffer, entry);
+                       TAILQ_REMOVE(&volume->buffer_lists[hi], buffer, entry);
                        hammer_cache_del(&buffer->cache);
                        free(buffer->ondisk);
                        free(buffer);
@@ -768,9 +789,12 @@ void
 flush_volume(struct volume_info *volume)
 {
        struct buffer_info *buffer;
+       int i;
 
-       TAILQ_FOREACH(buffer, &volume->buffer_list, entry)
-               flush_buffer(buffer);
+       for (i = 0; i < HAMMER_BUFLISTS; ++i) {
+               TAILQ_FOREACH(buffer, &volume->buffer_lists[i], entry)
+                       flush_buffer(buffer);
+       }
        writehammerbuf(volume, volume->ondisk, 0);
        volume->cache.modified = 0;
 }