The reconnect algorithm was historically O(n^4).
Some years ago I made it O(n^2). Someone helpfully made it O(n^4) again. Today I'm making it O(n). If that's not good enough, I don't know what else to do. B-) Technical details: * The graph traversal in propagate() is modified to be able to start from any point in the tree. To handle certain exceptional cases, it is also modified to work in two passes, marking the tree with a special tag and then changing it to DFOUND. * The reconnect case now modifies the child/sibling pointers and calls propagate() to propagate the connection state starting with the reconnected directory. Pray that you never encounter a file system trashed enough for this to matter.
This commit is contained in:
parent
3f2ff10f4c
commit
66418680d4
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: dir.c,v 1.28 2000/12/14 00:32:22 simonb Exp $ */
|
||||
/* $NetBSD: dir.c,v 1.29 2001/01/09 05:51:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
|
@ -38,7 +38,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)dir.c 8.8 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: dir.c,v 1.28 2000/12/14 00:32:22 simonb Exp $");
|
||||
__RCSID("$NetBSD: dir.c,v 1.29 2001/01/09 05:51:14 mycroft Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -84,38 +84,33 @@ static int mkentry __P((struct inodesc *));
|
|||
* Propagate connected state through the tree.
|
||||
*/
|
||||
void
|
||||
propagate()
|
||||
propagate(inumber)
|
||||
ino_t inumber;
|
||||
{
|
||||
struct inoinfo **inpp, *inp, *pinp;
|
||||
struct inoinfo **inpend;
|
||||
struct inoinfo *inp;
|
||||
|
||||
/*
|
||||
* Create a list of children for each directory.
|
||||
*/
|
||||
inpend = &inpsort[inplast];
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
inp->i_child = inp->i_sibling = inp->i_parentp = 0;
|
||||
if (statemap[inp->i_number] == DFOUND)
|
||||
statemap[inp->i_number] = DSTATE;
|
||||
inp = getinoinfo(inumber);
|
||||
|
||||
for (;;) {
|
||||
statemap[inp->i_number] = DMARK;
|
||||
if (inp->i_child &&
|
||||
statemap[inp->i_child->i_number] != DMARK)
|
||||
inp = inp->i_child;
|
||||
else if (inp->i_number == inumber)
|
||||
break;
|
||||
else if (inp->i_sibling)
|
||||
inp = inp->i_sibling;
|
||||
else
|
||||
inp = inp->i_parentp;
|
||||
}
|
||||
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_parent == 0 ||
|
||||
inp->i_number == ROOTINO)
|
||||
continue;
|
||||
pinp = getinoinfo(inp->i_parent);
|
||||
inp->i_parentp = pinp;
|
||||
inp->i_sibling = pinp->i_child;
|
||||
pinp->i_child = inp;
|
||||
}
|
||||
inp = getinoinfo(ROOTINO);
|
||||
while (inp) {
|
||||
for (;;) {
|
||||
statemap[inp->i_number] = DFOUND;
|
||||
if (inp->i_child &&
|
||||
statemap[inp->i_child->i_number] == DSTATE)
|
||||
statemap[inp->i_child->i_number] != DFOUND)
|
||||
inp = inp->i_child;
|
||||
else if (inp->i_number == inumber)
|
||||
break;
|
||||
else if (inp->i_sibling)
|
||||
inp = inp->i_sibling;
|
||||
else
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: extern.h,v 1.10 1998/07/26 20:32:42 mycroft Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.11 2001/01/09 05:51:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994 James A. Jegers
|
||||
|
@ -74,7 +74,7 @@ int pass4check __P((struct inodesc *));
|
|||
void pass5 __P((void));
|
||||
void pfatal __P((const char *fmt, ...));
|
||||
void pinode __P((ino_t));
|
||||
void propagate __P((void));
|
||||
void propagate __P((ino_t));
|
||||
void pwarn __P((const char *fmt, ...));
|
||||
int reply __P((char *));
|
||||
void resetinodebuf __P((void));
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: fsck.h,v 1.21 2000/12/13 22:38:15 scw Exp $ */
|
||||
/* $NetBSD: fsck.h,v 1.22 2001/01/09 05:51:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
|
@ -53,6 +53,7 @@
|
|||
#define DFOUND 04 /* directory found during descent */
|
||||
#define DCLEAR 05 /* directory is to be cleared */
|
||||
#define FCLEAR 06 /* file is to be cleared */
|
||||
#define DMARK 07 /* used in propagate()'s traversal algorithm */
|
||||
|
||||
/*
|
||||
* buffer cache structure.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: pass2.c,v 1.28 2001/01/05 02:02:57 lukem Exp $ */
|
||||
/* $NetBSD: pass2.c,v 1.29 2001/01/09 05:51:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
|
@ -38,7 +38,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)pass2.c 8.9 (Berkeley) 4/28/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: pass2.c,v 1.28 2001/01/05 02:02:57 lukem Exp $");
|
||||
__RCSID("$NetBSD: pass2.c,v 1.29 2001/01/09 05:51:14 mycroft Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -67,7 +67,7 @@ void
|
|||
pass2()
|
||||
{
|
||||
struct dinode *dp;
|
||||
struct inoinfo **inpp, *inp;
|
||||
struct inoinfo **inpp, *inp, *pinp;
|
||||
struct inoinfo **inpend;
|
||||
struct inodesc curino;
|
||||
struct dinode dino;
|
||||
|
@ -235,10 +235,30 @@ pass2()
|
|||
inp->i_dotdot = inp->i_parent;
|
||||
(void)changeino(inp->i_number, "..", inp->i_parent);
|
||||
}
|
||||
/*
|
||||
* Create a list of children for each directory.
|
||||
*/
|
||||
inpend = &inpsort[inplast];
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
inp->i_child = inp->i_sibling = inp->i_parentp = 0;
|
||||
if (statemap[inp->i_number] == DFOUND)
|
||||
statemap[inp->i_number] = DSTATE;
|
||||
}
|
||||
for (inpp = inpsort; inpp < inpend; inpp++) {
|
||||
inp = *inpp;
|
||||
if (inp->i_parent == 0 ||
|
||||
inp->i_number == ROOTINO)
|
||||
continue;
|
||||
pinp = getinoinfo(inp->i_parent);
|
||||
inp->i_parentp = pinp;
|
||||
inp->i_sibling = pinp->i_child;
|
||||
pinp->i_child = inp;
|
||||
}
|
||||
/*
|
||||
* Mark all the directories that can be found from the root.
|
||||
*/
|
||||
propagate();
|
||||
propagate(ROOTINO);
|
||||
}
|
||||
|
||||
static int
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: pass3.c,v 1.10 1997/09/16 16:45:19 lukem Exp $ */
|
||||
/* $NetBSD: pass3.c,v 1.11 2001/01/09 05:51:14 mycroft Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
|
@ -38,7 +38,7 @@
|
|||
#if 0
|
||||
static char sccsid[] = "@(#)pass3.c 8.2 (Berkeley) 4/27/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: pass3.c,v 1.10 1997/09/16 16:45:19 lukem Exp $");
|
||||
__RCSID("$NetBSD: pass3.c,v 1.11 2001/01/09 05:51:14 mycroft Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
|
@ -54,7 +54,7 @@ __RCSID("$NetBSD: pass3.c,v 1.10 1997/09/16 16:45:19 lukem Exp $");
|
|||
void
|
||||
pass3()
|
||||
{
|
||||
struct inoinfo **inpp, *inp;
|
||||
struct inoinfo **inpp, *inp, *pinp;
|
||||
ino_t orphan;
|
||||
int loopcnt;
|
||||
|
||||
|
@ -76,7 +76,10 @@ pass3()
|
|||
(void)linkup(orphan, inp->i_dotdot);
|
||||
inp->i_parent = inp->i_dotdot = lfdir;
|
||||
lncntp[lfdir]--;
|
||||
statemap[orphan] = DFOUND;
|
||||
propagate();
|
||||
pinp = getinoinfo(lfdir);
|
||||
inp->i_parentp = pinp;
|
||||
inp->i_sibling = pinp->i_child;
|
||||
pinp->i_child = inp;
|
||||
propagate(orphan);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue