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