9fans - fans of the OS Plan 9 from Bell Labs
 help / color / mirror / Atom feed
* [9fans] Wouldn't a rename(2) call be a good thing?
@ 1998-12-30  6:31 G.David
  0 siblings, 0 replies; only message in thread
From: G.David @ 1998-12-30  6:31 UTC (permalink / raw)


9fans,

I have been working on my data models and found some more
things lacking.  A rename(2) call would go a long way to
making data updates sane in the face of failures.  To
accomplish this I modified the way the fileserver implements
wstat(2) to allow an atomic file replacement.  The way I
did it is backwards compatible with normal wstat usage.

Also I asked the list a couple of months ago about the idea
of a system call interface to walk.  I proposed the call
should be called qstat(2).  There is also a dirqstat(2).
They return the same data as the stat(2) and dirstat(2)
calls, but only the qid, type and dev fields are valid.

Included is a little program I wrote to test these things.

David Butler
gdb@dbSystems.com

Disclamer:
Code hacking by professional on closed research course.
Do not try this at home. :->

#include <u.h>
#include <libc.h>

void
main()
{
	Dir mdir, ndir;
	int fd;
	char tmp[] = "Xsysname.pid";	/* tmp file name */
	char new[] = "new";

	/* if the tmp name starts with an invalid utf string */
	/* it is pretty safe to not be used */
	tmp[0] = Runesync;
	print("%d %x\n", strlen(tmp), tmp[0]);

	/* create a temp file such that if the process dies */
	/* it will be automatically removed */
	if((fd = create(tmp, OWRITE|ORCLOSE, 0666)) < 0) {
		fprint(2, "create tmp: %r\n");
		exits("create");
	}

	/* stat it by fd */
	if(dirfstat(fd, &mdir) < 0) {
		fprint(2, "dirfstat tmp: %r\n");
		exits("dirstat");
	}

	/* this will look strange because of the Runesync */
	print("%s/%ld/%ld/%ud/%ud\n", mdir.name,
	  mdir.qid.path, mdir.qid.vers, mdir.type, mdir.dev);

	/* this should remove the file */
	close(fd);

	/* check that it went away using walk */
	/* the returned structure is the same as stat, */
	/* but only the qid, type and dev are valid */
	if(dirqstat(tmp, &mdir) < 0) {
		fprint(2, "dirstat tmp: %r\n");
	}

	/* start again */
	if((fd = create(tmp, OWRITE|ORCLOSE, 0666)) < 0) {
		fprint(2, "create tmp: %r\n");
		exits("create");
	}

	/* write the "data" */
	if(write(fd, "test\n", 5) != 5) {
		fprint(2, "write tmp: %r\n");
		exits("write");
	}

	/* look again at the stat */
	if(dirfstat(fd, &mdir) < 0) {
		fprint(2, "dirfstat tmp: %r\n");
		exits("dirstat");
	}
	print("%s/%ld/%ld/%ud/%ud\n", mdir.name, 
	  mdir.qid.path, mdir.qid.vers, mdir.type, mdir.dev);

	/* the data is complete and we want to move this */
	/* data to the real name */
	/* this will clear the remove on close flag */
	strcpy(mdir.name, new);

	/* does the new name exist? */
	if(dirqstat(mdir.name, &ndir) < 0) {

		/* the new name does not exist */
		fprint(2, "dirqstat new: %r\n");
	} else {

		/* it does exist, lets try to atomically */
		/* replacing the old with the new */
		/* this is flagged by trying to change a file */
		/* to a directory or vice versa */
		mdir.mode |= CHDIR;

		/* do it */
		if(dirfwstat(fd, &mdir) < 0) {
			/* it should fail */
			fprint(2, "dirfwstat tmp new: %r\n");
			/* the error is Eqid "qid does not match" */
		}

		/* it will only succeed if the qid of the wstat */
		/* matches the qid of the file we are replacing */
		mdir.qid.path = ndir.qid.path;
		mdir.qid.vers = ndir.qid.vers;
	}

	/* rename */
	if(dirfwstat(fd, &mdir) < 0) {
		fprint(2, "dirfwstat tmp new: %r\n");
		exits("dirstat");
	}

	/* look at the file by fd, it should have the new name */
	if(dirfstat(fd, &mdir) < 0) {
		fprint(2, "dirfstat tmp: %r\n");
		exits("dirstat");
	}
	print("%s/%ld/%ld/%ud/%ud\n", mdir.name,
	  mdir.qid.path, mdir.qid.vers, mdir.type, mdir.dev);

	/* the close should leave the file there now */
	close(fd);

	/* is the old one there? */
	if(dirqstat(tmp, &mdir) < 0) {
		/* nope */
		fprint(2, "dirstat tmp: %r\n");
	}

	/* is the new one? */
	if(dirqstat(new, &mdir) < 0) {
		fprint(2, "dirstat b: %r\n");
		exits("dirstat");
	}

	/* yes! */
	print("%ld/%ld/%ud/%ud\n",
	  mdir.qid.path, mdir.qid.vers, mdir.type, mdir.dev);
}

The execution with the 0x80 removed for the non-Plan9 readers.

cpu% ./8.out
12 -80
sysname.pid/30/1/77/102
dirstat tmp: file does not exist
sysname.pid/30/2/77/102
dirqstat new: file does not exist
new/30/2/77/102
dirstat tmp: file does not exist
30/2/77/102
cpu% ./8.out
12 -80
sysname.pid/31/1/77/102
dirstat tmp: file does not exist
sysname.pid/31/2/77/102
dirfwstat tmp new: phase error -- qid does not match
new/31/2/77/102
dirstat tmp: file does not exist
31/2/77/102
cpu% 





^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~1998-12-30  6:31 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1998-12-30  6:31 [9fans] Wouldn't a rename(2) call be a good thing? G.David

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).