linux-btrfs.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support
@ 2010-10-06 21:00 David Nicol
  2010-10-07  6:10 ` Goffredo Baroncelli
  0 siblings, 1 reply; 6+ messages in thread
From: David Nicol @ 2010-10-06 21:00 UTC (permalink / raw)
  To: BTRFS MAILING LIST

[-- Attachment #1: Type: text/plain, Size: 391 bytes --]

the ISO 8601 duration support is very loose, but I believe it is
accurate for valid
input. Without any non-numeric designators, the timeout is interpreted
as seconds,
so
    btrfs fi reclaim 10.3321 /my_btrfs_mount ||  echo timed out
will wait 10332 ms before echoing, if the pending subvolume deletions
take longer than that.

Timeout defaults to 0, and path defaults to current directory.

[-- Attachment #2: progs_patch_8601.diff --]
[-- Type: text/x-diff, Size: 12980 bytes --]

diff --git a/Makefile b/Makefile
index 525676e..7442e14 100644
--- a/Makefile
+++ b/Makefile
@@ -37,12 +37,13 @@ all: version $(progs) manpages
 version:
 	bash version.sh
 
-btrfs: $(objects) btrfs.o btrfs_cmds.o
-	gcc $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o \
+btrfs: $(objects) btrfs.o btrfs_cmds.o iso8601toms.o
+	gcc $(CFLAGS) -o btrfs btrfs.o btrfs_cmds.o iso8601toms.o \
 		$(objects) $(LDFLAGS) $(LIBS)
 
-btrfsctl: $(objects) btrfsctl.o
-	gcc $(CFLAGS) -o btrfsctl btrfsctl.o $(objects) $(LDFLAGS) $(LIBS)
+btrfsctl: $(objects) btrfsctl.o iso8601toms.o
+	gcc $(CFLAGS) -o btrfsctl btrfsctl.o iso8601toms.o \
+		$(objects) $(LDFLAGS) $(LIBS)
 
 btrfs-vol: $(objects) btrfs-vol.o
 	gcc $(CFLAGS) -o btrfs-vol btrfs-vol.o $(objects) $(LDFLAGS) $(LIBS)
diff --git a/btrfs-list.c b/btrfs-list.c
index 7741705..7b92bc0 100644
--- a/btrfs-list.c
+++ b/btrfs-list.c
@@ -16,6 +16,7 @@
  * Boston, MA 021110-1307, USA.
  */
 
+#define _GNU_SOURCE
 #ifndef __CHECKER__
 #include <sys/ioctl.h>
 #include <sys/mount.h>
@@ -34,6 +35,7 @@
 #include "transaction.h"
 #include "utils.h"
 #include "version.h"
+#include <string.h>
 
 /* we store all the roots we find in an rbtree so that we can
  * search for them later.
diff --git a/btrfs.c b/btrfs.c
index ab5e57f..3928961 100644
--- a/btrfs.c
+++ b/btrfs.c
@@ -15,6 +15,7 @@
  */
 
 
+#define _GNU_SOURCE
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -29,6 +30,7 @@ struct Command {
 	CommandFunction	func;	/* function which implements the command */
 	int	nargs;		/* if == 999, any number of arguments
 				   if >= 0, number of arguments,
+				   if > 1000, 1000 more than the _maximum_ number of arguments,
 				   if < 0, _minimum_ number of arguments */
 	char	*verb;		/* verb */
 	char	*help;		/* help lines; form the 2nd onward they are
@@ -77,6 +79,11 @@ static struct Command commands[] = {
 	  "filesystem sync", "<path>\n"
 		"Force a sync on the filesystem <path>."
 	},
+	{ do_wait4clean, 1002, /* require at most two args */
+	  "filesystem reclaim", "<path> [timeout]\n"
+		"Wait for cleanup of deleted subvolumes in the filesystem <path>.\n"
+		"Optional timeout in whole or partial seconds, or ISO8601 string.\n"
+	},
 	{ do_resize, 2,
 	  "filesystem resize", "[+/-]<newsize>[gkm]|max <filesystem>\n"
 		"Resize the file system. If 'max' is passed, the filesystem\n"
@@ -349,17 +356,26 @@ static int parse_args(int argc, char **argv,
 		return -2;
 
 	/* check the number of argument */
-	if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){
+
+	if(matchcmd->nargs > 1000 ){
+          if ( matchcmd->nargs < (1000 + *nargs_)){
+		fprintf(stderr, "ERROR: '%s' requires only %d or fewer arg(s)\n",
+			matchcmd->verb, matchcmd->nargs - 1000 );
+			return -2;
+          }
+	} else {
+
+	  if (matchcmd->nargs < 0 && matchcmd->nargs < -*nargs_ ){
 		fprintf(stderr, "ERROR: '%s' requires minimum %d arg(s)\n",
 			matchcmd->verb, -matchcmd->nargs);
 			return -2;
-	}
-	if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){
+	  }
+	  if(matchcmd->nargs >= 0 && matchcmd->nargs != *nargs_ && matchcmd->nargs != 999){
 		fprintf(stderr, "ERROR: '%s' requires %d arg(s)\n",
 			matchcmd->verb, matchcmd->nargs);
 			return -2;
-	}
-	
+	  }
+	} 
         if (prepare_args( nargs_, args_, prgname, matchcmd )){
                 fprintf(stderr, "ERROR: not enough memory\\n");
 		return -20;
diff --git a/btrfs_cmds.c b/btrfs_cmds.c
index 8031c58..855c950 100644
--- a/btrfs_cmds.c
+++ b/btrfs_cmds.c
@@ -526,6 +526,37 @@ int do_fssync(int argc, char **argv)
 	return 0;
 }
 
+#include "iso8601toms.h"
+
+int do_wait4clean(int argc, char **argv)
+{
+	int fd, res;
+        struct btrfs_ioctl_cleaner_wait_args w4c_arg;
+
+	char	*path = ".";
+        w4c_arg.ms = 0UL;
+
+        if (argc > 1) 
+	     path = argv[1];
+        if (argc > 2) 
+             w4c_arg.ms = iso8601toms(argv[2]);
+
+	fd = open_file_or_dir(path);
+	if (fd < 0) {
+		fprintf(stderr, "ERROR: can't open file or dir '%s'\n", path);
+		return 12;
+	}
+	res = ioctl(fd, BTRFS_IOC_CLEANER_WAIT, &w4c_arg);
+	close(fd);
+	if( res != 0 ){
+		fprintf(stderr, "%s:error #%i:%s\n",
+                        path, res,strerror(res));
+		return -res;
+	}
+
+	return 0;
+}
+
 int do_scan(int argc, char **argv)
 {
 	int	i, fd;
diff --git a/btrfs_cmds.h b/btrfs_cmds.h
index 7bde191..c958338 100644
--- a/btrfs_cmds.h
+++ b/btrfs_cmds.h
@@ -19,6 +19,7 @@ int do_clone(int nargs, char **argv);
 int do_delete_subvolume(int nargs, char **argv);
 int do_create_subvol(int nargs, char **argv);
 int do_fssync(int nargs, char **argv);
+int do_wait4clean(int nargs, char **argv);
 int do_defrag(int argc, char **argv);
 int do_show_filesystem(int nargs, char **argv);
 int do_add_volume(int nargs, char **args);
diff --git a/btrfsctl.c b/btrfsctl.c
index be6bf25..307ec53 100644
--- a/btrfsctl.c
+++ b/btrfsctl.c
@@ -34,6 +34,7 @@
 #include "ctree.h"
 #include "transaction.h"
 #include "utils.h"
+#include "iso8601toms.h"
 #include "version.h"
 
 #ifdef __CHECKER__
@@ -57,6 +58,7 @@ static void print_usage(void)
 	printf("\t-a: scans all devices for Btrfs filesystems\n");
 	printf("\t-c: forces a single FS sync\n");
 	printf("\t-D: delete snapshot\n");
+	printf("\t-C [timeout] [directory]: wait for snapshot space recovery\n");
 	printf("\t-m [tree id] directory: set the default mounted subvolume"
 	       " to the [tree id] or the directory\n");
 	printf("%s\n", BTRFS_BUILD_VERSION);
@@ -96,7 +98,7 @@ int main(int ac, char **av)
 	char *fname = NULL;
 	char *snap_location = NULL;
 	int snap_fd = 0;
-	int fd;
+	int fd = -999; /* silence a warning */
 	int ret;
 	struct btrfs_ioctl_vol_args args;
 	char *name = NULL;
@@ -105,6 +107,7 @@ int main(int ac, char **av)
 	int len;
 	char *fullpath;
 	u64 objectid = 0;
+        struct btrfs_ioctl_cleaner_wait_args CWargs;
 
 	if (ac == 2 && strcmp(av[1], "-a") == 0) {
 		fprintf(stderr, "Scanning for Btrfs filesystems\n");
@@ -175,6 +178,10 @@ int main(int ac, char **av)
 				fprintf(stderr, "-D size too long\n");
 				exit(1);
 			}
+		} else if (strcmp(av[i], "-C") == 0) {
+			command = BTRFS_IOC_CLEANER_WAIT;
+                        CWargs.ms = ( ac > (i+1) ? iso8601toms(av[i+1]) : 0UL );
+			name = ( ac > ( i+2 ) ? av[i + 2] : "." );
 		} else if (strcmp(av[i], "-A") == 0) {
 			if (i >= ac - 1) {
 				fprintf(stderr, "-A requires an arg\n");
@@ -221,9 +228,9 @@ int main(int ac, char **av)
 			exit(1);
 		}
 		name = fname;
-	 } else {
+	} else if (command != BTRFS_IOC_CLEANER_WAIT) {
 		fd = open_file_or_dir(fname);
-	 }
+	}
 
 	if (name)
 		strcpy(args.name, name);
@@ -236,6 +243,9 @@ int main(int ac, char **av)
 	} else if (command == BTRFS_IOC_DEFAULT_SUBVOL) {
 		printf("objectid is %llu\n", objectid);
 		ret = ioctl(fd, command, &objectid);
+	} else if (command == BTRFS_IOC_CLEANER_WAIT) {
+		fd = open_file_or_dir(name);
+		ret = ioctl(fd, command, &CWargs);
 	} else
 		ret = ioctl(fd, command, &args);
 	if (ret < 0) {
diff --git a/ioctl.h b/ioctl.h
index 776d7a9..27df596 100644
--- a/ioctl.h
+++ b/ioctl.h
@@ -169,4 +169,11 @@ struct btrfs_ioctl_space_args {
 #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, u64)
 #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
 				    struct btrfs_ioctl_space_args)
+struct btrfs_ioctl_cleaner_wait_args{
+        unsigned long ms;
+        unsigned long flags; /* for future use */
+};
+#define BTRFS_IOC_CLEANER_WAIT _IOW(BTRFS_IOCTL_MAGIC, 21, \
+				    struct btrfs_ioctl_cleaner_wait_args)
 #endif
+
diff --git a/iso8601toms.c b/iso8601toms.c
new file mode 100644
index 0000000..a1ee9bd
--- /dev/null
+++ b/iso8601toms.c
@@ -0,0 +1,109 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+/***********
+
+ the following will correctly parse valid duration strings,
+ also it will accept a lot of invalid ones. 
+
+ it does:
+
+    know all the ISO8601 letters
+
+    accept a non-integer as the last numeric component
+
+ it silently accepts:
+
+    out of order duration type letters
+
+    strings missing the leading P character
+
+    lowercase duration type letters
+
+    non-integers in any position
+
+ it warns on:
+
+    P or p appearing somewhere besides the beginning of the string
+
+    unrecognized characters
+
+
+***********/
+
+#include <stdlib.h>
+#include <stdio.h>
+
+unsigned long iso8601toms(char *P){
+    unsigned long ms;
+    double component;
+    char *ptr;
+    char *endptr;
+    short M_min = 0;
+
+    ms = 0UL;
+    ptr = P;
+    for(;;){
+       component=strtod(ptr, &endptr);
+       switch (*endptr)
+       {
+          case 'P': /* anchor */ case 'p':
+             if (ptr > P)
+	         fprintf(stderr, "ignoring non-initial P "
+                         "in ISO8601 duration string %s\n", P);
+             break;
+          case 'Y': /* years */ case 'y':
+             component *= 12;
+          BIGM:
+             /* average days in a gregorian month */
+             component *= (365.2425 / 12.0);
+             /* ms in a day */
+             component *= ( 24 * 3600 * 1000 );
+             ms += component;
+             break;
+          case 'T': /* Time (not date) anchor */ case 't':
+             M_min = 1;
+             break;
+          case 'W': /* week */ case 'w':
+             component *= 7;
+          case 'D': /* day */ case 'd':
+             component *=  24 ;
+          case 'H': /* hour */ case 'h':
+             component *= 60;
+             M_min = 1;
+          case 'M': /* month, or minute */ case 'm':
+             if (!M_min++)
+                 goto BIGM;
+             component *= 60;
+          case 'S': /* second */ case 's':
+          case '\0': /* default to second */
+             component *= 1000;
+             ms += component;
+             break;
+          
+          default:
+	     fprintf(stderr,
+                "ignoring unexpected char [%c] "
+                "in iso8601 duration string %s\n",
+                *endptr, P
+             );
+       };
+       if (!*endptr)
+          return (ms); 
+       ptr = 1+endptr;
+    };
+}
+
diff --git a/iso8601toms.h b/iso8601toms.h
new file mode 100644
index 0000000..8f7ca83
--- /dev/null
+++ b/iso8601toms.h
@@ -0,0 +1,3 @@
+
+unsigned long iso8601toms(char *P);
+
diff --git a/man/btrfs.8.in b/man/btrfs.8.in
index 26ef982..5f1155e 100644
--- a/man/btrfs.8.in
+++ b/man/btrfs.8.in
@@ -19,6 +19,8 @@ btrfs \- control a btrfs filesystem
 .PP
 \fBbtrfs\fP \fBfilesystem sync\fP\fI <path> \fP
 .PP
+\fBbtrfs\fP \fBfilesystem reclaim\fP\fI <path> [timeout] \fP
+.PP
 \fBbtrfs\fP \fBfilesystem resize\fP\fI [+/\-]<size>[gkm]|max <filesystem>\fP
 .PP
 \fBbtrfs\fP \fBdevice scan\fP\fI [<device> [<device>..]]\fP
@@ -115,6 +117,15 @@ all the block devices.
 Force a sync for the filesystem identified by \fI<path>\fR.
 .TP
 
+\fBfilesystem reclaim\fR\fI <path> [timeout] \fR
+Wait for recovery of space from deleted
+subvolumes on the filesystem containing \fI<path>\fR to complete.
+The optional timeout is in seconds, which can be fractional, or you may use
+an ISO8601 duration string, such as PT5M2.5S, which would mean five minutes,
+two and a half seconds. The P and T are optional, but without them "M" might
+get interpreted as months, which is probably not what you want.
+.TP
+
 .\"
 .\" Some wording are extracted by the resize2fs man page
 .\"
diff --git a/man/btrfsctl.8.in b/man/btrfsctl.8.in
index c2d4488..62a1db2 100644
--- a/man/btrfsctl.8.in
+++ b/man/btrfsctl.8.in
@@ -10,6 +10,7 @@ btrfsctl \- control a btrfs filesystem
 [ \fB \-A\fP\fI device\fP ]
 [ \fB \-a\fP ]
 [ \fB \-c\fP ]
+[ \fB \-C\fP\fI [timeout [directory]]\fP ]
 .SH DESCRIPTION
 .B btrfsctl
 is used to control the filesystem and the files and directories stored. It is the tool to create a new snapshot for the filesystem.
@@ -35,6 +36,13 @@ Scans all devices present in the system for btrfs filesystem.
 .TP
 \fB\-c\fR
 Forces a filesystem sync.
+.TP
+\fB\-C\fR \fI[timeout] [directory]\fR
+Wait until all the space from all deleted snapshots has been recovered.
+The optional timeout parameter is in seconds, or an ISO8601 string,
+defaulting to zero, which means do not time out. Fractional seconds
+resolve to milliseconds. The optional directory parameter defaults to
+the current directory.
 .SH AVAILABILITY
 .B btrfsctl
 is part of btrfs-progs. Btrfs is currently under heavy development,

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support
  2010-10-06 21:00 IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support David Nicol
@ 2010-10-07  6:10 ` Goffredo Baroncelli
  2010-10-07 13:50   ` David Nicol
  2010-10-07 17:38   ` David Nicol
  0 siblings, 2 replies; 6+ messages in thread
From: Goffredo Baroncelli @ 2010-10-07  6:10 UTC (permalink / raw)
  To: linux-btrfs; +Cc: David Nicol

On Wednesday, 06 October, 2010, David Nicol wrote:
> the ISO 8601 duration support is very loose, but I believe it is
> accurate for valid
> input. Without any non-numeric designators, the timeout is interpreted
> as seconds,
> so
>     btrfs fi reclaim 10.3321 /my_btrfs_mount ||  echo timed out
> will wait 10332 ms before echoing, if the pending subvolume deletions
> take longer than that.
> 
> Timeout defaults to 0, and path defaults to current directory.
> 

Please the next time put your patch inline or it is more difficult to 
highlight a suggestion.

Any way:

1)
[...]
+	{ do_wait4clean, 1002, /* require at most two args */
+	  "filesystem reclaim", "<path> [timeout]\n"
+		"Wait for cleanup of deleted subvolumes in the filesystem 
<path>.\n"
+		"Optional timeout in whole or partial seconds, or ISO8601 
string.\n"
+	},
[...]
+int do_wait4clean(int argc, char **argv)
+{
+	int fd, res;
+        struct btrfs_ioctl_cleaner_wait_args w4c_arg;
+
+	char	*path = ".";
+        w4c_arg.ms = 0UL;
+
+        if (argc > 1) 
+	     path = argv[1];
+        if (argc > 2) 
+             w4c_arg.ms = iso8601toms(argv[2]);
 
In the man page and in the help the syntax is reported as:

 btrfs filesystem reclaim <path> [<timeout>]

instead it should be

 btrfs filesystem reclaim [<path> [<timeout>]]

and it has to be reported that path is optional and if it is omitted the 
current CWD is taken.

2) I think that it is more reasonable avoid a "strict" iso 8601 syntax for the 
time. I suggest to use a simple syntax like

0.xxxx -> subsecond 
s or nothing -> seconds
m -> minutes
h -> hour
d -> day
M -> month (but make sense to wait up to a month ?)
[...]

3) As minor issue I have to point out that "reclaim" seems (to me) that the 
user has to start this command in order to obtain more space, like if this 
command starts a garbage collector. In any case the help/man page explain 
clearly the behavior of the command.

4)
[...]
+unsigned long iso8601toms(char *P){
+    unsigned long ms;
+    double component;
+    char *ptr;
+    char *endptr;
+    short M_min = 0;
+
+    ms = 0UL;
+    ptr = P;
+    for(;;){
+       component=strtod(ptr, &endptr);
+       switch (*endptr)
+       {
+          case 'P': /* anchor */ case 'p':
+             if (ptr > P)
+	         fprintf(stderr, "ignoring non-initial P "
+                         "in ISO8601 duration string %s\n", P);
+             break;
+          case 'Y': /* years */ case 'y':
+             component *= 12;
+          BIGM:
+             /* average days in a gregorian month */
+             component *= (365.2425 / 12.0);
+             /* ms in a day */
+             component *= ( 24 * 3600 * 1000 );
+             ms += component;
+             break;
+          case 'T': /* Time (not date) anchor */ case 't':
+             M_min = 1;
+             break;
+          case 'W': /* week */ case 'w':
+             component *= 7;
+          case 'D': /* day */ case 'd':
+             component *=  24 ;
+          case 'H': /* hour */ case 'h':
+             component *= 60;
+             M_min = 1;
+          case 'M': /* month, or minute */ case 'm':
+             if (!M_min++)
+                 goto BIGM;
+             component *= 60;
[...]
In the function  I suggest to avoid if possible a goto in a switch case. I 
think that it is more clear to repeat few lines instead of doing a goto.

Reagrds
G.Baroncelli


-- 
gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo) <kreijack@inwind.it>
Key fingerprint = 4769 7E51 5293 D36C 814E  C054 BF04 F161 3DC5 0512

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support
  2010-10-07  6:10 ` Goffredo Baroncelli
@ 2010-10-07 13:50   ` David Nicol
  2010-10-07 14:25     ` David Nicol
  2010-10-07 17:38   ` David Nicol
  1 sibling, 1 reply; 6+ messages in thread
From: David Nicol @ 2010-10-07 13:50 UTC (permalink / raw)
  Cc: linux-btrfs

On Thu, Oct 7, 2010 at 1:10 AM, Goffredo Baroncelli <kreijack@libero.it=
> wrote:
> On Wednesday, 06 October, 2010, David Nicol wrote:
>> the ISO 8601 duration support is very loose, but I believe it is
>> accurate for valid

> In the man page and in the help the syntax is reported as:
>
> =C2=A0btrfs filesystem reclaim <path> [<timeout>]
>
> instead it should be
>
> =C2=A0btrfs filesystem reclaim [<path> [<timeout>]]
>
> and it has to be reported that path is optional and if it is omitted =
the
> current CWD is taken.

D'oh! yes you are right.



> 2) I think that it is more reasonable avoid a "strict" iso 8601 synta=
x for the
> time. I suggest to use a simple syntax like
>
> 0.xxxx -> subsecond
> s or nothing -> seconds
> m -> minutes
> h -> hour
> d -> day
> M -> month (but make sense to wait up to a month ?)
> [...]

That's what the function provides, aside from differentiating between
M and m instead of using the ISO8601 disambiguation rule (as explained
on wikipedia.) After sleeping on it I'm thinking that a better route
would be either

(1) having the timeout in seconds.subseconds and providing a separate
tool that will parse ISO8601 durations, which is suggested to invoke
in backticks. Greater reusability and fewer library functions linked
into the binaries for the win.

or

(2) only supporting the WDHMS designators, nothing larger, (not big-M
or Y), thus removing the ambiguity. Y or M before [TWDH] would be a
fatal error. No longer caring how many seconds in a year for the win.

> 3) As minor issue I have to point out that "reclaim" seems (to me) th=
at the
> user has to start this command in order to obtain more space, like if=
 this
> command starts a garbage collector. In any case the help/man page exp=
lain
> clearly the behavior of the command.

My hope is that the current behavior is a temporary stand-in for
something to be developed later that will more aggressively collect
garbage.


> + =C2=A0 =C2=A0 =C2=A0 switch (*endptr)
> + =C2=A0 =C2=A0 =C2=A0 {
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'P': /* anchor */ case 'p':
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (ptr > P)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0fprintf(stde=
rr, "ignoring non-initial P "
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0=
 =C2=A0 =C2=A0 "in ISO8601 duration string %s\n", P);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'Y': /* years */ case 'y':
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 component *=3D 12;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0BIGM:
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* average days in a greg=
orian month */
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 component *=3D (365.2425 =
/ 12.0);
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 /* ms in a day */
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 component *=3D ( 24 * 360=
0 * 1000 );
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 ms +=3D component;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'T': /* Time (not date) anch=
or */ case 't':
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 M_min =3D 1;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 break;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'W': /* week */ case 'w':
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 component *=3D 7;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'D': /* day */ case 'd':
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 component *=3D =C2=A024 ;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'H': /* hour */ case 'h':
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 component *=3D 60;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 M_min =3D 1;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case 'M': /* month, or minute */ =
case 'm':
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (!M_min++)
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 goto BIGM;
> + =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 component *=3D 60;
> [...]
> In the function =C2=A0I suggest to avoid if possible a goto in a swit=
ch case. I
> think that it is more clear to repeat few lines instead of doing a go=
to.

Well it isn't a whole Duff's device, but by choosing to use the goto
here the constant of year length in seconds only has to appear once. I
guess I could define a symbol. Stacking the cases like this should cut
down on the number of jumps in the compiled machine code, as each
"break" in a switch is short for a jump to the end. I'd be okay with
testing nearer the top so the jump is forward instead of backwards.

I believe that having a goto in a switch statement with a lot of
fallthroughs in its logic (such as this one) highlights that a C
switch statement makes a jump table rather than being a macro for an
oddly crippled series of else-if statements referring to the same
topic, which is what some providers of switch syntax in certain other
languages like to do with the construct.

review: http://en.wikipedia.org/wiki/Duff's_device

and I'm trying to optimize for size, not speed.
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" =
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support
  2010-10-07 13:50   ` David Nicol
@ 2010-10-07 14:25     ` David Nicol
  2010-10-07 15:50       ` David Nicol
  0 siblings, 1 reply; 6+ messages in thread
From: David Nicol @ 2010-10-07 14:25 UTC (permalink / raw)
  Cc: linux-btrfs

anyway I think I got the logic wrong: the function as given yesterday
would misparse

   PT1M1M

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support
  2010-10-07 14:25     ` David Nicol
@ 2010-10-07 15:50       ` David Nicol
  0 siblings, 0 replies; 6+ messages in thread
From: David Nicol @ 2010-10-07 15:50 UTC (permalink / raw)
  Cc: linux-btrfs

On Thu, Oct 7, 2010 at 9:25 AM, David Nicol <davidnicol@gmail.com> wrot=
e:
> anyway I think I got the logic wrong: the function as given yesterday
> would misparse
>
> =C2=A0 PT1M1M

no it wouldn't! because of the post-increment on the how-to-parse 'M'
state variable, the BIGM label can only get jumped to the first time,
and not following T, W, D or H. Rearranging it to have a forward jump
would lose this.

Better to have an initial sanity-check pass to verify that all
non-numerics are expected and in an acceptable order, and switch one
of the kinds of Ms to some other letter at that time, then zip through
the pieces with a case statement with no logic in it at all, just
stacked multiplications.

Goffredo -- this thinking-out-loud is not noise?
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" =
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support
  2010-10-07  6:10 ` Goffredo Baroncelli
  2010-10-07 13:50   ` David Nicol
@ 2010-10-07 17:38   ` David Nicol
  1 sibling, 0 replies; 6+ messages in thread
From: David Nicol @ 2010-10-07 17:38 UTC (permalink / raw)
  Cc: linux-btrfs

On Thu, Oct 7, 2010 at 1:10 AM, Goffredo Baroncelli <kreijack@libero.it> wrote:
> Please the next time put your patch inline or it is more difficult to
> highlight a suggestion.

* drop support for years and months, except as identified usage errors

* lower-case 'm' now minutes

* escalate syntax warnings to fatal exits


diff --git a/iso8601toms.c b/iso8601toms.c
index a1ee9bd..f982d34 100644
--- a/iso8601toms.c
+++ b/iso8601toms.c
@@ -25,6 +25,8 @@

     accept a non-integer as the last numeric component

+    always treats "m" as minutes
+
  it silently accepts:

     out of order duration type letters
@@ -35,10 +37,12 @@

     non-integers in any position

- it warns on:
+ it halts and catches fire on:

     P or p appearing somewhere besides the beginning of the string

+    Attempts to use Years or Months
+
     unrecognized characters


@@ -53,7 +57,6 @@ unsigned long iso8601toms(char *P){
     char *ptr;
     char *endptr;
     short M_min = 0;
-
     ms = 0UL;
     ptr = P;
     for(;;){
@@ -62,18 +65,13 @@ unsigned long iso8601toms(char *P){
        {
           case 'P': /* anchor */ case 'p':
              if (ptr > P)
-                fprintf(stderr, "ignoring non-initial P "
-                         "in ISO8601 duration string %s\n", P);
-             break;
-          case 'Y': /* years */ case 'y':
-             component *= 12;
-          BIGM:
-             /* average days in a gregorian month */
-             component *= (365.2425 / 12.0);
-             /* ms in a day */
-             component *= ( 24 * 3600 * 1000 );
-             ms += component;
-             break;
+                fprintf(stderr, "non-initial P "
+                         "in duration string %s\n", P);
+                 exit (-1);
+          case 'Y': /* year */ case 'y':
+                fprintf(stderr, "Years are not supported "
+                         "in duration string %s\n", P);
+                 exit (-1);
           case 'T': /* Time (not date) anchor */ case 't':
              M_min = 1;
              break;
@@ -84,9 +82,15 @@ unsigned long iso8601toms(char *P){
           case 'H': /* hour */ case 'h':
              component *= 60;
              M_min = 1;
-          case 'M': /* month, or minute */ case 'm':
-             if (!M_min++)
-                 goto BIGM;
+          case 'M': /* month, or minute */
+             if (M_min == 0 ){
+                fprintf(stderr, "Months are not supported "
+                         "in duration string %s\n"
+                         "use 'm' instead or prefix a 'T'\n"
+                         , P);
+                 exit (-1);
+             };
+          case 'm': /* minute */
              component *= 60;
           case 'S': /* second */ case 's':
           case '\0': /* default to second */
@@ -96,10 +100,11 @@ unsigned long iso8601toms(char *P){

           default:
             fprintf(stderr,
-                "ignoring unexpected char [%c] "
-                "in iso8601 duration string %s\n",
+                "unexpected char [%c] in duration string %s\n"
+                "valid designators are [WwDdHhMmSs] with implied
trailing S.\n",
                 *endptr, P
              );
+             exit (-1);
        };
        if (!*endptr)
           return (ms);

^ permalink raw reply related	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-10-07 17:38 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-06 21:00 IOCTL #21 part two: btrfs progs patch, including iso 8601 timeout support David Nicol
2010-10-07  6:10 ` Goffredo Baroncelli
2010-10-07 13:50   ` David Nicol
2010-10-07 14:25     ` David Nicol
2010-10-07 15:50       ` David Nicol
2010-10-07 17:38   ` David Nicol

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).