Index: openafs/src/WINNT/afsd/NTMakefile
diff -c openafs/src/WINNT/afsd/NTMakefile:1.46.2.5 openafs/src/WINNT/afsd/NTMakefile:1.46.2.6
*** openafs/src/WINNT/afsd/NTMakefile:1.46.2.5 Thu Jul 5 15:22:15 2007
--- openafs/src/WINNT/afsd/NTMakefile Thu Aug 23 23:21:49 2007
***************
*** 99,104 ****
--- 99,105 ----
$(OUT)\rawops.obj \
$(OUT)\afsdifs.obj \
$(OUT)\afsd_init.obj \
+ $(OUT)\cm_btree.obj \
$(OUT)\cm_cell.obj \
$(OUT)\cm_server.obj \
$(OUT)\cm_volume.obj \
Index: openafs/src/WINNT/afsd/afsd.h
diff -c openafs/src/WINNT/afsd/afsd.h:1.18.2.3 openafs/src/WINNT/afsd/afsd.h:1.18.2.4
*** openafs/src/WINNT/afsd/afsd.h:1.18.2.3 Thu Jul 5 15:22:15 2007
--- openafs/src/WINNT/afsd/afsd.h Thu Aug 23 23:21:49 2007
***************
*** 10,15 ****
--- 10,17 ----
#ifndef __AFSD_H_ENV__
#define __AFSD_H_ENV__ 1
+ #define USE_BPLUS 1
+
#include
#ifndef DJGPP
***************
*** 32,39 ****
--- 34,46 ----
#include "cm.h"
#include
+ #include
+ #include
+ #include
+
#include "cm_config.h"
#include "cm_user.h"
+ #include "cm_scache.h"
#include "cm_callback.h"
#ifdef DISKCACHE95
#include "cm_diskcache95.h"
***************
*** 42,48 ****
#include "cm_aclent.h"
#include "cm_server.h"
#include "cm_cell.h"
- #include "cm_scache.h"
#include "cm_volume.h"
#include "cm_volstat.h"
#include "cm_dcache.h"
--- 49,54 ----
***************
*** 64,72 ****
#include "afsd_eventlog.h"
#endif
- #include
- #include
- #include
#define AFS_DAEMON_SERVICE_NAME AFSREG_CLT_SVC_NAME
#define AFS_DAEMON_EVENT_NAME AFSREG_CLT_SW_NAME
--- 70,75 ----
Index: openafs/src/WINNT/afsd/afsd_init.c
diff -c openafs/src/WINNT/afsd/afsd_init.c:1.79.2.15 openafs/src/WINNT/afsd/afsd_init.c:1.79.2.16
*** openafs/src/WINNT/afsd/afsd_init.c:1.79.2.15 Fri Aug 10 16:39:26 2007
--- openafs/src/WINNT/afsd/afsd_init.c Thu Aug 23 23:21:49 2007
***************
*** 40,45 ****
--- 40,46 ----
extern afs_int32 cryptall;
extern int cm_enableServerLocks;
extern int cm_deleteReadOnly;
+ extern afs_int32 cm_BPlusTrees;
osi_log_t *afsd_logp;
***************
*** 1057,1062 ****
--- 1058,1071 ----
}
afsi_log("CM DeleteReadOnly is %u", cm_deleteReadOnly);
+ dummyLen = sizeof(DWORD);
+ code = RegQueryValueEx(parmKey, "BPlusTrees", NULL, NULL,
+ (BYTE *) &dwValue, &dummyLen);
+ if (code == ERROR_SUCCESS) {
+ cm_BPlusTrees = (unsigned short) dwValue;
+ }
+ afsi_log("CM BPlusTrees is %u", cm_BPlusTrees);
+
RegCloseKey (parmKey);
cacheBlocks = ((afs_uint64)cacheSize * 1024) / blockSize;
Index: openafs/src/WINNT/afsd/afsd_service.c
diff -c openafs/src/WINNT/afsd/afsd_service.c:1.52.4.15 openafs/src/WINNT/afsd/afsd_service.c:1.52.4.16
*** openafs/src/WINNT/afsd/afsd_service.c:1.52.4.15 Sun Aug 12 22:53:30 2007
--- openafs/src/WINNT/afsd/afsd_service.c Thu Aug 23 23:21:49 2007
***************
*** 1469,1474 ****
--- 1469,1479 ----
PowerNotificationThreadExit();
#endif
+ cm_DirDumpStats();
+ #ifdef USE_BPLUS
+ cm_BPlusDumpStats();
+ #endif
+
/* Notify any Volume Status Handlers that we are stopped */
cm_VolStatus_Service_Stopped();
Index: openafs/src/WINNT/afsd/cm.h
diff -c openafs/src/WINNT/afsd/cm.h:1.17.2.4 openafs/src/WINNT/afsd/cm.h:1.17.2.5
*** openafs/src/WINNT/afsd/cm.h:1.17.2.4 Thu Jul 5 15:22:15 2007
--- openafs/src/WINNT/afsd/cm.h Thu Aug 23 23:21:49 2007
***************
*** 301,306 ****
--- 301,307 ----
#define CM_ERROR_TOOMANYBUFS (CM_ERROR_BASE+51)
#define CM_ERROR_BAD_LEVEL (CM_ERROR_BASE+52)
#define CM_ERROR_NOT_A_DFSLINK (CM_ERROR_BASE+53)
+ #define CM_ERROR_INEXACT_MATCH (CM_ERROR_BASE+54)
/* Used by cm_FollowMountPoint and cm_GetVolumeByName */
#define RWVOL 0
Index: openafs/src/WINNT/afsd/cm_btree.c
diff -c openafs/src/WINNT/afsd/cm_btree.c:1.1.2.2 openafs/src/WINNT/afsd/cm_btree.c:1.1.2.4
*** openafs/src/WINNT/afsd/cm_btree.c:1.1.2.2 Wed Aug 22 12:00:45 2007
--- openafs/src/WINNT/afsd/cm_btree.c Sun Aug 26 20:11:43 2007
***************
*** 1 ****
! /* Place holder for B+ tree source code */
--- 1,1619 ----
! /*
! * Copyright 2007 Secure Endpoints Inc.
! *
! * All Rights Reserved.
! *
! * This software has been released under the terms of the IBM Public
! * License. For details, see the LICENSE file in the top-level source
! * directory or online at http://www.openafs.org/dl/license10.html
! *
! * Thanks to Jan Jannink for B+ tree algorithms.
! */
!
! #include
! #include
! #include
! #include
! #include "afsd.h"
!
! #ifdef USE_BPLUS
! #include "cm_btree.h"
!
! /******************* statistics globals *********************************/
! afs_uint32 bplus_lookup_hits = 0;
! afs_uint32 bplus_lookup_hits_inexact = 0;
! afs_uint32 bplus_lookup_misses = 0;
! afs_uint32 bplus_lookup_ambiguous = 0;
! afs_uint32 bplus_create_entry = 0;
! afs_uint32 bplus_remove_entry = 0;
! afs_uint32 bplus_build_tree = 0;
! afs_uint32 bplus_free_tree = 0;
! afs_uint32 bplus_dv_error = 0;
!
! afs_uint64 bplus_lookup_time = 0;
! afs_uint64 bplus_create_time = 0;
! afs_uint64 bplus_remove_time = 0;
! afs_uint64 bplus_build_time = 0;
! afs_uint64 bplus_free_time = 0;
!
! /*********************** private functions *************************/
! static void initFreeNodePool(Tree *B, int quantity);
! static Nptr getFreeNode(Tree *B);
! static void putFreeNode(Tree *B, Nptr self);
! static void cleanupNodePool(Tree *B);
!
! static Nptr descendToLeaf(Tree *B, Nptr curr);
! static int getSlot(Tree *B, Nptr curr);
! static int findKey(Tree *B, Nptr curr, int lo, int hi);
! static int bestMatch(Tree *B, Nptr curr, int slot);
!
! static Nptr getDataNode(Tree *B, keyT key, dataT data);
! static Nptr descendSplit(Tree *B, Nptr curr);
! static void insertEntry(Tree *B, Nptr node, int slot, Nptr sibling, Nptr downPtr);
! static void placeEntry(Tree *B, Nptr node, int slot, Nptr downPtr);
! static Nptr split(Tree *B, Nptr node);
! static void makeNewRoot(Tree *B, Nptr oldRoot, Nptr newNode);
!
! static Nptr descendBalance(Tree *B, Nptr curr, Nptr left, Nptr right, Nptr lAnc, Nptr rAnc, Nptr parent);
! static void collapseRoot(Tree *B, Nptr oldRoot, Nptr newRoot);
! static void removeEntry(Tree *B, Nptr curr, int slot);
! static Nptr merge(Tree *B, Nptr left, Nptr right, Nptr anchor);
! static Nptr shift(Tree *B, Nptr left, Nptr right, Nptr anchor);
!
! static void _clrentry(Nptr node, int entry);
! static void _pushentry(Nptr node, int entry, int offset);
! static void _pullentry(Nptr node, int entry, int offset);
! static void _xferentry(Nptr srcNode, int srcEntry, Nptr destNode, int destEntry);
! static void _setentry(Nptr node, int entry, keyT key, Nptr downNode);
!
! #ifdef DEBUG_BTREE
! static int _isRoot(Tree *B, Nptr n)
! {
! int flagset = ((n->flags & isROOT) == isROOT);
!
! if (!isnode(n))
! return 0;
!
! if (flagset && n != getroot(B))
! DebugBreak();
!
! return flagset;
! }
!
! static int _isFew(Tree *B, Nptr n)
! {
! int flagset = ((n->flags & FEWEST) == FEWEST);
! int fanout = getminfanout(B, n);
! int entries = numentries(n);
! int mincnt = entries <= fanout;
!
! if (!isnode(n))
! return 0;
!
! if (flagset && !mincnt || !flagset && mincnt)
! DebugBreak();
!
! return flagset;
! }
!
! static int _isFull(Tree *B, Nptr n)
! {
! int flagset = ((n->flags & isFULL) == isFULL);
! int maxcnt = numentries(n) == getfanout(B);
!
! if (!isnode(n))
! return 0;
!
! if (flagset && !maxcnt || !flagset && maxcnt)
! DebugBreak();
!
! return flagset;
! }
! #endif /* DEBUG_BTREE */
!
! /***********************************************************************\
! | B+tree Initialization and Cleanup Routines |
! \***********************************************************************/
!
! /******************** Set up B+tree structure **********************/
! Tree *initBtree(unsigned int poolsz, unsigned int fanout, KeyCmp keyCmp)
! {
! Tree *B;
! keyT empty = {NULL};
! dataT data = {0,0,0,0};
!
! if (fanout > MAX_FANOUT)
! fanout = MAX_FANOUT;
!
! setbplustree(B, malloc(sizeof(Tree)));
! memset(B, 0, sizeof(Tree));
! setfanout(B, fanout);
! setminfanout(B, (fanout + 1) >> 1);
! initFreeNodePool(B, poolsz);
!
! setleaf(B, getFreeNode(B)); /* set up the first leaf node */
! setroot(B, getleaf(B)); /* the root is initially the leaf */
! setflag(getroot(B), isLEAF);
! setflag(getroot(B), isROOT);
! setflag(getroot(B), FEWEST);
! inittreeheight(B);
!
! setfunkey(B,empty);
! setfundata(B,data);
! setcomparekeys(B, keyCmp);
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "INIT: B+tree of fanout %d at %10p.\n", fanout, (void *)B);
! OutputDebugString(B->message);
! #endif
!
! return B;
! }
!
! /******************** Clean up B+tree structure ********************/
! /*
! * dirlock must be write locked
! */
! void freeBtree(Tree *B)
! {
! #ifdef DEBUG_BTREE
! sprintf(B->message, "FREE: B+tree at %10p.\n", (void *) B);
! OutputDebugString(B->message);
! #endif
!
! cleanupNodePool(B);
!
! memset(B, 0, sizeof(*B));
! free((void *) B);
! }
!
!
! /***********************************************************************\
! | Find location for data |
! \***********************************************************************/
!
! /********************** top level lookup **********************/
! Nptr bplus_Lookup(Tree *B, keyT key)
! {
! Nptr findNode;
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "LOOKUP: key %s.\n", key.name);
! OutputDebugString(B->message);
! #endif
!
! setfunkey(B, key); /* set search key */
! findNode = descendToLeaf(B, getroot(B)); /* start search from root node */
!
! #ifdef DEBUG_BTREE
! if (findNode) {
! int slot;
! Nptr dataNode;
! dataT data;
!
! slot = findKey(B, findNode, 1, numentries(findNode));
! dataNode = getnode(findNode, slot);
! data = getdatavalue(dataNode);
!
! sprintf(B->message, "LOOKUP: %s found on page %d value (%d.%d.%d).\n",
! key.name,
! getnodenumber(B, findNode),
! data.volume,
! data.vnode,
! data.unique);
! } else
! sprintf(B->message, "LOOKUP: not found!\n");
! OutputDebugString(B->message);
! #endif
!
! return findNode;
! }
!
! /********************** `recurse' down B+tree **********************/
! static Nptr descendToLeaf(Tree *B, Nptr curr)
! {
! int slot;
! Nptr findNode;
! Nptr prev[64];
! int depth;
!
! memset(prev, 0, sizeof(prev));
!
! for (depth = 0, slot = getSlot(B, curr); isinternal(curr); depth++, slot = getSlot(B, curr)) {
! prev[depth] = curr;
! if (slot == 0)
! curr = getfirstnode(curr);
! else
! curr = getnode(curr, slot);
! #ifdef DEBUG_BTREE
! if ( !isnode(curr) )
! DebugBreak();
! #endif
! }
! if ((slot > 0) && !comparekeys(B)(getfunkey(B), getkey(curr, slot), 0))
! findNode = curr; /* correct key value found */
! else
! findNode = NONODE; /* key value not in tree */
!
! return findNode;
! }
!
! /******************** find slot for search key *********************/
! static int getSlot(Tree *B, Nptr curr)
! {
! int slot, entries;
!
! entries = numentries(curr); /* need this if root is ever empty */
! slot = !entries ? 0 : findKey(B, curr, 1, entries);
!
! return slot;
! }
!
!
! /******************** recursive binary search **********************/
! static int findKey(Tree *B, Nptr curr, int lo, int hi)
! {
! int mid, findslot = BTERROR;
!
! if (hi == lo) {
! findslot = bestMatch(B, curr, lo); /* recursion base case */
!
! #ifdef DEBUG_BTREE
! if (findslot == BTERROR) {
! sprintf(B->message, "Bad key ordering on node %d\n", getnodenumber(B, curr));
! OutputDebugString(B->message);
! }
! #endif
! } else {
! mid = (lo + hi) >> 1;
! switch (findslot = bestMatch(B, curr, mid)) {
! case BTLOWER: /* check lower half of range */
! findslot = findKey(B, curr, lo, mid - 1); /* never in 2-3+trees */
! break;
! case BTUPPER: /* check upper half of range */
! findslot = findKey(B, curr, mid + 1, hi);
! break;
! case BTERROR:
! sprintf(B->message, "Bad key ordering on node %d\n", getnodenumber(B, curr));
! OutputDebugString(B->message);
! }
! }
! return findslot;
! }
!
!
! /************ comparison of key with a target key slot *************/
! static int bestMatch(Tree *B, Nptr curr, int slot)
! {
! int diff, comp, findslot;
!
! diff = comparekeys(B)(getfunkey(B), getkey(curr, slot), 0);
! if (diff < 0) { /* also check previous slot */
! if ((slot == 1) ||
! ((comp = comparekeys(B)(getfunkey(B), getkey(curr, slot - 1), 0)) >= 0))
! {
! findslot = slot - 1;
! }
! else if (comp < diff) {
! findslot = BTERROR; /* inconsistent ordering of keys */
! #ifdef DEBUG_BTREE
! DebugBreak();
! #endif
! }
! else {
! findslot = BTLOWER; /* key must be below in node ordering */
! }
! } else { /* or check following slot */
! if ((slot == numentries(curr)) ||
! ((comp = comparekeys(B)(getfunkey(B), getkey(curr, slot + 1), 0)) < 0))
! {
! findslot = slot;
! }
! else if (comp == 0) {
! findslot = slot + 1;
! }
! else if (comp > diff) {
! findslot = BTERROR; /* inconsistent ordering of keys */
! #ifdef DEBUG_BTREE
! DebugBreak();
! #endif
! }
! else {
! findslot = BTUPPER; /* key must be above in node ordering */
! }
! }
! return findslot;
! }
!
!
! /***********************************************************************\
! | Insert new data into tree |
! \***********************************************************************/
!
!
! /********************** top level insert call **********************/
! void insert(Tree *B, keyT key, dataT data)
! {
! Nptr newNode;
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "INSERT: key %s.\n", key.name);
! OutputDebugString(B->message);
! #endif
!
! setfunkey(B, key); /* set insertion key */
! setfundata(B, data); /* a node containing data */
! setsplitpath(B, NONODE);
! newNode = descendSplit(B, getroot(B)); /* insertion point search from root */
! if (newNode != getsplitpath(B)) /* indicates the root node has split */
! makeNewRoot(B, getroot(B), newNode);
! }
!
!
! /***************** recurse down and split back up ******************/
! static Nptr
! descendSplit(Tree *B, Nptr curr)
! {
! Nptr downNode = NONODE, sibling = NONODE;
! int slot;
!
! #ifdef DEBUG_BTREE
! if (!isnode(curr))
! DebugBreak();
! #endif
! if (!isfull(curr))
! setsplitpath(B, NONODE);
! else if (getsplitpath(B) == NONODE)
! setsplitpath(B, curr); /* indicates where nodes must split */
!
! slot = getSlot(B, curr); /* is null only if the root is empty */
! if (isinternal(curr)) { /* continue recursion to leaves */
! if (slot == 0)
! downNode = descendSplit(B, getfirstnode(curr));
! else
! downNode = descendSplit(B, getnode(curr, slot));
! } else if ((slot > 0) && !comparekeys(B)(getfunkey(B), getkey(curr, slot), 0)) {
! if (!(gettreeflags(B) & TREE_FLAG_UNIQUE_KEYS)) {
! downNode = getDataNode(B, getfunkey(B), getfundata(B));
! getdatanext(downNode) = getnode(curr,slot);
! setnode(curr, slot, downNode);
! }
! downNode = NONODE;
! setsplitpath(B, NONODE);
! }
! else
! downNode = getDataNode(B, getfunkey(B), getfundata(B)); /* an insertion takes place */
!
! if (downNode != NONODE) { /* insert only where necessary */
! if (getsplitpath(B) != NONODE)
! sibling = split(B, curr); /* a sibling node is prepared */
! insertEntry(B, curr, slot, sibling, downNode);
! }
!
! return sibling;
! }
!
! /*************** determine location of inserted key ****************/
! static void
! insertEntry(Tree *B, Nptr currNode, int slot, Nptr sibling, Nptr downPtr)
! {
! int split, i, j, k, x, y;
! keyT key;
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "INSERT: slot %d, down node %d.\n", slot, getnodenumber(B, downPtr));
! OutputDebugString(B->message);
! #endif
!
! if (sibling == NONODE) { /* no split occurred */
! placeEntry(B, currNode, slot + 1, downPtr);
! }
! else { /* split entries between the two */
! if isinternal(currNode) {
! i = 1;
! split = getfanout(B) - getminfanout(B, currNode);
! } else if (isroot(currNode)) {
! /* split the root node and turn it into just a leaf */
! i = 0;
! split = getminfanout(B, currNode);
! } else {
! i = 0;
! split = getminfanout(B, currNode);
! }
! j = (slot != split ? 1 : 0);
! k = (slot >= split ? 1 : 0);
!
! /*
! * Move entries from the top half of the current node to
! * to the sibling node.
! * The number of entries to move is dependent upon where
! * the new entry is going to be added in relationship to
! * the split slot. (slots are 1-based). If order to produce
! * a balanced tree, if the insertion slot is greater than
! * the split we move one less entry as the new entry will
! * be inserted into the sibling.
! *
! * If the node that is being split is an internal node (i != 0)
! * then we move one less entry due to the extra down pointer
! * when the split slot is not equal to the insertion slot
! */
! for (x = split + k + j * i, y = 1; x <= getfanout(B); x++, y++) {
! xferentry(currNode, x, sibling, y); /* copy entries to sibling */
! clrentry(currNode, x);
! decentries(currNode);
! incentries(sibling);
!
! #ifdef DEBUG_BTREE
! if (getkey(sibling, numentries(sibling)).name == NULL)
! DebugBreak();
! #endif
! }
! clrflag(currNode, isFULL);
! if (numentries(currNode) == getminfanout(B, currNode))
! setflag(currNode, FEWEST); /* never happens in even size nodes */
!
! #ifdef DEBUG_BTREE
! if (numentries(sibling) > getfanout(B))
! DebugBreak();
! #endif
! if (numentries(sibling) == getfanout(B))
! setflag(sibling, isFULL); /* only ever happens in 2-3+trees */
!
! if (numentries(sibling) > getminfanout(B, sibling))
! clrflag(sibling, FEWEST);
!
! if (i) { /* set first pointer of internal node */
! if (j) {
! setfirstnode(sibling, getnode(currNode, split + k));
! decentries(currNode);
! if (numentries(currNode) == getminfanout(B, currNode))
! setflag(currNode, FEWEST);
! else
! clrflag(currNode, FEWEST);
! }
! else
! setfirstnode(sibling, downPtr);
! }
!
! if (j) { /* insert new entry into correct spot */
! if (k)
! placeEntry(B, sibling, slot - split + 1 - i, downPtr);
! else
! placeEntry(B, currNode, slot + 1, downPtr);
!
! /* set key separating nodes */
! if (isleaf(sibling))
! key = getkey(sibling, 1);
! else {
! Nptr leaf = getfirstnode(sibling);
! while ( isinternal(leaf) )
! leaf = getfirstnode(leaf);
! key = getkey(leaf, 1);
! }
! setfunkey(B, key);
! }
! else if (!i)
! placeEntry(B, sibling, 1, downPtr);
! }
! }
!
! /************ place key into appropriate node & slot ***************/
! static void
! placeEntry(Tree *B, Nptr node, int slot, Nptr downPtr)
! {
! int x;
!
! #ifdef DEBUG_BTREE
! if (isfull(node))
! DebugBreak();
! #endif
!
! #ifdef DEBUG_BTREE
! if (numentries(node) != 0 && getkey(node, numentries(node)).name == NULL)
! DebugBreak();
! #endif
! for (x = numentries(node); x >= slot && x != 0; x--) /* make room for new entry */
! pushentry(node, x, 1);
! setentry(node, slot, getfunkey(B), downPtr);/* place it in correct slot */
!
! incentries(node); /* adjust entry counter */
! #ifdef DEBUG_BTREE
! if (getkey(node, numentries(node)).name == NULL)
! DebugBreak();
! #endif
!
! if (numentries(node) == getfanout(B))
! setflag(node, isFULL);
! if (numentries(node) > getminfanout(B, node))
! clrflag(node, FEWEST);
! else
! setflag(node, FEWEST);
! }
!
!
! /***************** split full node and set flags *******************/
! static Nptr
! split(Tree *B, Nptr node)
! {
! Nptr sibling;
!
! sibling = getFreeNode(B);
!
! setflag(sibling, FEWEST); /* set up node flags */
!
! if (isleaf(node)) {
! setflag(sibling, isLEAF);
! setnextnode(sibling, getnextnode(node));/* adjust leaf pointers */
! setnextnode(node, sibling);
! }
! if (getsplitpath(B) == node)
! setsplitpath(B, NONODE); /* no more splitting needed */
!
! if (isroot(node))
! clrflag(node, isROOT);
!
! return sibling;
! }
!
!
! /********************** build new root node ************************/
! static void
! makeNewRoot(Tree *B, Nptr oldRoot, Nptr newNode)
! {
! setroot(B, getFreeNode(B));
!
! setfirstnode(getroot(B), oldRoot); /* old root becomes new root's child */
! setentry(getroot(B), 1, getfunkey(B), newNode); /* old root's sibling also */
! incentries(getroot(B));
! #ifdef DEBUG_BTREE
! if (numentries(getroot(B)) > getfanout(B))
! DebugBreak();
! #endif
!
! /* the oldRoot's isROOT flag was cleared in split() */
! setflag(getroot(B), isROOT);
! setflag(getroot(B), FEWEST);
! clrflag(getroot(B), isLEAF);
! inctreeheight(B);
! }
!
!
! /***********************************************************************\
! | Delete data from tree |
! \***********************************************************************/
!
! /********************** top level delete call **********************\
! |
! | The recursive call for deletion carries 5 additional parameters
! | which may be needed to rebalance the B+tree when removing the key.
! | These parameters are:
! | 1. immediate left neighbor of the current node
! | 2. immediate right neighbor of the current node
! | 3. the anchor of the current node and left neighbor
! | 4. the anchor of the current node and right neighbor
! | 5. the parent of the current node
! |
! | All of these parameters are simple to calculate going along the
! | recursive path to the leaf nodes and the point of key deletion.
! | At that time, the algorithm determines which node manipulations
! | are most efficient, that is, cause the least rearranging of data,
! | and minimize the need for non-local key manipulation.
! |
! \***********************************************************************/
! void delete(Tree *B, keyT key)
! {
! Nptr newNode;
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "DELETE: key %s.\n", key.name);
! OutputDebugString(B->message);
! #endif
!
! setfunkey(B, key); /* set deletion key */
! setmergepath(B, NONODE);
! newNode = descendBalance(B, getroot(B), NONODE, NONODE, NONODE, NONODE, NONODE);
! if (isnode(newNode)) {
! #ifdef DEBUG_BTREE
! sprintf(B->message, "DELETE: collapsing node %d", getnodenumber(B, newNode));
! OutputDebugString(B->message);
! #endif
! collapseRoot(B, getroot(B), newNode); /* remove root when superfluous */
! }
! }
!
!
! /********************** remove old root node ***********************/
! static void
! collapseRoot(Tree *B, Nptr oldRoot, Nptr newRoot)
! {
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "COLLAPSE: old %d, new %d.\n", getnodenumber(B, oldRoot), getnodenumber(B, newRoot));
! OutputDebugString(B->message);
! showNode(B, "collapseRoot oldRoot", oldRoot);
! showNode(B, "collapseRoot newRoot", newRoot);
! #endif
!
! setroot(B, newRoot);
! setflag(newRoot, isROOT);
! clrflag(newRoot, FEWEST);
! putFreeNode(B, oldRoot);
! dectreeheight(B); /* the height of the tree decreases */
! }
!
!
! /**************** recurse down and balance back up *****************/
! static Nptr
! descendBalance(Tree *B, Nptr curr, Nptr left, Nptr right, Nptr lAnc, Nptr rAnc, Nptr parent)
! {
! Nptr newMe=NONODE, myLeft=NONODE, myRight=NONODE, lAnchor=NONODE, rAnchor=NONODE, newNode=NONODE;
! int slot = 0, notleft = 0, notright = 0, fewleft = 0, fewright = 0, test = 0;
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "descendBalance curr %d, left %d, right %d, lAnc %d, rAnc %d, parent %d\n",
! curr ? getnodenumber(B, curr) : -1,
! left ? getnodenumber(B, left) : -1,
! right ? getnodenumber(B, right) : -1,
! lAnc ? getnodenumber(B, lAnc) : -1,
! rAnc ? getnodenumber(B, rAnc) : -1,
! parent ? getnodenumber(B, parent) : -1);
! OutputDebugString(B->message);
! #endif
!
! if (!isfew(curr))
! setmergepath(B,NONODE);
! else if (getmergepath(B) == NONODE)
! setmergepath(B, curr); /* mark which nodes may need rebalancing */
!
! slot = getSlot(B, curr);
!
! if (isinternal(curr)) /* set up next recursion call's parameters */
! {
! if (slot == 0) {
! newNode = getfirstnode(curr);
! myLeft = !isnode(left) ? NONODE : getlastnode(left);
! lAnchor = lAnc;
! }
! else {
! newNode = getnode(curr, slot);
! if (slot == 1)
! myLeft = getfirstnode(curr);
! else
! myLeft = getnode(curr, slot - 1);
! lAnchor = curr;
! }
!
! if (slot == numentries(curr)) {
! myRight = !isnode(right) ? NONODE : getfirstnode(right);
! rAnchor = rAnc;
! }
! else {
! myRight = getnode(curr, slot + 1);
! rAnchor = curr;
! }
! newMe = descendBalance(B, newNode, myLeft, myRight, lAnchor, rAnchor, curr);
! }
! else if ((slot > 0) && !comparekeys(B)(getfunkey(B), getkey(curr, slot), 0))
! {
! Nptr next;
! int exact = 0;
! int count = 0;
!
! newNode = getnode(curr, slot);
! next = getdatanext(newNode);
!
! /*
! * We only delete exact matches.
! */
! if (!comparekeys(B)(getfunkey(B), getdatakey(newNode), EXACT_MATCH)) {
! /* exact match, free the first entry */
! setnode(curr, slot, next);
!
! if (next == NONODE) {
! /* delete this key as there are no more data values */
! newMe = newNode;
! } else {
! /* otherwise, there are more and we leave the key in place */
! setnode(curr, slot, next);
! putFreeNode(B, newNode);
!
! /* but do not delete the key */
! newMe = NONODE;
! setmergepath(B, NONODE);
! }
! } else if (next == NONODE) {
! /*
! * we didn't find an exact match and there are no more
! * choices. so we leave it alone and remove nothing.
! */
! newMe = NONODE;
! setmergepath(B, NONODE);
! } else {
! /* The first data node doesn't match but there are other
! * options. So we must determine if any of the next nodes
! * are the one we are looking for.
! */
! Nptr dataNode = newNode;
!
! while ( next ) {
! if (!comparekeys(B)(getfunkey(B), getdatakey(next), EXACT_MATCH)) {
! /* we found the one to delete */
! getdatanext(dataNode) = getdatanext(next);
! putFreeNode(B, next);
! }
! }
!
! /* do not delete the key */
! newMe = NONODE;
! setmergepath(B, NONODE);
! }
! }
! else
! {
! newMe = NONODE; /* no deletion possible, key not found */
! setmergepath(B, NONODE);
! }
!
! /***************** rebalancing tree after deletion *****************\
! |
! | The simplest B+tree rebalancing consists of the following rules.
! |
! | If a node underflows:
! | CASE 1 check if it is the root, and collapse it if it is,
! | CASE 2 otherwise, check if both of its neighbors are minimum
! | sized and merge the underflowing node with one of them,
! | CASE 3 otherwise shift surplus entries to the underflowing node.
! |
! | The choice of which neighbor to use is optional. However, the
! | rebalancing rules that follow also ensure whenever possible
! | that the merges and shifts which do occur use a neighbor whose
! | anchor is the parent of the underflowing node.
! |
! | Cases 3, 4, 5 below are more an optimization than a requirement,
! | and can be omitted, with a change of the action value in case 6,
! | which actually corresponds to the third case described above.
! |
! \***********************************************************************/
!
! /* begin deletion, working upwards from leaves */
!
! if (newMe != NONODE) { /* this node removal doesn't consider duplicates */
! #ifdef DEBUG_BTREE
! sprintf(B->message, "descendBalance DELETE: slot %d, node %d.\n", slot, getnodenumber(B, curr));
! OutputDebugString(B->message);
! #endif
!
! removeEntry(B, curr, slot + (newMe != newNode)); /* removes one of two */
!
! #ifdef DEBUG_BTREE
! showNode(B, "descendBalance curr", curr);
! #endif
! }
!
! if (getmergepath(B) == NONODE)
! newNode = NONODE;
! else { /* tree rebalancing rules for node merges and shifts */
! notleft = !isnode(left);
! notright = !isnode(right);
! if (!notleft)
! fewleft = isfew(left); /* only used when defined */
! if (!notright)
! fewright = isfew(right);
!
! /* CASE 1: prepare root node (curr) for removal */
! if (notleft && notright) {
! test = isleaf(curr); /* check if B+tree has become empty */
! newNode = test ? NONODE : getfirstnode(curr);
! }
! /* CASE 2: the merging of two nodes is a must */
! else if ((notleft || fewleft) && (notright || fewright)) {
! test = (lAnc != parent);
! newNode = test ? merge(B, curr, right, rAnc) : merge(B, left, curr, lAnc);
! }
! /* CASE 3: choose the better of a merge or a shift */
! else if (!notleft && fewleft && !notright && !fewright) {
! test = (rAnc != parent) && (curr == getmergepath(B));
! newNode = test ? merge(B, left, curr, lAnc) : shift(B, curr, right, rAnc);
! }
! /* CASE 4: also choose between a merge or a shift */
! else if (!notleft && !fewleft && !notright && fewright) {
! test = !(lAnc == parent) && (curr == getmergepath(B));
! newNode = test ? merge(B, curr, right, rAnc) : shift(B, left, curr, lAnc);
! }
! /* CASE 5: choose the more effective of two shifts */
! else if (lAnc == rAnc) { /* => both anchors are the parent */
! test = (numentries(left) <= numentries(right));
! newNode = test ? shift(B, curr, right, rAnc) : shift(B, left, curr, lAnc);
! }
! /* CASE 6: choose the shift with more local effect */
! else { /* if omitting cases 3,4,5 use below */
! test = (lAnc == parent); /* test = (!notleft && !fewleft); */
! newNode = test ? shift(B, left, curr, lAnc) : shift(B, curr, right, rAnc);
! }
! }
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "descendBalance returns %d\n", getnodenumber(B, newNode));
! OutputDebugString(B->message);
! #endif
! return newNode;
! }
!
!
! /**************** remove key and pointer from node *****************/
! static void
! removeEntry(Tree *B, Nptr curr, int slot)
! {
! int x;
!
! putFreeNode(B, getnode(curr, slot)); /* return deleted node to free list */
! for (x = slot; x < numentries(curr); x++)
! pullentry(curr, x, 1); /* adjust node with removed key */
! decentries(curr);
! clrflag(curr, isFULL); /* keep flag information up to date */
! if (numentries(curr) > getminfanout(B, curr))
! clrflag(curr, FEWEST);
! else
! setflag(curr, FEWEST);
! }
!
!
! /******* merge a node pair & set emptied node up for removal *******/
! static Nptr
! merge(Tree *B, Nptr left, Nptr right, Nptr anchor)
! {
! int x, y, z;
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "MERGE: left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
! OutputDebugString(B->message);
! showNode(B, "pre-merge anchor", anchor);
! showNode(B, "pre-merge left", left);
! showNode(B, "pre-merge right", right);
! #endif
!
! if (isinternal(left)) {
! incentries(left); /* copy key separating the nodes */
! #ifdef DEBUG_BTREE
! if (numentries(left) > getfanout(B))
! DebugBreak();
! #endif
! setfunkey(B, getkey(right, 1)); /* defined but maybe just deleted */
! z = getSlot(B, anchor); /* needs the just calculated key */
! setfunkey(B, getkey(anchor, z)); /* set slot to delete in anchor */
! setentry(left, numentries(left), getfunkey(B), getfirstnode(right));
! }
! else
! setnextnode(left, getnextnode(right));
!
! for (x = numentries(left) + 1, y = 1; y <= numentries(right); x++, y++) {
! incentries(left);
! #ifdef DEBUG_BTREE
! if (numentries(left) > getfanout(B))
! DebugBreak();
! #endif
! xferentry(right, y, left, x); /* transfer entries to left node */
! }
! clearentries(right);
!
! if (numentries(left) > getminfanout(B, left))
! clrflag(left, FEWEST);
! if (numentries(left) == getfanout(B))
! setflag(left, isFULL); /* never happens in even size nodes */
!
! if (getmergepath(B) == left || getmergepath(B) == right)
! setmergepath(B, NONODE); /* indicate rebalancing is complete */
!
! #ifdef DEBUG_BTREE
! showNode(B, "post-merge anchor", anchor);
! showNode(B, "post-merge left", left);
! showNode(B, "post-merge right", right);
! #endif
! return right;
! }
!
!
! /****** shift entries in a node pair & adjust anchor key value *****/
! static Nptr
! shift(Tree *B, Nptr left, Nptr right, Nptr anchor)
! {
! int i, x, y, z;
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "SHIFT: left %d, right %d, anchor %d.\n",
! getnodenumber(B, left),
! getnodenumber(B, right),
! getnodenumber(B, anchor));
! OutputDebugString(B->message);
! showNode(B, "pre-shift anchor", anchor);
! showNode(B, "pre-shift left", left);
! showNode(B, "pre-shift right", right);
! #endif
!
! i = isinternal(left);
!
! if (numentries(left) < numentries(right)) { /* shift entries to left */
! y = (numentries(right) - numentries(left)) >> 1;
! x = numentries(left) + y;
! setfunkey(B, getkey(right, y + 1 - i)); /* set new anchor key value */
! z = getSlot(B, anchor); /* find slot in anchor node */
! #ifdef DEBUG_BTREE
! if (z == 0 && !isroot(anchor))
! DebugBreak();
! #endif
! if (i) { /* move out old anchor value */
! decentries(right); /* adjust for shifting anchor */
! incentries(left);
! #ifdef DEBUG_BTREE
! if (numentries(left) > getfanout(B))
! DebugBreak();
! #endif
! setentry(left, numentries(left), getkey(anchor, z), getfirstnode(right));
! setfirstnode(right, getnode(right, y + 1 - i));
! }
! clrflag(right, isFULL);
! setkey(anchor, z, getfunkey(B)); /* set new anchor value */
! for (z = y, y -= i; y > 0; y--, x--) {
! decentries(right); /* adjust entry count */
! incentries(left);
! #ifdef DEBUG_BTREE
! if (numentries(left) > getfanout(B))
! DebugBreak();
! #endif
! xferentry(right, y, left, x); /* transfer entries over */
! }
!
! for (x = 1; x <= numentries(right); x++) /* adjust reduced node */
! pullentry(right, x, z);
! }
! else if (numentries(left) > numentries(right)) { /* shift entries to right */
! y = (numentries(left) - numentries(right)) >> 1;
! x = numentries(left) - y + 1;
!
! for (z = numentries(right); z > 0; z--) /* adjust increased node */
! pushentry(right, z, y);
!
! setfunkey(B, getkey(left, x)); /* set new anchor key value */
! z = getSlot(B, anchor) + 1;
! if (i) {
! decentries(left);
! incentries(right);
! #ifdef DEBUG_BTREE
! if (numentries(right) > getfanout(B))
! DebugBreak();
! #endif
! setentry(right, y, getkey(anchor, z), getfirstnode(right));
! setfirstnode(right, getnode(left, x));
! }
! clrflag(left, isFULL);
! setkey(anchor, z, getfunkey(B));
! for (x = numentries(left) + i, y -= i; y > 0; y--, x--) {
! decentries(left);
! incentries(right);
! #ifdef DEBUG_BTREE
! if (numentries(right) > getfanout(B))
! DebugBreak();
! #endif
! xferentry(left, x, right, y); /* transfer entries over */
! clrentry(left, x);
! }
! }
! #ifdef DEBUG_BTREE
! else {
! DebugBreak();
! }
! #endif /* DEBUG_BTREE */
!
! if (numentries(left) > getminfanout(B, left)) /* adjust node flags */
! clrflag(left, FEWEST); /* never happens in 2-3+trees */
! else
! setflag(left, FEWEST);
! if (numentries(right) > getminfanout(B, right))
! clrflag(right, FEWEST); /* never happens in 2-3+trees */
! else
! setflag(right, FEWEST);
! setmergepath(B, NONODE);
!
! #ifdef DEBUG_BTREE
! sprintf(B->message, "SHIFT: left %d, right %d.\n", getnodenumber(B, left), getnodenumber(B, right));
! OutputDebugString(B->message);
! showNode(B, "post-shift anchor", anchor);
! showNode(B, "post-shift left", left);
! showNode(B, "post-shift right", right);
! #endif
!
! return NONODE;
! }
!
!
! static void
! _clrentry(Nptr node, int entry)
! {
! if (getkey(node,entry).name != NULL) {
! free(getkey(node,entry).name);
! getkey(node,entry).name = NULL;
! }
! getnode(node,entry) = NONODE;
! }
!
! static void
! _pushentry(Nptr node, int entry, int offset)
! {
! if (getkey(node,entry + offset).name != NULL)
! free(getkey(node,entry + offset).name);
! #ifdef DEBUG_BTREE
! if (entry == 0)
! DebugBreak();
! #endif
! getkey(node,entry + offset).name = strdup(getkey(node,entry).name);
! #ifdef DEBUG_BTREE
! if ( getnode(node, entry) == NONODE )
! DebugBreak();
! #endif
! getnode(node,entry + offset) = getnode(node,entry);
! }
!
! static void
! _pullentry(Nptr node, int entry, int offset)
! {
! if (getkey(node,entry).name != NULL)
! free(getkey(node,entry).name);
! getkey(node,entry).name = strdup(getkey(node,entry + offset).name);
! #ifdef DEBUG_BTREE
! if ( getnode(node, entry + offset) == NONODE )
! DebugBreak();
! #endif
! getnode(node,entry) = getnode(node,entry + offset);
! }
!
! static void
! _xferentry(Nptr srcNode, int srcEntry, Nptr destNode, int destEntry)
! {
! if (getkey(destNode,destEntry).name != NULL)
! free(getkey(destNode,destEntry).name);
! getkey(destNode,destEntry).name = strdup(getkey(srcNode,srcEntry).name);
! #ifdef DEBUG_BTREE
! if ( getnode(srcNode, srcEntry) == NONODE )
! DebugBreak();
! #endif
! getnode(destNode,destEntry) = getnode(srcNode,srcEntry);
! }
!
! static void
! _setentry(Nptr node, int entry, keyT key, Nptr downNode)
! {
! if (getkey(node,entry).name != NULL)
! free(getkey(node,entry).name);
! getkey(node,entry).name = strdup(key.name);
! #ifdef DEBUG_BTREE
! if ( downNode == NONODE )
! DebugBreak();
! #endif
! getnode(node,entry) = downNode;
! }
!
!
! /***********************************************************************\
! | Empty Node Utilities |
! \***********************************************************************/
!
! /********************* Set up initial pool of free nodes ***********/
! static void
! initFreeNodePool(Tree *B, int quantity)
! {
! int i;
! Nptr n, p;
!
! setfirstallnode(B, NONODE);
! setfirstfreenode(B, NONODE);
!
! for (i = 0, p = NONODE; i < quantity; i++) {
! n = malloc(sizeof(*n));
! memset(n, 0, sizeof(*n));
! setnodenumber(B,n,i);
!
! if (p) {
! setnextnode(p, n); /* insert node into free node list */
! setallnode(p, n);
! } else {
! setfirstfreenode(B, n);
! setfirstallnode(B, n);
! }
! p = n;
! }
! setnextnode(p, NONODE); /* indicates end of free node list */
! setallnode(p, NONODE); /* indicates end of all node list */
!
! setpoolsize(B, quantity);
! }
!
!
! /******************* Cleanup Free Node Pool **************************/
!
! static void
! cleanupNodePool(Tree *B)
! {
! int i, j;
! Nptr node, next;
!
! for ( i=0, node = getfirstallnode(B); node != NONODE && imessage, "- -- -- -- -- -- -- -- -- -- -- -- -\n");
! OutputDebugString(B->message);
! sprintf(B->message, "| %-20s |\n", where);
! OutputDebugString(B->message);
! sprintf(B->message, "| node %6d ", getnodenumber(B, n));
! OutputDebugString(B->message);
! sprintf(B->message, " magic %4x |\n", getmagic(n));
! OutputDebugString(B->message);
! sprintf(B->message, "- -- -- -- -- -- -- -- -- -- -- -- -\n");
! OutputDebugString(B->message);
! sprintf(B->message, "| flags %1d%1d%1d%1d ", isfew(n), isfull(n), isroot(n), isleaf(n));
! OutputDebugString(B->message);
! sprintf(B->message, "| keys = %5d ", numentries(n));
! OutputDebugString(B->message);
! sprintf(B->message, "| node = %6d |\n", getnodenumber(B, getfirstnode(n)));
! OutputDebugString(B->message);
! for (x = 1; x <= numentries(n); x++) {
! sprintf(B->message, "| entry %6d ", x);
! OutputDebugString(B->message);
! sprintf(B->message, "| key = %6s ", getkey(n, x).name);
! OutputDebugString(B->message);
! sprintf(B->message, "| node = %6d |\n", getnodenumber(B, getnode(n, x)));
! OutputDebugString(B->message);
! }
! sprintf(B->message, "- -- -- -- -- -- -- -- -- -- -- -- -\n");
! OutputDebugString(B->message);
! }
!
! /****************** B+tree class variable printer ******************/
! void showBtree(Tree *B)
! {
! sprintf(B->message, "- -- -- -- -- -- -\n");
! OutputDebugString(B->message);
! sprintf(B->message, "| B+tree %10p |\n", (void *) B);
! OutputDebugString(B->message);
! sprintf(B->message, "- -- -- -- -- -- -\n");
! OutputDebugString(B->message);
! sprintf(B->message, "| root %6d |\n", getnodenumber(B, getroot(B)));
! OutputDebugString(B->message);
! sprintf(B->message, "| leaf %6d |\n", getnodenumber(B, getleaf(B)));
! OutputDebugString(B->message);
! sprintf(B->message, "| fanout %3d |\n", getfanout(B) + 1);
! OutputDebugString(B->message);
! sprintf(B->message, "| minfanout %3d |\n", getminfanout(B, getroot(B)) + 1);
! OutputDebugString(B->message);
! sprintf(B->message, "| height %3d |\n", gettreeheight(B));
! OutputDebugString(B->message);
! sprintf(B->message, "| freenode %6d |\n", getnodenumber(B, getfirstfreenode(B)));
! OutputDebugString(B->message);
! sprintf(B->message, "| theKey %6s |\n", getfunkey(B).name);
! OutputDebugString(B->message);
! sprintf(B->message, "| theData %d.%d.%d |\n", getfundata(B).volume,
! getfundata(B).vnode, getfundata(B).unique);
! OutputDebugString(B->message);
! sprintf(B->message, "- -- -- -- -- -- -\n");
! OutputDebugString(B->message);
! }
!
! void
! listBtreeNodes(Tree *B, const char * parent_desc, Nptr node)
! {
! int i;
! char thisnode[64];
! dataT data;
!
! if (isntnode(node)) {
! sprintf(B->message, "%s - NoNode!!!\n");
! OutputDebugString(B->message);
! return;
! }
!
! if (!isnode(node))
! {
! data = getdatavalue(node);
! sprintf(B->message, "%s - data node %d (%d.%d.%d)\n",
! parent_desc, getnodenumber(B, node),
! data.volume, data.vnode, data.unique);
! OutputDebugString(B->message);
! return;
! } else
! showNode(B, parent_desc, node);
!
! if ( isinternal(node) || isroot(node) ) {
! sprintf(thisnode, "parent %6d", getnodenumber(B , node));
!
! OutputDebugString(B->message);
! for ( i= isinternal(node) ? 0 : 1; i <= numentries(node); i++ ) {
! listBtreeNodes(B, thisnode, i == 0 ? getfirstnode(node) : getnode(node, i));
! }
! }
! }
!
! /*********************** B+tree data printer ***********************/
! void
! listBtreeValues(Tree *B, Nptr n, int num)
! {
! int slot;
! keyT prev = {""};
! dataT data;
!
! for (slot = 1; (n != NONODE) && num && numentries(n); num--) {
! if (comparekeys(B)(getkey(n, slot),prev, 0) < 0) {
! sprintf(B->message, "BOMB %8s\n", getkey(n, slot).name);
! OutputDebugString(B->message);
! DebugBreak();
! }
! prev = getkey(n, slot);
! data = getdatavalue(getnode(n, slot));
! sprintf(B->message, "%8s (%d.%d.%d)\n",
! prev.name, data.volume, data.vnode, data.unique);
! OutputDebugString(B->message);
! if (++slot > numentries(n))
! n = getnextnode(n), slot = 1;
! }
! sprintf(B->message, "\n\n");
! OutputDebugString(B->message);
! }
!
! /******************** entire B+tree data printer *******************/
! void
! listAllBtreeValues(Tree *B)
! {
! listBtreeValues(B, getleaf(B), BTERROR);
! }
! #endif /* DEBUG_BTREE */
!
! void
! findAllBtreeValues(Tree *B)
! {
! int num = -1;
! Nptr n = getleaf(B), l;
! int slot;
! keyT prev = {""};
!
! for (slot = 1; (n != NONODE) && num && numentries(n); num--) {
! if (comparekeys(B)(getkey(n, slot),prev, 0) < 0) {
! sprintf(B->message,"BOMB %8s\n", getkey(n, slot).name);
! OutputDebugString(B->message);
! #ifdef DEBUG_BTREE
! DebugBreak();
! #endif
! }
! prev = getkey(n, slot);
! l = bplus_Lookup(B, prev);
! if ( l != n ){
! if (l == NONODE)
! sprintf(B->message,"BOMB %8s cannot be found\n", prev.name);
! else
! sprintf(B->message,"BOMB lookup(%8s) finds wrong node\n", prev.name);
! OutputDebugString(B->message);
! #ifdef DEBUG_BTREE
! DebugBreak();
! #endif
! }
!
! if (++slot > numentries(n))
! n = getnextnode(n), slot = 1;
! }
! }
!
! /*
! * the return must be -1, 0, or 1. stricmp() in MSVC 8.0
! * does not return only those values.
! */
! static int
! compareKeys(keyT key1, keyT key2, int flags)
! {
! int comp;
!
! if (flags & EXACT_MATCH)
! comp = strcmp(key1.name, key2.name);
! else
! comp = stricmp(key1.name, key2.name);
! return (comp < 0 ? -1 : (comp > 0 ? 1 : 0));
! }
!
! /* Look up a file name in directory.
!
! On entry:
! op->scp->dirlock is read locked
!
! On exit:
! op->scp->dirlock is read locked
! */
! int
! cm_BPlusDirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
! {
! int rc = EINVAL;
! keyT key = {entry};
! Nptr leafNode = NONODE;
! LARGE_INTEGER start, end;
!
! if (op->scp->dirBplus == NULL ||
! op->dataVersion != op->scp->dirDataVersion) {
! rc = EINVAL;
! goto done;
! }
!
! QueryPerformanceCounter(&start);
!
! leafNode = bplus_Lookup(op->scp->dirBplus, key);
! if (leafNode != NONODE) {
! int slot;
! Nptr firstDataNode, dataNode, nextDataNode;
! int exact = 0;
! int count = 0;
!
! /* Found a leaf that matches the key via a case-insensitive
! * match. There may be one or more data nodes that match.
! * If we have an exact match, return that.
! * If we have an ambiguous match, return an error.
! * If we have only one inexact match, return that.
! */
! slot = findKey(op->scp->dirBplus, leafNode, 1, numentries(leafNode));
! firstDataNode = getnode(leafNode, slot);
!
! for ( dataNode = firstDataNode; dataNode; dataNode = nextDataNode) {
! count++;
! if (!comparekeys(op->scp->dirBplus)(key, getdatakey(dataNode), EXACT_MATCH) ) {
! exact = 1;
! break;
! }
! nextDataNode = getdatanext(dataNode);
! }
!
! if (exact) {
! *cfid = getdatavalue(dataNode);
! rc = 0;
! bplus_lookup_hits++;
! } else if (count == 1) {
! *cfid = getdatavalue(firstDataNode);
! rc = CM_ERROR_INEXACT_MATCH;
! bplus_lookup_hits_inexact++;
! } else {
! rc = CM_ERROR_AMBIGUOUS_FILENAME;
! bplus_lookup_ambiguous++;
! }
! } else {
! rc = ENOENT;
! bplus_lookup_misses++;
! }
!
! QueryPerformanceCounter(&end);
!
! bplus_lookup_time += (end.QuadPart - start.QuadPart);
!
! done:
! return rc;
! }
!
!
! /*
! On entry:
! op->scp->dirlock is write locked
!
! On exit:
! op->scp->dirlock is write locked
! */
! long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid)
! {
! long rc = 0;
! keyT key = {entry};
! LARGE_INTEGER start, end;
!
! if (op->scp->dirBplus == NULL ||
! op->dataVersion != op->scp->dirDataVersion) {
! rc = EINVAL;
! goto done;
! }
!
! QueryPerformanceCounter(&start);
! bplus_create_entry++;
!
! insert(op->scp->dirBplus, key, *cfid);
!
! QueryPerformanceCounter(&end);
!
! bplus_create_time += (end.QuadPart - start.QuadPart);
!
! done:
!
! return rc;
! }
!
! /*
! On entry:
! op->scp->dirlock is write locked
!
! On exit:
! op->scp->dirlock is write locked
! */
! int cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry)
! {
! long rc = 0;
! keyT key = {entry};
! LARGE_INTEGER start, end;
!
! if (op->scp->dirBplus == NULL ||
! op->dataVersion != op->scp->dirDataVersion) {
! rc = EINVAL;
! goto done;
! }
!
! QueryPerformanceCounter(&start);
!
! bplus_remove_entry++;
!
! if (op->scp->dirBplus) {
! delete(op->scp->dirBplus, key);
! }
!
! QueryPerformanceCounter(&end);
!
! bplus_remove_time += (end.QuadPart - start.QuadPart);
!
! done:
! return rc;
!
! }
!
! static
! int cm_BPlusDirFoo(struct cm_scache *scp, struct cm_dirEntry *dep,
! void *dummy, osi_hyper_t *entryOffsetp)
! {
! keyT key = {dep->name};
! dataT data = {scp->fid.cell, scp->fid.volume, ntohl(dep->fid.vnode), ntohl(dep->fid.unique)};
!
! /* the Write lock is held in cm_BPlusDirBuildTree() */
! insert(scp->dirBplus, key, data);
!
! #ifdef BTREE_DEBUG
! findAllBtreeValues(scp->dirBplus);
! #endif
! return 0;
! }
!
!
! /*
! * scp->dirlock must be writeLocked before call
! *
! * scp->mutex must not be held
! */
! long cm_BPlusDirBuildTree(cm_scache_t *scp, cm_user_t *userp, cm_req_t* reqp)
! {
! long rc = 0;
! osi_hyper_t thyper;
! LARGE_INTEGER start, end;
!
! osi_assert(scp->dirBplus == NULL);
!
! QueryPerformanceCounter(&start);
! bplus_build_tree++;
!
! if (scp->dirBplus == NULL) {
! scp->dirBplus = initBtree(64, MAX_FANOUT, compareKeys);
! }
! if (scp->dirBplus == NULL) {
! rc = ENOMEM;
! } else {
! thyper.LowPart = 0;
! thyper.HighPart = 0;
! rc = cm_ApplyDir(scp, cm_BPlusDirFoo, NULL, &thyper, userp, reqp, NULL);
! }
!
! QueryPerformanceCounter(&end);
!
! bplus_build_time += (end.QuadPart - start.QuadPart);
!
! return rc;
! }
!
! void cm_BPlusDumpStats(void)
! {
! afsi_log("B+ Lookup Hits: %-8d", bplus_lookup_hits);
! afsi_log(" Inexact Hits: %-8d", bplus_lookup_hits_inexact);
! afsi_log(" Ambiguous Hits: %-8d", bplus_lookup_ambiguous);
! afsi_log(" Misses: %-8d", bplus_lookup_misses);
! afsi_log(" Create: %-8d", bplus_create_entry);
! afsi_log(" Remove: %-8d", bplus_remove_entry);
! afsi_log(" Build Tree: %-8d", bplus_build_tree);
! afsi_log(" Free Tree: %-8d", bplus_free_tree);
! afsi_log(" DV Error: %-8d", bplus_dv_error);
!
! afsi_log("B+ Time Lookup: %-16I64d", bplus_lookup_time);
! afsi_log(" Create: %-16I64d", bplus_create_time);
! afsi_log(" Remove: %-16I64d", bplus_remove_time);
! afsi_log(" Build: %-16I64d", bplus_build_time);
! afsi_log(" Free: %-16I64d", bplus_free_time);
! }
! #endif /* USE_BPLUS */
Index: openafs/src/WINNT/afsd/cm_btree.h
diff -c openafs/src/WINNT/afsd/cm_btree.h:1.1.2.2 openafs/src/WINNT/afsd/cm_btree.h:1.1.2.3
*** openafs/src/WINNT/afsd/cm_btree.h:1.1.2.2 Wed Aug 22 12:00:45 2007
--- openafs/src/WINNT/afsd/cm_btree.h Thu Aug 23 23:21:49 2007
***************
*** 1 ****
! /* place holder for B+ tree header */
--- 1,281 ----
! /*
! * Copyright 2007 Secure Endpoints Inc.
! *
! * All Rights Reserved.
! *
! * This software has been released under the terms of the IBM Public
! * License. For details, see the LICENSE file in the top-level source
! * directory or online at http://www.openafs.org/dl/license10.html
! *
! * Thanks to Jan Jannink for B+ tree algorithms.
! */
!
! #ifndef BPLUSTREE_H
! #define BPLUSTREE_H 1
!
! /******** flag bits (5 of 16 used, 11 for magic value) ********/
!
! /* bits set at node creation/split/merge */
! #define isLEAF 0x01
! #define isROOT 0x02
! #define isDATA 0x04
!
! /* bits set at key insertion/deletion */
! #define isFULL 0x08
! #define FEWEST 0x10
! #define FLAGS_MASK 0xFF
!
! /* identifies data as being a B+tree node */
! #define BTREE_MAGIC 0xBEE0BEE0
! #define BTREE_MAGIC_MASK 0xFFFFFFFF
!
!
! /************************* constants ************************/
!
! /* The maximum number of Entrys in one Node */
! #define MAX_FANOUT 9
!
! /* corresponds to a NULL node pointer value */
! #define NONODE NULL
!
! /* special node slot values used in key search */
! #define BTERROR -1
! #define BTUPPER -2
! #define BTLOWER -3
!
!
! /************************* Data Types **********************************/
! typedef struct node *Nptr;
!
! typedef struct key {
! char *name;
! } keyT;
!
! typedef cm_fid_t dataT;
!
! typedef struct entry {
! keyT key;
! Nptr downNode;
! } Entry;
!
! typedef struct inner {
! short pairs;
! Nptr firstNode;
! } Inner;
!
!
! typedef struct leaf {
! short pairs;
! Nptr nextNode;
! } Leaf;
!
! typedef struct data {
! keyT key;
! dataT value;
! Nptr next;
! } Data;
!
! typedef struct node {
! Nptr pool;
! unsigned short number;
! unsigned short flags;
! unsigned long magic;
! union {
! Entry e[MAX_FANOUT]; /* allows access to entry array */
! Inner i;
! Leaf l;
! Data d;
! } X;
! } Node;
!
!
! typedef int (*KeyCmp)(keyT, keyT, int);
! #define EXACT_MATCH 0x01
!
!
! typedef struct tree {
! unsigned int flags; /* tree flags */
! unsigned int poolsize; /* # of nodes allocated for tree */
! Nptr root; /* pointer to root node */
! Nptr leaf; /* pointer to first leaf node in B+tree */
! unsigned int fanout; /* # of pointers to other nodes */
! unsigned int minfanout; /* usually minfanout == ceil(fanout/2) */
! unsigned int height; /* nodes traversed from root to leaves */
! Nptr pool; /* list of all nodes */
! Nptr empty; /* list of empty nodes */
! keyT theKey; /* the key value used in tree operations */
! dataT theData; /* data used for insertions/deletions */
! union { /* nodes to change in insert and delete */
! Nptr split;
! Nptr merge;
! } branch;
! KeyCmp keycmp; /* pointer to function comparing two keys */
! char message[1024];
! } Tree;
!
! #define TREE_FLAGS_MASK 0x01
! #define TREE_FLAG_UNIQUE_KEYS 0x01
!
! /************************* B+ tree Public functions ****************/
! Tree *initBtree(unsigned int poolsz, unsigned int fan, KeyCmp keyCmp);
! void freeBtree(Tree *B);
!
! #ifdef DEBUG_BTREE
! void showNode(Tree *B, const char * str, Nptr node);
! void showBtree(Tree *B);
! void listBtreeValues(Tree *B, Nptr start, int count);
! void listAllBtreeValues(Tree *B);
! void listBtreeNodes(Tree *B, const char * where, Nptr node);
! void findAllBtreeValues(Tree *B);
! #endif
!
! void insert(Tree *B, keyT key, dataT data);
! void delete(Tree *B, keyT key);
! Nptr lookup(Tree *B, keyT key);
!
! /******************* cache manager directory operations ***************/
! int cm_BPlusDirLookup(cm_dirOp_t * op, char *entry, cm_fid_t * cfid);
! long cm_BPlusDirCreateEntry(cm_dirOp_t * op, char *entry, cm_fid_t * cfid);
! int cm_BPlusDirDeleteEntry(cm_dirOp_t * op, char *entry);
! long cm_BPlusDirBuildTree(cm_scache_t *scp, cm_user_t *userp, cm_req_t* reqp);
! void cm_BPlusDumpStats(void);
!
! extern afs_uint32 bplus_free_tree;
! extern afs_uint32 bplus_dv_error;
! extern afs_uint64 bplus_free_time;
!
! /************ Accessor Macros *****************************************/
!
! /* low level definition of Nptr value usage */
! #define nAdr(n) (n)->X
!
! /* access keys and pointers in a node */
! #define getkey(j, q) (nAdr(j).e[(q)].key)
! #define getnode(j, q) (nAdr(j).e[(q)].downNode)
! #define setkey(j, q, v) ((q > 0) ? nAdr(j).e[(q)].key.name = strdup((v).name) : NULL)
! #define setnode(j, q, v) (nAdr(j).e[(q)].downNode = (v))
!
! /* access tree flag values */
! #define settreeflags(B,v) (B->flags |= (v & TREE_FLAGS_MASK))
! #define gettreeflags(B) (B->flags)
! #define cleartreeflags(B) (B->flags = 0);
!
! /* access node flag values */
! #define setflag(j, v) ((j)->flags |= (v & FLAGS_MASK))
! #define clrflag(j, v) ((j)->flags &= ~(v & FLAGS_MASK))
! #define getflags(j) ((j)->flags & FLAGS_MASK)
! #define getmagic(j) ((j)->magic & BTREE_MAGIC_MASK)
! #define clearflags(j) ((j)->flags = 0, (j)->magic = BTREE_MAGIC)
!
!
! /* check that a node is in fact a node */
! #define isnode(j) (((j) != NONODE) && (((j)->magic & BTREE_MAGIC_MASK) == BTREE_MAGIC) && !((j)->flags & isDATA))
! #define isntnode(j) ((j) == NONODE)
!
!
! /* test individual flag values */
! #define isinternal(j) (((j)->flags & isLEAF) == 0)
! #define isleaf(j) (((j)->flags & isLEAF) == isLEAF)
! #define isdata(j) (((j)->flags & isDATA) == isDATA)
! #ifndef DEBUG_BTREE
! #define isroot(j) (((j)->flags & isROOT) == isROOT)
! #define isfull(j) (((j)->flags & isFULL) == isFULL)
! #define isfew(j) (((j)->flags & FEWEST) == FEWEST)
! #else
! #define isroot(j) _isRoot(B, j)
! #define isfew(j) _isFew(B, j)
! #define isfull(j) _isFull(B, j)
! #endif
!
! /* manage number of keys in a node */
! #define numentries(j) (nAdr(j).i.pairs)
! #define clearentries(j) (nAdr(j).i.pairs = 0)
! #define incentries(j) (nAdr(j).i.pairs++)
! #define decentries(j) (nAdr(j).i.pairs--)
!
!
! /* manage first/last node pointers in internal nodes */
! #define setfirstnode(j, v) (nAdr(j).i.firstNode = (v))
! #define getfirstnode(j) (nAdr(j).i.firstNode)
! #define getlastnode(j) (nAdr(j).e[nAdr(j).i.pairs].downNode)
!
!
! /* manage pointers to next nodes in leaf nodes */
! /* also used for free nodes list */
! #define setnextnode(j, v) (nAdr(j).l.nextNode = (v))
! #define getnextnode(j) (nAdr(j).l.nextNode)
!
! /* manage pointers to all nodes list */
! #define setallnode(j, v) ((j)->pool = (v))
! #define getallnode(j) ((j)->pool)
!
! /* manage access to data nodes */
! #define getdata(j) (nAdr(j).d)
! #define getdatavalue(j) (getdata(j).value)
! #define getdatakey(j) (getdata(j).key)
! #define getdatanext(j) (getdata(j).next)
!
! /* shift/transfer entries for insertion/deletion */
! #define clrentry(j, q) _clrentry(j,q)
! #define pushentry(j, q, v) _pushentry(j, q, v)
! #define pullentry(j, q, v) _pullentry(j, q, v)
! #define xferentry(j, q, v, z) _xferentry(j, q, v, z)
! #define setentry(j, q, v, z) _setentry(j, q, v, z)
!
!
! /* access key and data values for B+tree methods */
! /* pass values to getSlot(), descend...() */
! #define getfunkey(B) ((B)->theKey)
! #define getfundata(B) ((B)->theData)
! #define setfunkey(B,v) ((B)->theKey = (v))
! #define setfundata(B,v) ((B)->theData = (v))
!
! /* define number of B+tree nodes for free node pool */
! #define getpoolsize(B) ((B)->poolsize)
! #define setpoolsize(B,v) ((B)->poolsize = (v))
!
! /* locations from which tree access begins */
! #define getroot(B) ((B)->root)
! #define setroot(B,v) ((B)->root = (v))
! #define getleaf(B) ((B)->leaf)
! #define setleaf(B,v) ((B)->leaf = (v))
!
! /* define max/min number of pointers per node */
! #define getfanout(B) ((B)->fanout)
! #define setfanout(B,v) ((B)->fanout = (v) - 1)
! #define getminfanout(B,j) (isroot(j) ? (isleaf(j) ? 0 : 1) : (isleaf(j) ? (B)->fanout - (B)->minfanout: (B)->minfanout))
! #define setminfanout(B,v) ((B)->minfanout = (v) - 1)
!
! /* manage B+tree height */
! #define inittreeheight(B) ((B)->height = 0)
! #define inctreeheight(B) ((B)->height++)
! #define dectreeheight(B) ((B)->height--)
! #define gettreeheight(B) ((B)->height)
!
! /* access pool of free nodes */
! #define getfirstfreenode(B) ((B)->empty)
! #define setfirstfreenode(B,v) ((B)->empty = (v))
!
! /* access all node list */
! #define getfirstallnode(B) ((B)->pool)
! #define setfirstallnode(B,v) ((B)->pool = (v))
!
! /* handle split/merge points during insert/delete */
! #define getsplitpath(B) ((B)->branch.split)
! #define setsplitpath(B,v) ((B)->branch.split = (v))
! #define getmergepath(B) ((B)->branch.merge)
! #define setmergepath(B,v) ((B)->branch.merge = (v))
!
! /* exploit function to compare two B+tree keys */
! #define comparekeys(B) (*(B)->keycmp)
! #define setcomparekeys(B,v) ((B)->keycmp = (v))
!
! /* location containing B+tree class variables */
! #define setbplustree(B,v) ((B) = (Tree *)(v))
!
! /* representation independent node numbering */
! #define setnodenumber(B,v,q) ((v)->number = (q))
! #define getnodenumber(B,v) ((v) != NONODE ? (v)->number : -1)
!
! #endif /* BPLUSTREE_H */
!
Index: openafs/src/WINNT/afsd/cm_dir.c
diff -c openafs/src/WINNT/afsd/cm_dir.c:1.4.4.2 openafs/src/WINNT/afsd/cm_dir.c:1.4.4.4
*** openafs/src/WINNT/afsd/cm_dir.c:1.4.4.2 Thu Aug 2 16:53:51 2007
--- openafs/src/WINNT/afsd/cm_dir.c Tue Aug 28 13:50:06 2007
***************
*** 17,27 ****
--- 17,54 ----
#include
#include
#include "afsd.h"
+ #ifdef USE_BPLUS
+ #include "cm_btree.h"
+ #endif
#include
afs_int32 DErrno;
+ afs_uint32 dir_lookup_hits = 0;
+ afs_uint32 dir_lookup_misses = 0;
+ afs_uint32 dir_create_entry = 0;
+ afs_uint32 dir_remove_entry = 0;
+
+ afs_uint64 dir_lookup_time = 0;
+ afs_uint64 dir_create_time = 0;
+ afs_uint64 dir_remove_time = 0;
+
+ afs_int32 cm_BPlusTrees = 0;
+
+ void cm_DirDumpStats(void)
+ {
+ afsi_log("Dir Lookup Hits: %-8d", dir_lookup_hits);
+ afsi_log(" Misses: %-8d", dir_lookup_misses);
+ afsi_log(" Create: %-8d", dir_create_entry);
+ afsi_log(" Remove: %-8d", dir_remove_entry);
+
+ afsi_log("Dir Times Lookup: %-16I64d", dir_lookup_time);
+ afsi_log(" Create: %-16I64d", dir_create_time);
+ afsi_log(" Remove: %-16I64d", dir_remove_time);
+ }
+
+
/* Local static prototypes */
static long
cm_DirGetBlob(cm_dirOp_t * op,
***************
*** 80,89 ****
entry is a string name.
On entry:
! op->scp->mx is locked
On exit:
! op->scp->mx is locked
None of the directory buffers for op->scp should be locked by the
calling thread.
--- 107,116 ----
entry is a string name.
On entry:
! op->scp->mx is unlocked
On exit:
! op->scp->mx is unlocked
None of the directory buffers for op->scp should be locked by the
calling thread.
***************
*** 93,98 ****
--- 120,126 ----
{
int blobs, firstelt;
int i;
+ LARGE_INTEGER start, end;
cm_dirEntry_t *ep = NULL;
cm_buf_t *entrybuf = NULL;
***************
*** 109,114 ****
--- 137,146 ----
if (*entry == 0)
return EINVAL;
+ QueryPerformanceCounter(&start);
+
+ dir_create_entry++;
+
osi_Log4(afsd_logp, "cm_DirCreateEntry for op 0x%p, name [%s] and fid[%d,%d]",
op, osi_LogSaveString(afsd_logp, entry), cfid->vnode, cfid->unique);
***************
*** 120,139 ****
if (code == 0) {
cm_DirReleasePage(op, &entrybuf, FALSE);
cm_DirReleasePage(op, &prevptrbuf, FALSE);
! return EEXIST;
}
blobs = cm_NameEntries(entry, NULL); /* number of entries required */
firstelt = cm_DirFindBlobs(op, blobs);
if (firstelt < 0) {
osi_Log0(afsd_logp, "cm_DirCreateEntry returning EFBIG");
! return EFBIG; /* directory is full */
}
/* First, we fill in the directory entry. */
code = cm_DirGetBlob(op, firstelt, &entrybuf, &ep);
! if (code != 0)
! return EIO;
ep->flag = CM_DIR_FFIRST;
ep->fid.vnode = htonl(cfid->vnode);
--- 152,175 ----
if (code == 0) {
cm_DirReleasePage(op, &entrybuf, FALSE);
cm_DirReleasePage(op, &prevptrbuf, FALSE);
! code = EEXIST;
! goto done;
}
blobs = cm_NameEntries(entry, NULL); /* number of entries required */
firstelt = cm_DirFindBlobs(op, blobs);
if (firstelt < 0) {
osi_Log0(afsd_logp, "cm_DirCreateEntry returning EFBIG");
! code = EFBIG; /* directory is full */
! goto done;
}
/* First, we fill in the directory entry. */
code = cm_DirGetBlob(op, firstelt, &entrybuf, &ep);
! if (code != 0) {
! code = EIO;
! goto done;
! }
ep->flag = CM_DIR_FFIRST;
ep->fid.vnode = htonl(cfid->vnode);
***************
*** 144,150 ****
code = cm_DirGetPage(op, 0, &dhpbuf, &dhp);
if (code != 0) {
cm_DirReleasePage(op, &entrybuf, TRUE);
! return EIO;
}
i = cm_DirHash(entry);
--- 180,187 ----
code = cm_DirGetPage(op, 0, &dhpbuf, &dhp);
if (code != 0) {
cm_DirReleasePage(op, &entrybuf, TRUE);
! code = EIO;
! goto done;
}
i = cm_DirHash(entry);
***************
*** 157,163 ****
osi_Log0(afsd_logp, "cm_DirCreateEntry returning success");
! return 0;
}
/* Return the length of a directory in pages
--- 194,205 ----
osi_Log0(afsd_logp, "cm_DirCreateEntry returning success");
! code = 0;
! done:
! QueryPerformanceCounter(&end);
!
! dir_create_time += (end.QuadPart - start.QuadPart);
! return code;
}
/* Return the length of a directory in pages
***************
*** 200,209 ****
/* Delete a directory entry.
On entry:
! op->scp->mx is locked
On exit:
! op->scp->mx is locked
None of the directory buffers for op->scp should be locked by the
calling thread.
--- 242,251 ----
/* Delete a directory entry.
On entry:
! op->scp->mx is unlocked
On exit:
! op->scp->mx is unlocked
None of the directory buffers for op->scp should be locked by the
calling thread.
***************
*** 221,228 ****
cm_buf_t *pibuf = NULL;
osi_hyper_t thyper;
unsigned long junk;
-
long code;
osi_Log2(afsd_logp, "cm_DirDeleteEntry for op 0x%p, entry [%s]",
op, osi_LogSaveString(afsd_logp, entry));
--- 263,272 ----
cm_buf_t *pibuf = NULL;
osi_hyper_t thyper;
unsigned long junk;
long code;
+ LARGE_INTEGER start, end;
+
+ QueryPerformanceCounter(&start);
osi_Log2(afsd_logp, "cm_DirDeleteEntry for op 0x%p, entry [%s]",
op, osi_LogSaveString(afsd_logp, entry));
***************
*** 232,240 ****
&pibuf, &previtem);
if (code != 0) {
osi_Log0(afsd_logp, "cm_DirDeleteEntry returning ENOENT");
! return ENOENT;
}
*previtem = firstitem->next;
cm_DirReleasePage(op, &pibuf, TRUE);
--- 276,287 ----
&pibuf, &previtem);
if (code != 0) {
osi_Log0(afsd_logp, "cm_DirDeleteEntry returning ENOENT");
! code = ENOENT;
! goto done;
}
+ dir_remove_entry++;
+
*previtem = firstitem->next;
cm_DirReleasePage(op, &pibuf, TRUE);
***************
*** 252,259 ****
cm_DirFreeBlobs(op, index, nitems);
osi_Log0(afsd_logp, "cm_DirDeleteEntry returning success");
! return 0;
}
/* Find a bunch of contiguous entries; at least nblobs in a row.
--- 299,312 ----
cm_DirFreeBlobs(op, index, nitems);
osi_Log0(afsd_logp, "cm_DirDeleteEntry returning success");
+ code = 0;
! done:
! QueryPerformanceCounter(&end);
!
! dir_remove_time += (end.QuadPart - start.QuadPart);
!
! return code;
}
/* Find a bunch of contiguous entries; at least nblobs in a row.
***************
*** 446,452 ****
* directory header page are allocated, 1 to the page header, 4 to the
* allocation map and 8 to the hash table.
*
! * Called with op->scp->mx
*/
int
cm_DirMakeDir(cm_dirOp_t * op, cm_fid_t * me, cm_fid_t * parent)
--- 499,505 ----
* directory header page are allocated, 1 to the page header, 4 to the
* allocation map and 8 to the hash table.
*
! * Called with op->scp->mx unlocked
*/
int
cm_DirMakeDir(cm_dirOp_t * op, cm_fid_t * me, cm_fid_t * parent)
***************
*** 454,460 ****
int i;
cm_dirHeader_t *dhp = NULL;
cm_buf_t *dhpbuf = NULL;
!
long code;
osi_Log3(afsd_logp, "cm_DirMakeDir for op 0x%p, directory fid[%d, %d]",
--- 507,513 ----
int i;
cm_dirHeader_t *dhp = NULL;
cm_buf_t *dhpbuf = NULL;
! int rc = 0;
long code;
osi_Log3(afsd_logp, "cm_DirMakeDir for op 0x%p, directory fid[%d, %d]",
***************
*** 463,470 ****
parent->vnode, parent->unique);
code = cm_DirGetPage(op, 0, &dhpbuf, &dhp);
! if (code)
! return 1;
dhp->header.pgcount = htons(1);
dhp->header.tag = htons(1234);
--- 516,525 ----
parent->vnode, parent->unique);
code = cm_DirGetPage(op, 0, &dhpbuf, &dhp);
! if (code) {
! rc = 1;
! goto done;
! }
dhp->header.pgcount = htons(1);
dhp->header.tag = htons(1234);
***************
*** 486,501 ****
osi_Log0(afsd_logp, "cm_DirMakeDir returning success");
! return 0;
}
/* Look up a file name in directory.
On entry:
! op->scp->mx is locked
On exit:
! op->scp->mx is locked
None of the directory buffers for op->scp should be locked by the
calling thread.
--- 541,557 ----
osi_Log0(afsd_logp, "cm_DirMakeDir returning success");
! done:
! return rc;
}
/* Look up a file name in directory.
On entry:
! op->scp->mx is unlocked
On exit:
! op->scp->mx is unlocked
None of the directory buffers for op->scp should be locked by the
calling thread.
***************
*** 507,514 ****
cm_buf_t *itembuf = NULL;
unsigned short *previtem = NULL;
cm_buf_t *pibuf = NULL;
-
long code;
osi_Log2(afsd_logp, "cm_DirLookup for op 0x%p, entry[%s]",
op, osi_LogSaveString(afsd_logp, entry));
--- 563,573 ----
cm_buf_t *itembuf = NULL;
unsigned short *previtem = NULL;
cm_buf_t *pibuf = NULL;
long code;
+ LARGE_INTEGER start;
+ LARGE_INTEGER end;
+
+ QueryPerformanceCounter(&start);
osi_Log2(afsd_logp, "cm_DirLookup for op 0x%p, entry[%s]",
op, osi_LogSaveString(afsd_logp, entry));
***************
*** 517,523 ****
&itembuf, &firstitem,
&pibuf, &previtem);
if (code != 0) {
! return ENOENT;
}
cm_DirReleasePage(op, &pibuf, FALSE);
--- 576,584 ----
&itembuf, &firstitem,
&pibuf, &previtem);
if (code != 0) {
! dir_lookup_misses++;
! code = ENOENT;
! goto done;
}
cm_DirReleasePage(op, &pibuf, FALSE);
***************
*** 532,538 ****
osi_Log2(afsd_logp, "cm_DirLookup returning fid[%d,%d]",
cfid->vnode, cfid->unique);
! return 0;
}
/* Look up a file name in directory.
--- 593,607 ----
osi_Log2(afsd_logp, "cm_DirLookup returning fid[%d,%d]",
cfid->vnode, cfid->unique);
! dir_lookup_hits++;
! code = 0;
!
! done:
! QueryPerformanceCounter(&end);
!
! dir_lookup_time += (end.QuadPart - start.QuadPart);
!
! return code;
}
/* Look up a file name in directory.
***************
*** 865,874 ****
*/
long
cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
! cm_dirOp_t * op)
{
long code;
! int i;
osi_Log3(afsd_logp, "Beginning dirOp[0x%p] for scp[0x%p], userp[0x%p]",
op, scp, userp);
--- 934,943 ----
*/
long
cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
! afs_uint32 lockType, cm_dirOp_t * op)
{
long code;
! int i, mxheld = 0;
osi_Log3(afsd_logp, "Beginning dirOp[0x%p] for scp[0x%p], userp[0x%p]",
op, scp, userp);
***************
*** 895,901 ****
--- 964,1036 ----
op->newLength = op->length;
op->dataVersion = scp->dataVersion;
op->newDataVersion = op->dataVersion;
+
+ #ifdef USE_BPLUS
+ lock_ObtainRead(&scp->dirlock);
+ if (!cm_BPlusTrees ||
+ (scp->dirBplus &&
+ scp->dirDataVersion == scp->dataVersion))
+ {
+ int mxheld = 0;
+
+ switch (lockType) {
+ case CM_DIRLOCK_NONE:
+ lock_ReleaseRead(&scp->dirlock);
+ break;
+ case CM_DIRLOCK_READ:
+ /* got it already */
+ break;
+ case CM_DIRLOCK_WRITE:
+ default:
+ lock_ReleaseRead(&scp->dirlock);
+ lock_ObtainWrite(&scp->dirlock);
+ }
+ } else {
+ lock_ReleaseRead(&scp->dirlock);
+ lock_ObtainWrite(&scp->dirlock);
+ if (scp->dirBplus &&
+ scp->dirDataVersion != scp->dataVersion)
+ {
+ bplus_dv_error++;
+ bplus_free_tree++;
+ freeBtree(scp->dirBplus);
+ scp->dirBplus = NULL;
+ scp->dirDataVersion = -1;
+ }
+
+ if (!scp->dirBplus) {
+ cm_BPlusDirBuildTree(scp, userp, reqp);
+ if (scp->dirBplus)
+ scp->dirDataVersion = scp->dataVersion;
+ }
+
+ switch (lockType) {
+ case CM_DIRLOCK_NONE:
+ lock_ReleaseWrite(&scp->dirlock);
+ break;
+ case CM_DIRLOCK_READ:
+ lock_ConvertWToR(&scp->dirlock);
+ break;
+ case CM_DIRLOCK_WRITE:
+ default:
+ /* got it already */;
+ }
+ }
+ #else
+ switch (lockType) {
+ case CM_DIRLOCK_NONE:
+ break;
+ case CM_DIRLOCK_READ:
+ lock_ObtainRead(&scp->dirlock);
+ break;
+ case CM_DIRLOCK_WRITE:
+ default:
+ lock_ObtainWrite(&scp->dirlock);
+ }
+ #endif
+ op->lockType = lockType;
} else {
+
cm_EndDirOp(op);
}
***************
*** 903,909 ****
}
/* Check if it is safe for us to perform local directory updates.
! Called with scp->mx held. */
int
cm_CheckDirOpForSingleChange(cm_dirOp_t * op)
{
--- 1038,1044 ----
}
/* Check if it is safe for us to perform local directory updates.
! Called with scp->mx unlocked. */
int
cm_CheckDirOpForSingleChange(cm_dirOp_t * op)
{
***************
*** 934,940 ****
}
/* End a sequence of directory operations. Called with op->scp->mx
! locked.*/
long
cm_EndDirOp(cm_dirOp_t * op)
{
--- 1069,1075 ----
}
/* End a sequence of directory operations. Called with op->scp->mx
! unlocked.*/
long
cm_EndDirOp(cm_dirOp_t * op)
{
***************
*** 949,958 ****
if (op->dirtyBufCount > 0) {
/* we made changes. We should go through the list of buffers
and update the dataVersion for each. */
-
- lock_ReleaseMutex(&op->scp->mx);
code = buf_ForceDataVersion(op->scp, op->dataVersion, op->newDataVersion);
! lock_ObtainMutex(&op->scp->mx);
}
if (op->scp)
--- 1084,1122 ----
if (op->dirtyBufCount > 0) {
/* we made changes. We should go through the list of buffers
and update the dataVersion for each. */
code = buf_ForceDataVersion(op->scp, op->dataVersion, op->newDataVersion);
!
! #ifdef USE_BPLUS
! /* and update the data version on the B+ tree */
! if (op->scp->dirBplus &&
! op->scp->dirDataVersion == op->dataVersion) {
!
! switch (op->lockType) {
! case CM_DIRLOCK_READ:
! lock_ReleaseRead(&op->scp->dirlock);
! /* fall through ... */
! case CM_DIRLOCK_NONE:
! lock_ObtainWrite(&op->scp->dirlock);
! op->lockType = CM_DIRLOCK_WRITE;
! break;
! case CM_DIRLOCK_WRITE:
! default:
! /* already got it */;
! }
! op->scp->dirDataVersion = op->newDataVersion;
! }
! #endif
! }
!
! switch (op->lockType) {
! case CM_DIRLOCK_NONE:
! break;
! case CM_DIRLOCK_READ:
! lock_ReleaseRead(&op->scp->dirlock);
! break;
! case CM_DIRLOCK_WRITE:
! default:
! lock_ReleaseWrite(&op->scp->dirlock);
}
if (op->scp)
***************
*** 1079,1085 ****
}
! /* NOTE: called with scp->mx NOT held */
static int
cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * bufferp, int flags)
{
--- 1243,1249 ----
}
! /* NOTE: called with scp->mx held or not depending on the flags */
static int
cm_DirOpDelBuffer(cm_dirOp_t * op, cm_buf_t * bufferp, int flags)
{
***************
*** 1178,1187 ****
This should be called before cm_DirGetPage() is called per scp.
On entry:
! scp->mx locked
On exit:
! scp->mx locked
During:
scp->mx may be released
--- 1342,1351 ----
This should be called before cm_DirGetPage() is called per scp.
On entry:
! scp->mx unlocked
On exit:
! scp->mx unlocked
During:
scp->mx may be released
***************
*** 1191,1198 ****
--- 1355,1364 ----
{
long code;
+ lock_ObtainMutex(&op->scp->mx);
code = cm_SyncOp(op->scp, NULL, op->userp, &op->req, PRSFS_LOOKUP,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
+ lock_ReleaseMutex(&op->scp->mx);
osi_Log2(afsd_logp, "cm_DirCheckStatus for op 0x%p returning code 0x%x",
op, code);
***************
*** 1204,1210 ****
cm_DirGetPage() or any other function that returns a locked, held,
directory page buffer.
! Called with scp->mx held
*/
static long
cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified)
--- 1370,1376 ----
cm_DirGetPage() or any other function that returns a locked, held,
directory page buffer.
! Called with scp->mx unlocked
*/
static long
cm_DirReleasePage(cm_dirOp_t * op, cm_buf_t ** bufferpp, int modified)
***************
*** 1215,1221 ****
return EINVAL;
cm_DirOpDelBuffer(op, *bufferpp,
! ((modified ? DIROP_MODIFIED : 0) | DIROP_SCPLOCKED));
buf_Release(*bufferpp);
*bufferpp = NULL;
--- 1381,1387 ----
return EINVAL;
cm_DirOpDelBuffer(op, *bufferpp,
! ((modified ? DIROP_MODIFIED : 0)));
buf_Release(*bufferpp);
*bufferpp = NULL;
***************
*** 1244,1258 ****
should be released via cm_DirReleasePage().
On entry:
! scp->mx locked.
If *bufferpp is non-NULL, then *bufferpp->mx is locked.
On exit:
! scp->mxlocked
If *bufferpp is non-NULL, then *bufferpp->mx is locked.
During:
! scp->mx will be released
*/
static long
--- 1410,1424 ----
should be released via cm_DirReleasePage().
On entry:
! scp->mx unlocked.
If *bufferpp is non-NULL, then *bufferpp->mx is locked.
On exit:
! scp->mx unlocked
If *bufferpp is non-NULL, then *bufferpp->mx is locked.
During:
! scp->mx will be obtained and released
*/
static long
***************
*** 1284,1291 ****
thyper = bufferp->offset;
}
- lock_ReleaseMutex(&op->scp->mx);
-
if (!bufferp || !LargeIntegerEqualTo(thyper, bufferOffset)) {
/* wrong buffer */
--- 1450,1455 ----
***************
*** 1395,1402 ****
_exit:
*bufferpp = bufferp;
- if (op->scp)
- lock_ObtainMutex(&op->scp->mx);
osi_Log1(afsd_logp, "cm_DirGetPage returning code 0x%x", code);
--- 1559,1564 ----
Index: openafs/src/WINNT/afsd/cm_dir.h
diff -c openafs/src/WINNT/afsd/cm_dir.h:1.4.4.2 openafs/src/WINNT/afsd/cm_dir.h:1.4.4.3
*** openafs/src/WINNT/afsd/cm_dir.h:1.4.4.2 Thu Aug 2 16:53:52 2007
--- openafs/src/WINNT/afsd/cm_dir.h Thu Aug 23 23:21:49 2007
***************
*** 101,109 ****
--- 101,114 ----
#define CM_DIROPBUFF_INUSE 0x1
+ #define CM_DIRLOCK_NONE 0x0
+ #define CM_DIRLOCK_READ 0x1
+ #define CM_DIRLOCK_WRITE 0x2
+
/* Used for managing transactional directory operations. Each
instance should only be used by one thread. */
typedef struct cm_dirOp {
+ int lockType;
cm_scache_t * scp;
cm_user_t * userp;
cm_req_t req;
***************
*** 119,131 ****
afs_uint32 dirtyBufCount;
! int nBuffers; /* number of buffers below */
cm_dirOpBuffer_t buffers[CM_DIROP_MAXBUFFERS];
} cm_dirOp_t;
extern long
cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
! cm_dirOp_t * op);
extern int
cm_CheckDirOpForSingleChange(cm_dirOp_t * op);
--- 124,136 ----
afs_uint32 dirtyBufCount;
! afs_uint32 nBuffers; /* number of buffers below */
cm_dirOpBuffer_t buffers[CM_DIROP_MAXBUFFERS];
} cm_dirOp_t;
extern long
cm_BeginDirOp(cm_scache_t * scp, cm_user_t * userp, cm_req_t * reqp,
! afs_uint32 lockType, cm_dirOp_t * op);
extern int
cm_CheckDirOpForSingleChange(cm_dirOp_t * op);
***************
*** 175,178 ****
--- 180,185 ----
extern void
cm_DirEntryListFree(cm_dirEntryList_t ** list);
+ extern void
+ cm_DirDumpStats(void);
#endif /* __CM_DIR_ENV__ */
Index: openafs/src/WINNT/afsd/cm_scache.c
diff -c openafs/src/WINNT/afsd/cm_scache.c:1.35.2.41 openafs/src/WINNT/afsd/cm_scache.c:1.35.2.42
*** openafs/src/WINNT/afsd/cm_scache.c:1.35.2.41 Thu Aug 9 01:33:56 2007
--- openafs/src/WINNT/afsd/cm_scache.c Thu Aug 23 23:21:49 2007
***************
*** 21,26 ****
--- 21,27 ----
#include
#include "afsd.h"
+ #include "cm_btree.h"
/*extern void afsi_log(char *pattern, ...);*/
***************
*** 207,212 ****
--- 208,227 ----
* while we hold the global refcount lock.
*/
cm_FreeAllACLEnts(scp);
+
+ #ifdef USE_BPLUS
+ /* destroy directory Bplus Tree */
+ if (scp->dirBplus) {
+ LARGE_INTEGER start, end;
+ QueryPerformanceCounter(&start);
+ bplus_free_tree++;
+ freeBtree(scp->dirBplus);
+ scp->dirBplus = NULL;
+ QueryPerformanceCounter(&end);
+
+ bplus_free_time += (end.QuadPart - start.QuadPart);
+ }
+ #endif
return 0;
}
***************
*** 299,304 ****
--- 314,322 ----
scp->magic = CM_SCACHE_MAGIC;
lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
+ #ifdef USE_BPLUS
+ lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock");
+ #endif
scp->serverLock = -1;
/* and put it in the LRU queue */
***************
*** 494,499 ****
--- 512,524 ----
scp->cbExpires = 0;
scp->flags &= ~CM_SCACHEFLAG_CALLBACK;
+ #ifdef USE_BPLUS
+ if (scp->dirBplus)
+ freeBtree(scp->dirBplus);
+ scp->dirBplus = NULL;
+ scp->dirDataVersion = -1;
+ lock_FinalizeRWLock(&scp->dirlock);
+ #endif
lock_FinalizeMutex(&scp->mx);
lock_FinalizeRWLock(&scp->bufCreateLock);
}
***************
*** 523,529 ****
scp = scp->allNextp ) {
lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
!
scp->cbServerp = NULL;
scp->cbExpires = 0;
scp->fileLocksH = NULL;
--- 548,556 ----
scp = scp->allNextp ) {
lock_InitializeMutex(&scp->mx, "cm_scache_t mutex");
lock_InitializeRWLock(&scp->bufCreateLock, "cm_scache_t bufCreateLock");
! #ifdef USE_BPLUS
! lock_InitializeRWLock(&scp->dirlock, "cm_scache_t dirlock");
! #endif
scp->cbServerp = NULL;
scp->cbExpires = 0;
scp->fileLocksH = NULL;
***************
*** 537,542 ****
--- 564,573 ----
scp->openShares = 0;
scp->openExcls = 0;
scp->waitCount = 0;
+ #ifdef USE_BPLUS
+ scp->dirBplus = NULL;
+ scp->dirDataVersion = -1;
+ #endif
scp->flags &= ~CM_SCACHEFLAG_WAITING;
}
}
Index: openafs/src/WINNT/afsd/cm_scache.h
diff -c openafs/src/WINNT/afsd/cm_scache.h:1.21.2.13 openafs/src/WINNT/afsd/cm_scache.h:1.21.2.14
*** openafs/src/WINNT/afsd/cm_scache.h:1.21.2.13 Thu Jun 28 00:05:20 2007
--- openafs/src/WINNT/afsd/cm_scache.h Thu Aug 23 23:21:49 2007
***************
*** 193,198 ****
--- 193,205 ----
/* bulk stat progress */
osi_hyper_t bulkStatProgress; /* track bulk stats of large dirs */
+ #ifdef USE_BPLUS
+ /* directory B+ tree */ /* only allocated if is directory */
+ osi_rwlock_t dirlock; /* controls access to dirBplus */
+ afs_uint32 dirDataVersion; /* data version represented by dirBplus */
+ struct tree *dirBplus; /* dirBplus */
+ #endif
+
/* open state */
afs_uint16 openReads; /* open for reading */
afs_uint16 openWrites; /* open for writing */
Index: openafs/src/WINNT/afsd/cm_utils.c
diff -c openafs/src/WINNT/afsd/cm_utils.c:1.11.4.4 openafs/src/WINNT/afsd/cm_utils.c:1.11.4.5
*** openafs/src/WINNT/afsd/cm_utils.c:1.11.4.4 Thu Feb 15 01:02:03 2007
--- openafs/src/WINNT/afsd/cm_utils.c Thu Aug 23 23:21:49 2007
***************
*** 14,19 ****
--- 14,20 ----
#ifndef DJGPP
#include
#include
+ #include
#ifndef EWOULDBLOCK
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EINPROGRESS WSAEINPROGRESS
***************
*** 42,47 ****
--- 43,51 ----
#define ETOOMANYREFS WSAETOOMANYREFS
#define ETIMEDOUT WSAETIMEDOUT
#define ECONNREFUSED WSAECONNREFUSED
+ #ifdef ELOOP
+ #undef ELOOP
+ #endif
#define ELOOP WSAELOOP
#ifdef ENAMETOOLONG
#undef ENAMETOOLONG
***************
*** 60,66 ****
#define EREMOTE WSAEREMOTE
#endif /* EWOULDBLOCK */
#endif /* !DJGPP */
- #include
#include
#include
--- 64,69 ----
Index: openafs/src/WINNT/afsd/cm_vnodeops.c
diff -c openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.38 openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.41
*** openafs/src/WINNT/afsd/cm_vnodeops.c:1.69.2.38 Thu Aug 23 16:43:08 2007
--- openafs/src/WINNT/afsd/cm_vnodeops.c Sun Aug 26 20:05:24 2007
***************
*** 23,28 ****
--- 23,29 ----
#include
#include "afsd.h"
+ #include "cm_btree.h"
#ifdef DEBUG
extern void afsi_log(char *pattern, ...);
***************
*** 590,604 ****
lock_ObtainMutex(&scp->mx);
code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! if (code) {
! lock_ReleaseMutex(&scp->mx);
return code;
- }
! if (scp->fileType != CM_SCACHETYPE_DIRECTORY) {
! lock_ReleaseMutex(&scp->mx);
return CM_ERROR_NOTDIR;
- }
if (retscp) /* if this is a lookup call */
{
--- 591,602 ----
lock_ObtainMutex(&scp->mx);
code = cm_SyncOp(scp, NULL, userp, reqp, PRSFS_LOOKUP,
CM_SCACHESYNC_NEEDCALLBACK | CM_SCACHESYNC_GETSTATUS);
! lock_ReleaseMutex(&scp->mx);
! if (code)
return code;
! if (scp->fileType != CM_SCACHETYPE_DIRECTORY)
return CM_ERROR_NOTDIR;
if (retscp) /* if this is a lookup call */
{
***************
*** 615,642 ****
#else /* !AFS_FREELANCE_CLIENT */
TRUE
#endif
! ) {
! int casefold = sp->caseFold;
! sp->caseFold = 0; /* we have a strong preference for exact matches */
! if ( *retscp = cm_dnlcLookup(scp, sp)) /* dnlc hit */
{
sp->caseFold = casefold;
- lock_ReleaseMutex(&scp->mx);
- return 0;
- }
- sp->caseFold = casefold;
/* see if we can find it using the directory hash tables.
we can only do exact matches, since the hash is case
sensitive. */
{
cm_dirOp_t dirop;
code = ENOENT;
! code = cm_BeginDirOp(scp, userp, reqp, &dirop);
if (code == 0) {
! code = cm_DirLookup(&dirop, sp->searchNamep, &sp->fid);
cm_EndDirOp(&dirop);
}
--- 613,651 ----
#else /* !AFS_FREELANCE_CLIENT */
TRUE
#endif
! )
{
+ int casefold = sp->caseFold;
+ sp->caseFold = 0; /* we have a strong preference for exact matches */
+ if ( *retscp = cm_dnlcLookup(scp, sp)) /* dnlc hit */
+ {
+ sp->caseFold = casefold;
+ return 0;
+ }
sp->caseFold = casefold;
/* see if we can find it using the directory hash tables.
we can only do exact matches, since the hash is case
sensitive. */
{
cm_dirOp_t dirop;
+ #ifdef USE_BPLUS
+ int usedBplus = 0;
+ #endif
code = ENOENT;
! code = cm_BeginDirOp(scp, userp, reqp, CM_DIRLOCK_READ, &dirop);
if (code == 0) {
!
! #ifdef USE_BPLUS
! code = cm_BPlusDirLookup(&dirop, sp->searchNamep, &sp->fid);
! if (code != EINVAL)
! usedBplus = 1;
! else
! #endif
! code = cm_DirLookup(&dirop, sp->searchNamep, &sp->fid);
!
cm_EndDirOp(&dirop);
}
***************
*** 644,657 ****
/* found it */
sp->found = TRUE;
sp->ExactFound = TRUE;
- lock_ReleaseMutex(&scp->mx);
-
*retscp = NULL; /* force caller to call cm_GetSCache() */
-
return 0;
}
}
! }
}
/*
--- 653,676 ----
/* found it */
sp->found = TRUE;
sp->ExactFound = TRUE;
*retscp = NULL; /* force caller to call cm_GetSCache() */
return 0;
}
+ #ifdef USE_BPLUS
+ if (usedBplus) {
+ if (sp->caseFold && code == CM_ERROR_INEXACT_MATCH) {
+ /* found it */
+ sp->found = TRUE;
+ sp->ExactFound = FALSE;
+ *retscp = NULL; /* force caller to call cm_GetSCache() */
+ return 0;
+ }
+
+ return CM_ERROR_NOSUCHFILE;
+ }
+ #endif
}
! }
}
/*
***************
*** 660,667 ****
*/
dirLength = scp->length;
- lock_ReleaseMutex(&scp->mx);
-
bufferp = NULL;
bufferOffset.LowPart = bufferOffset.HighPart = 0;
if (startOffsetp)
--- 679,684 ----
***************
*** 1176,1197 ****
not. */
cm_dirOp_t dirop;
! lock_ObtainMutex(&dscp->mx);
!
! code = cm_BeginDirOp(dscp, userp, reqp, &dirop);
if (code == 0) {
! code = cm_DirLookup(&dirop, namep, &rock.fid);
cm_EndDirOp(&dirop);
}
- lock_ReleaseMutex(&dscp->mx);
-
if (code == 0) {
/* found it */
rock.found = TRUE;
goto haveFid;
}
}
rock.fid.cell = dscp->fid.cell;
--- 1193,1232 ----
not. */
cm_dirOp_t dirop;
+ #ifdef USE_BPLUS
+ int usedBplus = 0;
+ #endif
! code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_READ, &dirop);
if (code == 0) {
! #ifdef USE_BPLUS
! code = cm_BPlusDirLookup(&dirop, namep, &rock.fid);
! if (code != EINVAL)
! usedBplus = 1;
! else
! #endif
! code = cm_DirLookup(&dirop, namep, &rock.fid);
!
cm_EndDirOp(&dirop);
}
if (code == 0) {
/* found it */
rock.found = TRUE;
goto haveFid;
}
+ #ifdef USE_BPLUS
+ if (usedBplus) {
+ if (code == CM_ERROR_INEXACT_MATCH && (flags & CM_FLAG_CASEFOLD)) {
+ /* found it */
+ code = 0;
+ rock.found = TRUE;
+ goto haveFid;
+ }
+
+ return CM_ERROR_NOSUCHFILE;
+ }
+ #endif
}
rock.fid.cell = dscp->fid.cell;
***************
*** 1551,1560 ****
#endif
/* make sure we don't screw up the dir status during the merge */
! lock_ObtainMutex(&dscp->mx);
!
! code = cm_BeginDirOp(dscp, userp, reqp, &dirop);
sflags = CM_SCACHESYNC_STOREDATA;
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags);
lock_ReleaseMutex(&dscp->mx);
--- 1586,1594 ----
#endif
/* make sure we don't screw up the dir status during the merge */
! code = cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
+ lock_ObtainMutex(&dscp->mx);
sflags = CM_SCACHESYNC_STOREDATA;
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, sflags);
lock_ReleaseMutex(&dscp->mx);
***************
*** 1587,1600 ****
else
osi_Log0(afsd_logp, "CALL RemoveFile SUCCESS");
lock_ObtainMutex(&dscp->mx);
cm_dnlcRemove(dscp, namep);
cm_SyncOpDone(dscp, NULL, sflags);
if (code == 0) {
cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 0);
- if (cm_CheckDirOpForSingleChange(&dirop)) {
- cm_DirDeleteEntry(&dirop, namep);
- }
} else if (code == CM_ERROR_NOSUCHFILE) {
/* windows would not have allowed the request to delete the file
* if it did not believe the file existed. therefore, we must
--- 1621,1633 ----
else
osi_Log0(afsd_logp, "CALL RemoveFile SUCCESS");
+ lock_ObtainWrite(&dscp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
lock_ObtainMutex(&dscp->mx);
cm_dnlcRemove(dscp, namep);
cm_SyncOpDone(dscp, NULL, sflags);
if (code == 0) {
cm_MergeStatus(NULL, dscp, &newDirStatus, &volSync, userp, 0);
} else if (code == CM_ERROR_NOSUCHFILE) {
/* windows would not have allowed the request to delete the file
* if it did not believe the file existed. therefore, we must
***************
*** 1602,1610 ****
*/
dscp->cbServerp = NULL;
}
- cm_EndDirOp(&dirop);
lock_ReleaseMutex(&dscp->mx);
return code;
}
--- 1635,1650 ----
*/
dscp->cbServerp = NULL;
}
lock_ReleaseMutex(&dscp->mx);
+ if (code == 0 && cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_DirDeleteEntry(&dirop, namep);
+ #ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&dirop, namep);
+ #endif
+ }
+ cm_EndDirOp(&dirop);
+
return code;
}
***************
*** 1882,1888 ****
fids[fid_count++] = nscp->fid;
}
}
! } else {
cm_ReleaseSCache(tscp);
if (dirScp)
cm_ReleaseSCache(dirScp);
--- 1922,1930 ----
fids[fid_count++] = nscp->fid;
}
}
! }
!
! if (code) {
cm_ReleaseSCache(tscp);
if (dirScp)
cm_ReleaseSCache(dirScp);
***************
*** 1895,1901 ****
osi_Log1(afsd_logp,"cm_NameI code 0x%x", code);
return code;
}
! }
haveComponent = 0; /* component done */
if (dirScp)
cm_ReleaseSCache(dirScp);
--- 1937,1944 ----
osi_Log1(afsd_logp,"cm_NameI code 0x%x", code);
return code;
}
! }
!
haveComponent = 0; /* component done */
if (dirScp)
cm_ReleaseSCache(dirScp);
***************
*** 2602,2616 ****
* that someone who does a chmod will know to wait until our call
* completes.
*/
lock_ObtainMutex(&dscp->mx);
- cm_BeginDirOp(dscp, userp, reqp, &dirop);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
cm_StartCallbackGrantingCall(NULL, &cbReq);
} else {
cm_EndDirOp(&dirop);
}
- lock_ReleaseMutex(&dscp->mx);
if (code) {
return code;
}
--- 2645,2659 ----
* that someone who does a chmod will know to wait until our call
* completes.
*/
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
lock_ObtainMutex(&dscp->mx);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseMutex(&dscp->mx);
if (code == 0) {
cm_StartCallbackGrantingCall(NULL, &cbReq);
} else {
cm_EndDirOp(&dirop);
}
if (code) {
return code;
}
***************
*** 2645,2650 ****
--- 2688,2695 ----
else
osi_Log0(afsd_logp, "CALL CreateFile SUCCESS");
+ lock_ObtainWrite(&dscp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
***************
*** 2682,2693 ****
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
- lock_ObtainMutex(&dscp->mx);
if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
cm_DirCreateEntry(&dirop, namep, &newFid);
}
cm_EndDirOp(&dirop);
- lock_ReleaseMutex(&dscp->mx);
return code;
}
--- 2727,2739 ----
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
cm_DirCreateEntry(&dirop, namep, &newFid);
+ #ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
+ #endif
}
cm_EndDirOp(&dirop);
return code;
}
***************
*** 2747,2761 ****
* data, so that someone who does a chmod on the dir will wait until
* our call completes.
*/
lock_ObtainMutex(&dscp->mx);
- cm_BeginDirOp(dscp, userp, reqp, &dirop);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
cm_StartCallbackGrantingCall(NULL, &cbReq);
} else {
cm_EndDirOp(&dirop);
}
- lock_ReleaseMutex(&dscp->mx);
if (code) {
return code;
}
--- 2793,2807 ----
* data, so that someone who does a chmod on the dir will wait until
* our call completes.
*/
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
lock_ObtainMutex(&dscp->mx);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseMutex(&dscp->mx);
if (code == 0) {
cm_StartCallbackGrantingCall(NULL, &cbReq);
} else {
cm_EndDirOp(&dirop);
}
if (code) {
return code;
}
***************
*** 2790,2795 ****
--- 2836,2843 ----
else
osi_Log0(afsd_logp, "CALL MakeDir SUCCESS");
+ lock_ObtainWrite(&dscp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
***************
*** 2826,2837 ****
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
- lock_ObtainMutex(&dscp->mx);
if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
cm_DirCreateEntry(&dirop, namep, &newFid);
}
cm_EndDirOp(&dirop);
- lock_ReleaseMutex(&dscp->mx);
/* and return error code */
return code;
--- 2874,2886 ----
if (!didEnd)
cm_EndCallbackGrantingCall(NULL, &cbReq, NULL, 0);
if (scp && cm_CheckDirOpForSingleChange(&dirop)) {
cm_DirCreateEntry(&dirop, namep, &newFid);
+ #ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
+ #endif
}
cm_EndDirOp(&dirop);
/* and return error code */
return code;
***************
*** 2855,2866 ****
return CM_ERROR_CROSSDEVLINK;
}
lock_ObtainMutex(&dscp->mx);
- cm_BeginDirOp(dscp, userp, reqp, &dirop);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
if (code != 0)
cm_EndDirOp(&dirop);
- lock_ReleaseMutex(&dscp->mx);
if (code)
return code;
--- 2904,2915 ----
return CM_ERROR_CROSSDEVLINK;
}
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
lock_ObtainMutex(&dscp->mx);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseMutex(&dscp->mx);
if (code != 0)
cm_EndDirOp(&dirop);
if (code)
return code;
***************
*** 2895,2906 ****
--- 2944,2960 ----
else
osi_Log0(afsd_logp, "CALL Link SUCCESS");
+ lock_ObtainWrite(&dscp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
if (cm_CheckDirOpForSingleChange(&dirop)) {
cm_DirCreateEntry(&dirop, namep, &sscp->fid);
+ #ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, namep, &sscp->fid);
+ #endif
}
}
cm_EndDirOp(&dirop);
***************
*** 2929,2940 ****
* so that someone who does a chmod on the dir will wait until our
* call completes.
*/
lock_ObtainMutex(&dscp->mx);
- cm_BeginDirOp(dscp, userp, reqp, &dirop);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
if (code != 0)
cm_EndDirOp(&dirop);
- lock_ReleaseMutex(&dscp->mx);
if (code) {
return code;
}
--- 2983,2994 ----
* so that someone who does a chmod on the dir will wait until our
* call completes.
*/
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
lock_ObtainMutex(&dscp->mx);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseMutex(&dscp->mx);
if (code != 0)
cm_EndDirOp(&dirop);
if (code) {
return code;
}
***************
*** 2967,2972 ****
--- 3021,3028 ----
else
osi_Log0(afsd_logp, "CALL Symlink SUCCESS");
+ lock_ObtainWrite(&dscp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
***************
*** 2978,2983 ****
--- 3034,3042 ----
newFid.unique = newAFSFid.Unique;
cm_DirCreateEntry(&dirop, namep, &newFid);
+ #ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&dirop, namep, &newFid);
+ #endif
}
}
cm_EndDirOp(&dirop);
***************
*** 3019,3039 ****
AFSFetchStatus updatedDirStatus;
AFSVolSync volSync;
struct rx_connection * callp;
! cm_dirOp_t dirOp;
/* before starting the RPC, mark that we're changing the directory data,
* so that someone who does a chmod on the dir will wait until our
* call completes.
*/
lock_ObtainMutex(&dscp->mx);
- cm_BeginDirOp(dscp, userp, reqp, &dirOp);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
if (code) {
! cm_EndDirOp(&dirOp);
! lock_ReleaseMutex(&dscp->mx);
return code;
}
- lock_ReleaseMutex(&dscp->mx);
didEnd = 0;
/* try the RPC now */
--- 3078,3097 ----
AFSFetchStatus updatedDirStatus;
AFSVolSync volSync;
struct rx_connection * callp;
! cm_dirOp_t dirop;
/* before starting the RPC, mark that we're changing the directory data,
* so that someone who does a chmod on the dir will wait until our
* call completes.
*/
+ cm_BeginDirOp(dscp, userp, reqp, CM_DIRLOCK_NONE, &dirop);
lock_ObtainMutex(&dscp->mx);
code = cm_SyncOp(dscp, NULL, userp, reqp, 0, CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseMutex(&dscp->mx);
if (code) {
! cm_EndDirOp(&dirop);
return code;
}
didEnd = 0;
/* try the RPC now */
***************
*** 3061,3078 ****
else
osi_Log0(afsd_logp, "CALL RemoveDir SUCCESS");
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
cm_dnlcRemove(dscp, namep);
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
- if (cm_CheckDirOpForSingleChange(&dirOp)) {
- cm_DirDeleteEntry(&dirOp, namep);
}
- }
- cm_EndDirOp(&dirOp);
lock_ReleaseMutex(&dscp->mx);
/* and return error code */
return code;
}
--- 3119,3144 ----
else
osi_Log0(afsd_logp, "CALL RemoveDir SUCCESS");
+ lock_ObtainWrite(&dscp->dirlock);
+ dirop.lockType = CM_DIRLOCK_WRITE;
lock_ObtainMutex(&dscp->mx);
cm_SyncOpDone(dscp, NULL, CM_SCACHESYNC_STOREDATA);
if (code == 0) {
cm_dnlcRemove(dscp, namep);
cm_MergeStatus(NULL, dscp, &updatedDirStatus, &volSync, userp, 0);
}
lock_ReleaseMutex(&dscp->mx);
+ if (code == 0) {
+ if (cm_CheckDirOpForSingleChange(&dirop)) {
+ cm_DirDeleteEntry(&dirop, namep);
+ #ifdef USE_BPLUS
+ cm_BPlusDirDeleteEntry(&dirop, namep);
+ #endif
+ }
+ }
+ cm_EndDirOp(&dirop);
+
/* and return error code */
return code;
}
***************
*** 3124,3139 ****
return CM_ERROR_RENAME_IDENTICAL;
oneDir = 1;
lock_ObtainMutex(&oldDscp->mx);
cm_dnlcRemove(oldDscp, oldNamep);
cm_dnlcRemove(oldDscp, newNamep);
- cm_BeginDirOp(oldDscp, userp, reqp, &oldDirOp);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
if (code != 0) {
cm_EndDirOp(&oldDirOp);
}
- lock_ReleaseMutex(&oldDscp->mx);
}
else {
/* two distinct dir vnodes */
--- 3190,3205 ----
return CM_ERROR_RENAME_IDENTICAL;
oneDir = 1;
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
lock_ObtainMutex(&oldDscp->mx);
cm_dnlcRemove(oldDscp, oldNamep);
cm_dnlcRemove(oldDscp, newNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseMutex(&oldDscp->mx);
if (code != 0) {
cm_EndDirOp(&oldDirOp);
}
}
else {
/* two distinct dir vnodes */
***************
*** 3150,3208 ****
return CM_ERROR_CROSSDEVLINK;
if (oldDscp->fid.vnode < newDscp->fid.vnode) {
lock_ObtainMutex(&oldDscp->mx);
- cm_BeginDirOp(oldDscp, userp, reqp, &oldDirOp);
cm_dnlcRemove(oldDscp, oldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
if (code != 0)
cm_EndDirOp(&oldDirOp);
- lock_ReleaseMutex(&oldDscp->mx);
if (code == 0) {
lock_ObtainMutex(&newDscp->mx);
- cm_BeginDirOp(newDscp, userp, reqp, &newDirOp);
cm_dnlcRemove(newDscp, newNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
- if (code != 0)
- cm_EndDirOp(&newDirOp);
lock_ReleaseMutex(&newDscp->mx);
if (code) {
/* cleanup first one */
lock_ObtainMutex(&oldDscp->mx);
cm_SyncOpDone(oldDscp, NULL,
CM_SCACHESYNC_STOREDATA);
- cm_EndDirOp(&oldDirOp);
lock_ReleaseMutex(&oldDscp->mx);
}
}
}
else {
/* lock the new vnode entry first */
lock_ObtainMutex(&newDscp->mx);
- cm_BeginDirOp(newDscp, userp, reqp, &newDirOp);
cm_dnlcRemove(newDscp, newNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
if (code != 0)
cm_EndDirOp(&newDirOp);
- lock_ReleaseMutex(&newDscp->mx);
if (code == 0) {
lock_ObtainMutex(&oldDscp->mx);
- cm_BeginDirOp(oldDscp, userp, reqp, &oldDirOp);
cm_dnlcRemove(oldDscp, oldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
if (code != 0)
cm_EndDirOp(&oldDirOp);
- lock_ReleaseMutex(&oldDscp->mx);
if (code) {
/* cleanup first one */
lock_ObtainMutex(&newDscp->mx);
cm_SyncOpDone(newDscp, NULL,
CM_SCACHESYNC_STOREDATA);
- cm_EndDirOp(&newDirOp);
lock_ReleaseMutex(&newDscp->mx);
}
}
}
--- 3216,3274 ----
return CM_ERROR_CROSSDEVLINK;
if (oldDscp->fid.vnode < newDscp->fid.vnode) {
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
lock_ObtainMutex(&oldDscp->mx);
cm_dnlcRemove(oldDscp, oldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseMutex(&oldDscp->mx);
if (code != 0)
cm_EndDirOp(&oldDirOp);
if (code == 0) {
+ cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
lock_ObtainMutex(&newDscp->mx);
cm_dnlcRemove(newDscp, newNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
lock_ReleaseMutex(&newDscp->mx);
if (code) {
+ cm_EndDirOp(&newDirOp);
+
/* cleanup first one */
lock_ObtainMutex(&oldDscp->mx);
cm_SyncOpDone(oldDscp, NULL,
CM_SCACHESYNC_STOREDATA);
lock_ReleaseMutex(&oldDscp->mx);
+ cm_EndDirOp(&oldDirOp);
}
}
}
else {
/* lock the new vnode entry first */
+ cm_BeginDirOp(newDscp, userp, reqp, CM_DIRLOCK_NONE, &newDirOp);
lock_ObtainMutex(&newDscp->mx);
cm_dnlcRemove(newDscp, newNamep);
code = cm_SyncOp(newDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseMutex(&newDscp->mx);
if (code != 0)
cm_EndDirOp(&newDirOp);
if (code == 0) {
+ cm_BeginDirOp(oldDscp, userp, reqp, CM_DIRLOCK_NONE, &oldDirOp);
lock_ObtainMutex(&oldDscp->mx);
cm_dnlcRemove(oldDscp, oldNamep);
code = cm_SyncOp(oldDscp, NULL, userp, reqp, 0,
CM_SCACHESYNC_STOREDATA);
+ lock_ReleaseMutex(&oldDscp->mx);
if (code != 0)
cm_EndDirOp(&oldDirOp);
if (code) {
/* cleanup first one */
lock_ObtainMutex(&newDscp->mx);
cm_SyncOpDone(newDscp, NULL,
CM_SCACHESYNC_STOREDATA);
lock_ReleaseMutex(&newDscp->mx);
+ cm_EndDirOp(&newDirOp);
}
}
}
***************
*** 3245,3292 ****
osi_Log0(afsd_logp, "CALL Rename SUCCESS");
/* update the individual stat cache entries for the directories */
lock_ObtainMutex(&oldDscp->mx);
cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
! if (code == 0) {
cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
userp, 0);
if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
! diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
if (diropCode == 0) {
if (oneDir) {
diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
}
! if (diropCode == 0) {
diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
! }
}
}
}
cm_EndDirOp(&oldDirOp);
- lock_ReleaseMutex(&oldDscp->mx);
/* and update it for the new one, too, if necessary */
if (!oneDir) {
lock_ObtainMutex(&newDscp->mx);
cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
! if (code == 0) {
cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
userp, 0);
/* we only make the local change if we successfully made
the change in the old directory AND there was only one
change in the new directory */
if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) {
cm_DirCreateEntry(&newDirOp, newNamep, &fileFid);
}
}
cm_EndDirOp(&newDirOp);
- lock_ReleaseMutex(&newDscp->mx);
}
/* and return error code */
--- 3311,3379 ----
osi_Log0(afsd_logp, "CALL Rename SUCCESS");
/* update the individual stat cache entries for the directories */
+ lock_ObtainWrite(&oldDscp->dirlock);
+ oldDirOp.lockType = CM_DIRLOCK_WRITE;
lock_ObtainMutex(&oldDscp->mx);
cm_SyncOpDone(oldDscp, NULL, CM_SCACHESYNC_STOREDATA);
! if (code == 0)
cm_MergeStatus(NULL, oldDscp, &updatedOldDirStatus, &volSync,
userp, 0);
+ lock_ReleaseMutex(&oldDscp->mx);
+ if (code == 0) {
if (cm_CheckDirOpForSingleChange(&oldDirOp)) {
! #ifdef USE_BPLUS
! diropCode = cm_BPlusDirLookup(&oldDirOp, oldNamep, &fileFid);
! if (diropCode == CM_ERROR_INEXACT_MATCH)
! diropCode = 0;
! else if (diropCode == EINVAL)
! #endif
! diropCode = cm_DirLookup(&oldDirOp, oldNamep, &fileFid);
if (diropCode == 0) {
if (oneDir) {
diropCode = cm_DirCreateEntry(&oldDirOp, newNamep, &fileFid);
+ #ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&oldDirOp, newNamep, &fileFid);
+ #endif
}
! if (diropCode == 0) {
diropCode = cm_DirDeleteEntry(&oldDirOp, oldNamep);
! #ifdef USE_BPLUS
! cm_BPlusDirDeleteEntry(&oldDirOp, oldNamep);
! #endif
! }
}
}
}
cm_EndDirOp(&oldDirOp);
/* and update it for the new one, too, if necessary */
if (!oneDir) {
+ lock_ObtainWrite(&newDscp->dirlock);
+ newDirOp.lockType = CM_DIRLOCK_WRITE;
lock_ObtainMutex(&newDscp->mx);
cm_SyncOpDone(newDscp, NULL, CM_SCACHESYNC_STOREDATA);
! if (code == 0)
cm_MergeStatus(NULL, newDscp, &updatedNewDirStatus, &volSync,
userp, 0);
+ lock_ReleaseMutex(&newDscp->mx);
+ if (code == 0) {
/* we only make the local change if we successfully made
the change in the old directory AND there was only one
change in the new directory */
if (diropCode == 0 && cm_CheckDirOpForSingleChange(&newDirOp)) {
cm_DirCreateEntry(&newDirOp, newNamep, &fileFid);
+ #ifdef USE_BPLUS
+ cm_BPlusDirCreateEntry(&newDirOp, newNamep, &fileFid);
+ #endif
}
}
cm_EndDirOp(&newDirOp);
}
/* and return error code */
Index: openafs/src/WINNT/afsd/lock.txt
diff -c openafs/src/WINNT/afsd/lock.txt:1.2 openafs/src/WINNT/afsd/lock.txt:1.2.32.1
*** openafs/src/WINNT/afsd/lock.txt:1.2 Sat Nov 4 05:01:43 2000
--- openafs/src/WINNT/afsd/lock.txt Thu Aug 23 23:21:49 2007
***************
*** 15,20 ****
--- 15,22 ----
- smb_fid_t mutex
+ - scache dirlock
+
- scache flags (storing, fetching, etc); if set for more than one
vnode in a volume, must be set in vnode order (see cm_Rename).
Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm
diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm:1.5.4.18 openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm:1.5.4.19
*** openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm:1.5.4.18 Thu Aug 23 13:13:15 2007
--- openafs/src/WINNT/doc/install/Documentation/en_US/html/index.htm Tue Aug 28 13:52:01 2007
***************
*** 57,63 ****
OpenAFS for Windows
! Version 1.5.23
--- 57,63 ----
OpenAFS for Windows
! Version 1.5.24
***************
*** 80,86 ****
·
OpenAFS for Windows 1.5.23
Release Notes
--- 80,86 ----
·
OpenAFS for Windows 1.5.24
Release Notes
Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm
diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm:1.1.6.18 openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm:1.1.6.19
*** openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm:1.1.6.18 Thu Aug 23 13:13:20 2007
--- openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/logo.htm Tue Aug 28 13:52:05 2007
***************
*** 18,24 ****
.shape {behavior:url(#default#VML);}
!
OpenAFS for Windows 1.5.23 Release Notes
! OpenAFS for Windows 1.5.24 Release Notes
! OpenAFS for Windows 1.5.23 Release Notes
! OpenAFS for Windows 1.5.24 Release Notes
! OpenAFS for Windows 1.5.23
Release Notes
The Andrew File System (AFS) is a location-independent
--- 586,592 ----
!
OpenAFS for Windows 1.5.24
Release Notes
The Andrew File System (AFS) is a location-independent
Index: openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm
diff -c openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm:1.2.6.17 openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm:1.2.6.18
*** openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm:1.2.6.17 Thu Aug 23 13:13:21 2007
--- openafs/src/WINNT/doc/install/Documentation/en_US/html/ReleaseNotes/toc.htm Tue Aug 28 13:52:06 2007
***************
*** 10,16 ****
<