#include "afs/afs_osidnlc.h"
/* Forward declarations. */
-static void afs_GetDownD(int anumber, int *aneedSpace);
+static void afs_GetDownD(int anumber, int *aneedSpace, afs_int32 buckethint);
static void afs_FreeDiscardedDCache(void);
static void afs_DiscardDCache(struct dcache *);
static void afs_FreeDCache(struct dcache *);
+/* For split cache */
+static afs_int32 afs_DCGetBucket(struct vcache *);
+static void afs_DCAdjustSize(struct dcache *, afs_int32, afs_int32);
+static void afs_DCMoveBucket(struct dcache *, afs_int32, afs_int32);
+static void afs_DCSizeInit(void);
+static afs_int32 afs_DCWhichBucket(afs_int32, afs_int32);
+
/*
* --------------------- Exported definitions ---------------------
*/
+/* For split cache */
+afs_int32 afs_blocksUsed_0; /*1K blocks in cache - in theory is zero */
+afs_int32 afs_blocksUsed_1; /*1K blocks in cache */
+afs_int32 afs_blocksUsed_2; /*1K blocks in cache */
+afs_int32 afs_pct1 = -1;
+afs_int32 afs_pct2 = -1;
+afs_uint32 afs_tpct1 = 0;
+afs_uint32 afs_tpct2 = 0;
+afs_uint32 splitdcache = 0;
+
afs_lock_t afs_xdcache; /*Lock: alloc new disk cache entries */
afs_int32 afs_freeDCList; /*Free list for disk cache entries */
afs_int32 afs_freeDCCount; /*Count of elts in freeDCList */
int cacheDiskType; /*Type of backing disk for cache */
struct afs_cacheOps *afs_cacheType;
+static afs_int32
+afs_DCGetBucket(struct vcache *avc)
+{
+ /* This should be replaced with some sort of user configurable function */
+ if (avc->states & CRO) {
+ return 2;
+ } else if (avc->states & CBackup) {
+ return 1;
+ } else {
+ /* RW */
+ }
+ /* main bucket */
+ return 1;
+}
+
+static void
+afs_DCAdjustSize(struct dcache *adc, afs_int32 oldSize, afs_int32 newSize)
+{
+ afs_int32 adjustSize = newSize - oldSize;
+
+ if (!splitdcache)
+ return;
+
+ switch (adc->bucket)
+ {
+ case 0:
+ afs_blocksUsed_0 += adjustSize;
+ afs_stats_cmperf.cacheBucket0_Discarded += oldSize;
+ break;
+ case 1:
+ afs_blocksUsed_1 += adjustSize;
+ afs_stats_cmperf.cacheBucket1_Discarded += oldSize;
+ break;
+ case 2:
+ afs_blocksUsed_2 += adjustSize;
+ afs_stats_cmperf.cacheBucket2_Discarded += oldSize;
+ break;
+ }
+
+ return;
+}
+
+static void
+afs_DCMoveBucket(struct dcache *adc, afs_int32 size, afs_int32 newBucket)
+{
+ if (!splitdcache)
+ return;
+
+ switch (adc->bucket)
+ {
+ case 0:
+ afs_blocksUsed_0 -= size;
+ break;
+ case 1:
+ afs_blocksUsed_1 -= size;
+ break;
+ case 2:
+ afs_blocksUsed_2 -= size;
+ break;
+ }
+
+ adc->bucket = newBucket;
+
+ switch (adc->bucket)
+ {
+ case 0:
+ afs_blocksUsed_0 += size;
+ break;
+ case 1:
+ afs_blocksUsed_1 += size;
+ break;
+ case 2:
+ afs_blocksUsed_2 += size;
+ break;
+ }
+
+ return;
+}
+
+static void
+afs_DCSizeInit(void)
+{
+ afs_blocksUsed_0 = afs_blocksUsed_1 = afs_blocksUsed_2 = 0;
+}
+
+static afs_int32
+afs_DCWhichBucket(afs_int32 phase, afs_int32 bucket)
+{
+ if (!splitdcache)
+ return 0;
+ afs_pct1 = afs_blocksUsed_1*100/afs_cacheBlocks;
+ afs_pct2 = afs_blocksUsed_2*100/afs_cacheBlocks;
+
+ /* Short cut: if we don't know about it, try to kill it */
+ if (phase < 2 && afs_blocksUsed_0)
+ return 0;
+
+ if (afs_pct1 > afs_tpct1)
+ return 1;
+ if (afs_pct2 > afs_tpct2)
+ return 2;
+ return 0; /* unlikely */
+}
/*
afs_blocksUsed - afs_blocksDiscarded - cb_lowat;
slots_needed =
dc_hiwat - afs_freeDCCount - afs_discardDCCount;
- afs_GetDownD(slots_needed, &space_needed);
+ afs_GetDownD(slots_needed, &space_needed, 0);
if ((space_needed <= 0) && (slots_needed <= 0)) {
break;
}
if (!newSize)
adc->validPos = 0;
newSize = ((newSize + afs_fsfragsize) ^ afs_fsfragsize) >> 10; /* round up */
+ afs_DCAdjustSize(adc, oldSize, newSize);
if (newSize > oldSize) {
/* We're growing the file, wakeup the daemon */
afs_MaybeWakeupTruncateDaemon();
#define MAXATONCE 16 /* max we can obtain at once */
static void
-afs_GetDownD(int anumber, int *aneedSpace)
+afs_GetDownD(int anumber, int *aneedSpace, afs_int32 buckethint)
{
struct dcache *tdc;
afs_hyper_t maxVictimTime; /* youngest (largest LRU time) victim */
afs_uint32 maxVictimPtr; /* where it is */
int discard;
+ int curbucket;
AFS_STATCNT(afs_GetDownD);
if (CheckLock(&afs_xdcache) != -1)
if (anumber > MAXATONCE)
anumber = MAXATONCE; /* all we can do */
+ /* rewrite so phases include a better eligiblity for gc test*/
/*
* The phase variable manages reclaims. Set to 0, the first pass,
- * we don't reclaim active entries. Set to 1, we reclaim even active
- * ones.
+ * we don't reclaim active entries, or other than target bucket.
+ * Set to 1, we reclaim even active ones in target bucket.
+ * Set to 2, we reclaim any inactive one.
+ * Set to 3, we reclaim even active ones.
*/
- phase = 0;
+ if (splitdcache) {
+ phase = 0;
+ } else {
+ phase = 4;
+ }
+
for (i = 0; i < afs_cacheFiles; i++)
/* turn off all flags */
afs_indexFlags[i] &= ~IFFlag;
/* find oldest entries for reclamation */
maxVictimPtr = victimPtr = 0;
hzero(maxVictimTime);
+ curbucket = afs_DCWhichBucket(phase, buckethint);
/* select victims from access time array */
for (i = 0; i < afs_cacheFiles; i++) {
if (afs_indexFlags[i] & (IFDataMod | IFFree | IFDiscarded)) {
continue;
}
tdc = afs_indexTable[i];
+ if (tdc && (curbucket != tdc->bucket) && (phase < 4))
+ {
+ /* Wrong bucket; can't use it! */
+ continue;
+ }
if (tdc && (tdc->refCount != 0)) {
/* Referenced; can't use it! */
continue;
if (tvc) {
tchunkoffset = AFS_CHUNKTOBASE(tdc->f.chunk);
chunkFlags = afs_indexFlags[tdc->index];
- if (phase == 0 && osi_Active(tvc))
- skip = 1;
- if (phase > 0 && osi_Active(tvc)
- && (tvc->states & CDCLock)
- && (chunkFlags & IFAnyPages))
- skip = 1;
+ if ((((phase / 2) & 1) == 0) && osi_Active(tvc))
+ skip = 1;
+ if ((((phase / 2) & 1) == 1) && osi_Active(tvc)
+ && (tvc->states & CDCLock)
+ && (chunkFlags & IFAnyPages))
+ skip = 1;
if (chunkFlags & IFDataMod)
skip = 1;
afs_Trace4(afs_iclSetp, CM_TRACE_GETDOWND,
ICL_TYPE_POINTER, tvc, ICL_TYPE_INT32, 3,
ICL_TYPE_INT32, tdc->index, ICL_TYPE_OFFSET,
ICL_HANDLE_OFFSET(tchunkoffset));
-#ifndef AFS_DEC_ENV
AFS_STATCNT(afs_gget);
-#endif
afs_HashOutDCache(tdc);
if (tdc->f.chunkBytes != 0) {
discard = 1;
afs_PutDCache(tdc);
}
- if (phase == 0) {
+ if (phase < 5) {
/* Phase is 0 and no one was found, so try phase 1 (ignore
* osi_Active flag) */
if (j == 0) {
- phase = 1;
+ phase++;
for (i = 0; i < afs_cacheFiles; i++)
/* turn off all flags */
afs_indexFlags[i] &= ~IFFlag;
}
} else {
- /* found no one in phase 1, we're hosed */
+ /* found no one in phases 0-5, we're hosed */
if (victimPtr == 0)
break;
}
{
int i, us;
-#ifndef AFS_DEC_ENV
AFS_STATCNT(afs_glink);
-#endif
/* we know this guy's in the LRUQ. We'll move dude into DCQ below */
DZap(adc);
/* if this guy is in the hash table, pull him out */
afs_CFileTruncate(tfile, 0);
afs_CFileClose(tfile);
afs_AdjustSize(tdc, 0);
+ tdc->f.states &= ~(DRO|DBackup|DRW);
+ afs_DCMoveBucket(tdc, 0, 0);
/*
* Free the element we just truncated
#endif
}
- tdc->stamp = 0;
-#ifdef IHINT
- if (tdc->ihint) {
- struct osi_file *f = (struct osi_file *)tdc->ihint;
- tdc->ihint = 0;
- afs_UFSClose(f);
- nihints--;
- }
-#endif /* IHINT */
-
-
/* finally put the entry in the free list */
afs_indexTable[ix] = NULL;
afs_indexFlags[ix] &= ~IFEverUsed;
break; /* leaving refCount high for caller */
}
afs_PutDCache(tdc);
+ tdc = NULL;
}
index = afs_dcnextTbl[index];
}
updateV2DC(int lockVc, struct vcache *v, struct dcache *d, int src)
{
if (!lockVc || 0 == NBObtainWriteLock(&v->lock, src)) {
- if (hsame(v->m.DataVersion, d->f.versionNo) && v->callback) {
- v->quick.dc = d;
- v->quick.stamp = d->stamp = MakeStamp();
- v->quick.minLoc = AFS_CHUNKTOBASE(d->f.chunk);
- /* Don't think I need these next two lines forever */
- v->quick.len = d->f.chunkBytes;
- v->h1.dchint = d;
- }
+ if (hsame(v->m.DataVersion, d->f.versionNo) && v->callback)
+ v->dchint = d;
if (lockVc)
ReleaseWriteLock(&v->lock);
}
shortcut = 0;
/* check hints first! (might could use bcmp or some such...) */
- if ((tdc = avc->h1.dchint)) {
+ if ((tdc = avc->dchint)) {
int dcLocked;
/*
while (1) {
if (!setLocks)
avc->states |= CDCLock;
- afs_GetDownD(5, (int *)0); /* just need slots */
+ /* just need slots */
+ afs_GetDownD(5, (int *)0, afs_DCGetBucket(avc));
if (!setLocks)
avc->states &= ~CDCLock;
if (afs_discardDCList != NULLIDX
size =
((tdc->f.chunkBytes +
afs_fsfragsize) ^ afs_fsfragsize) >> 10;
+ tdc->f.states &= ~(DRO|DBackup|DRW);
+ afs_DCMoveBucket(tdc, size, 0);
afs_blocksDiscarded -= size;
afs_stats_cmperf.cacheBlocksDiscarded = afs_blocksDiscarded;
if (aflags & 2) {
*/
afs_indexFlags[tdc->index] &= ~(IFDirtyPages | IFAnyPages);
tdc->f.fid = avc->fid;
+ if (avc->states & CRO)
+ tdc->f.states = DRO;
+ else if (avc->states & CBackup)
+ tdc->f.states = DBackup;
+ else
+ tdc->f.states = DRW;
+ afs_DCMoveBucket(tdc, 0, afs_DCGetBucket(avc));
afs_indexUnique[tdc->index] = tdc->f.fid.Fid.Unique;
hones(tdc->f.versionNo); /* invalid value */
tdc->f.chunk = chunk;
afs_dvhashTbl[i] = tdc->index;
tdc->dflags = DFEntryMod;
tdc->mflags = 0;
- tdc->f.states = 0;
afs_MaybeWakeupTruncateDaemon();
MReleaseWriteLock(&afs_xdcache);
ConvertWToSLock(&tdc->lock);
#endif /* AFS_SGI_ENV */
if (AFS_CHUNKTOBASE(chunk) + adjustsize >= avc->m.Length &&
#else /* defined(AFS_AIX32_ENV) || defined(AFS_SGI_ENV) */
-#if defined(AFS_SUN_ENV) || defined(AFS_OSF_ENV)
+#if defined(AFS_SUN5_ENV) || defined(AFS_OSF_ENV)
if ((doAdjustSize || (AFS_CHUNKTOBASE(chunk) >= avc->m.Length)) &&
#else
if (AFS_CHUNKTOBASE(chunk) >= avc->m.Length &&
* fetch the whole file.
*/
DZap(tdc); /* pages in cache may be old */
-#ifdef IHINT
- if (file = tdc->ihint) {
- if (tdc->f.inode == file->inum)
- usedihint++;
- else {
- tdc->ihint = 0;
- afs_UFSClose(file);
- file = 0;
- nihints--;
- file = osi_UFSOpen(tdc->f.inode);
- }
- } else
-#endif /* IHINT */
- file = afs_CFileOpen(tdc->f.inode);
+ file = afs_CFileOpen(tdc->f.inode);
afs_RemoveVCB(&avc->fid);
tdc->f.states |= DWriting;
tdc->dflags |= DFFetching;
if (vType(avc) == VDIR) {
DZap(tdc);
}
+ tdc->f.states &= ~(DRO|DBackup|DRW);
+ afs_DCMoveBucket(tdc, 0, 0);
ReleaseWriteLock(&tdc->lock);
afs_PutDCache(tdc);
ObtainWriteLock(&afs_xcbhash, 454);
* avc->lock(W); assert(!setLocks || slowPass)
*/
osi_Assert(!setLocks || slowPass);
+ tdc->f.states &= ~(DRO|DBackup|DRW);
+ afs_DCMoveBucket(tdc, 0, 0);
tdc = NULL;
goto done;
}
} else {
tdc = tmpdc;
tdc->f.states = 0;
- tdc->ihint = 0;
}
/*
#endif
lasterrtime = osi_Time();
afs_indexUnique[aslot] = tdc->f.fid.Fid.Unique;
+ tdc->f.states &= ~(DRO|DBackup|DRW);
+ afs_DCMoveBucket(tdc, 0, 0);
+ } else {
+ if (&tdc->f != 0) {
+ if (tdc->f.states & DRO) {
+ afs_DCMoveBucket(tdc, 0, 2);
+ } else if (tdc->f.states & DBackup) {
+ afs_DCMoveBucket(tdc, 0, 1);
+ } else {
+ afs_DCMoveBucket(tdc, 0, 1);
+ }
+ }
}
tdc->refCount = 1;
tdc->index = aslot;
dput(filevp);
#else
tdc->f.inode = afs_vnodeToInumber(filevp);
-#ifdef AFS_DEC_ENV
- grele(filevp);
-#else
AFS_RELE(filevp);
-#endif
#endif /* AFS_LINUX22_ENV */
} else {
tdc->f.inode = ainode;
tdc->f.fid.Fid.Volume = 0; /* not in the hash table */
if (tstat.size != 0)
osi_UFSTruncate(tfile, 0);
+ tdc->f.states &= ~(DRO|DBackup|DRW);
+ afs_DCMoveBucket(tdc, 0, 0);
/* put entry in free cache slot list */
afs_dvnextTbl[tdc->index] = afs_freeDCList;
afs_freeDCList = index;
afs_freeDSList = &tdp[0];
for (i = 0; i < aDentries - 1; i++) {
tdp[i].lruq.next = (struct afs_q *)(&tdp[i + 1]);
+ RWLOCK_INIT(&tdp[i].lock, "dcache lock");
+ RWLOCK_INIT(&tdp[i].tlock, "dcache tlock");
+ RWLOCK_INIT(&tdp[i].mflock, "dcache flock");
}
tdp[aDentries - 1].lruq.next = (struct afs_q *)0;
+ RWLOCK_INIT(&tdp[aDentries - 1].lock, "dcache lock");
+ RWLOCK_INIT(&tdp[aDentries - 1].tlock, "dcache tlock");
+ RWLOCK_INIT(&tdp[aDentries - 1].mflock, "dcache flock");
afs_stats_cmperf.cacheBlocksOrig = afs_stats_cmperf.cacheBlocksTotal =
afs_cacheBlocks = ablocks;
afs_dcentries = aDentries;
afs_blocksUsed = 0;
+ afs_stats_cmperf.cacheBucket0_Discarded =
+ afs_stats_cmperf.cacheBucket1_Discarded =
+ afs_stats_cmperf.cacheBucket2_Discarded = 0;
+ afs_DCSizeInit();
QInit(&afs_DLRU);
}
afs_osi_Free(afs_dchashTbl, afs_dhashsize * sizeof(afs_int32));
afs_blocksUsed = afs_dcentries = 0;
+ afs_stats_cmperf.cacheBucket0_Discarded =
+ afs_stats_cmperf.cacheBucket1_Discarded =
+ afs_stats_cmperf.cacheBucket2_Discarded = 0;
hzero(afs_indexCounter);
afs_freeDCCount = 0;