⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 index.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
字号:
#include "stdinc.h"#include "dat.h"#include "fns.h"static int	buckLook(u8int *score, int type, u8int *data, int n);static int	writeBucket(ISect *is, u32int buck, IBucket *ib, DBlock *b);static int	okIBucket(IBucket *ib, ISect *is);static ISect	*initISect1(ISect *is);static VtLock	*indexLock;	//ZZZstatic char IndexMagic[] = "venti index configuration";Index*initIndex(char *name, ISect **sects, int n){	IFile f;	Index *ix;	ISect *is;	u32int last, blockSize, tabSize;	int i;	if(n <= 0){		setErr(EOk, "no index sections to initialize index");		return nil;	}	ix = MKZ(Index);	if(ix == nil){		setErr(EOk, "can't initialize index: out of memory");		freeIndex(ix);		return nil;	}	tabSize = sects[0]->tabSize;	if(!partIFile(&f, sects[0]->part, sects[0]->tabBase, tabSize))		return 0;	if(!parseIndex(&f, ix)){		freeIFile(&f);		freeIndex(ix);		return nil;	}	freeIFile(&f);	if(!nameEq(ix->name, name)){		setErr(ECorrupt, "mismatched index name: found %s expected %s", ix->name, name);		return nil;	}	ix->sects = sects;	if(ix->nsects != n){		setErr(ECorrupt, "mismatched number index sections: found %d expected %d", n, ix->nsects);		freeIndex(ix);		return nil;	}	last = 0;	blockSize = ix->blockSize;	for(i = 0; i < ix->nsects; i++){		is = sects[i];		if(!nameEq(ix->name, is->index)		|| is->blockSize != blockSize		|| is->tabSize != tabSize		|| !nameEq(is->name, ix->smap[i].name)		|| is->start != ix->smap[i].start		|| is->stop != ix->smap[i].stop		|| last != is->start		|| is->start > is->stop){			setErr(ECorrupt, "inconsistent index sections in %s", ix->name);			freeIndex(ix);			return nil;		}		last = is->stop;	}	ix->tabSize = tabSize;	ix->buckets = last;	ix->div = (((u64int)1 << 32) + last - 1) / last;	last = (((u64int)1 << 32) - 1) / ix->div + 1;	if(last != ix->buckets){		setErr(ECorrupt, "inconsistent math for buckets in %s", ix->name);		freeIndex(ix);		return nil;	}	ix->arenas = MKNZ(Arena*, ix->narenas);	if(!mapArenas(ix->amap, ix->arenas, ix->narenas, ix->name)){		freeIndex(ix);		return nil;	}	return ix;}intwbIndex(Index *ix){	Fmt f;	ZBlock *b;	int i;	if(ix->nsects == 0){		setErr(EOk, "no sections in index %s", ix->name);		return 0;	}	b = allocZBlock(ix->tabSize, 1);	if(b == nil){		setErr(EOk, "can't write index configuration: out of memory");		return 0;	}	fmtZBInit(&f, b);	if(!outputIndex(&f, ix)){		setErr(EOk, "can't make index configuration: table storage too small %d", ix->tabSize);		freeZBlock(b);		return 0;	}	for(i = 0; i < ix->nsects; i++){		if(!writePart(ix->sects[i]->part, ix->sects[i]->tabBase, b->data, ix->tabSize)){			setErr(EOk, "can't write index: %R");			freeZBlock(b);			return 0;		}	}	freeZBlock(b);	for(i = 0; i < ix->nsects; i++)		if(!wbISect(ix->sects[i]))			return 0;	return 1;}/* * index: IndexMagic '\n' version '\n' name '\n' blockSize '\n' sections arenas * version, blockSize: u32int * name: max. ANameSize string * sections, arenas: AMap */intoutputIndex(Fmt *f, Index *ix){	if(fmtprint(f, "%s\n%ud\n%s\n%ud\n", IndexMagic, ix->version, ix->name, ix->blockSize) < 0)		return 0;	return outputAMap(f, ix->smap, ix->nsects) && outputAMap(f, ix->amap, ix->narenas);}intparseIndex(IFile *f, Index *ix){	AMapN amn;	u32int v;	char *s;	/*	 * magic	 */	s = ifileLine(f);	if(s == nil || strcmp(s, IndexMagic) != 0){		setErr(ECorrupt, "bad index magic for %s", f->name);		return 0;	}	/*	 * version	 */	if(!ifileU32Int(f, &v)){		setErr(ECorrupt, "syntax error: bad version number in %s", f->name);		return 0;	}	ix->version = v;	if(ix->version != IndexVersion){		setErr(ECorrupt, "bad version number in %s", f->name);		return 0;	}	/*	 * name	 */	if(!ifileName(f, ix->name)){		setErr(ECorrupt, "syntax error: bad index name in %s", f->name);		return 0;	}	/*	 * block size	 */	if(!ifileU32Int(f, &v)){		setErr(ECorrupt, "syntax error: bad version number in %s", f->name);		return 0;	}	ix->blockSize = v;	if(!parseAMap(f, &amn))		return 0;	ix->nsects = amn.n;	ix->smap = amn.map;	if(!parseAMap(f, &amn))		return 0;	ix->narenas = amn.n;	ix->amap = amn.map;	return 1;}/* * initialize an entirely new index */Index *newIndex(char *name, ISect **sects, int n){	Index *ix;	AMap *smap;	u64int nb;	u32int div, ub, xb, start, stop, blockSize, tabSize;	int i, j;	if(n < 1){		setErr(EOk, "creating index with no index sections");		return nil;	}	/*	 * compute the total buckets available in the index,	 * and the total buckets which are used.	 */	nb = 0;	blockSize = sects[0]->blockSize;	tabSize = sects[0]->tabSize;	for(i = 0; i < n; i++){		if(sects[i]->start != 0 || sects[i]->stop != 0		|| sects[i]->index[0] != '\0'){			setErr(EOk, "creating new index using non-empty section %s", sects[i]->name);			return nil;		}		if(blockSize != sects[i]->blockSize){			setErr(EOk, "mismatched block sizes in index sections");			return nil;		}		if(tabSize != sects[i]->tabSize){			setErr(EOk, "mismatched config table sizes in index sections");			return nil;		}		nb += sects[i]->blocks;	}	/*	 * check for duplicate names	 */	for(i = 0; i < n; i++){		for(j = i + 1; j < n; j++){			if(nameEq(sects[i]->name, sects[j]->name)){				setErr(EOk, "duplicate section name %s for index %s", sects[i]->name, name);				return nil;			}		}	}	if(nb >= ((u64int)1 << 32)){		setErr(EBug, "index too large");		return nil;	}	div = (((u64int)1 << 32) + nb - 1) / nb;	ub = (((u64int)1 << 32) - 1) / div + 1;	if(div < 100){		setErr(EBug, "index divisor too coarse");		return nil;	}	if(ub > nb){		setErr(EBug, "index initialization math wrong");		return nil;	}	/*	 * initialize each of the index sections	 * and the section map table	 */	smap = MKNZ(AMap, n);	if(smap == nil){		setErr(EOk, "can't create new index: out of memory");		return nil;	}	xb = nb - ub;	start = 0;	for(i = 0; i < n; i++){		stop = start + sects[i]->blocks - xb / n;		if(i == n - 1)			stop = ub;		sects[i]->start = start;		sects[i]->stop = stop;		nameCp(sects[i]->index, name);		smap[i].start = start;		smap[i].stop = stop;		nameCp(smap[i].name, sects[i]->name);		start = stop;	}	/*	 * initialize the index itself	 */	ix = MKZ(Index);	if(ix == nil){		setErr(EOk, "can't create new index: out of memory");		free(smap);		return nil;	}	ix->version = IndexVersion;	nameCp(ix->name, name);	ix->sects = sects;	ix->smap = smap;	ix->nsects = n;	ix->blockSize = blockSize;	ix->div = div;	ix->buckets = ub;	ix->tabSize = tabSize;	return ix;}ISect*initISect(Part *part){	ISect *is;	ZBlock *b;	int ok;	b = allocZBlock(HeadSize, 0);	if(b == nil || !readPart(part, PartBlank, b->data, HeadSize)){		setErr(EAdmin, "can't read index section header: %R");		return nil;	}	is = MKZ(ISect);	if(is == nil){		freeZBlock(b);		return nil;	}	is->part = part;	ok = unpackISect(is, b->data);	freeZBlock(b);	if(!ok){		setErr(ECorrupt, "corrupted index section header: %R");		freeISect(is);		return nil;	}	if(is->version != ISectVersion){		setErr(EAdmin, "unknown index section version %d", is->version);		freeISect(is);		return nil;	}	return initISect1(is);}ISect*newISect(Part *part, char *name, u32int blockSize, u32int tabSize){	ISect *is;	u32int tabBase;	is = MKZ(ISect);	if(is == nil)		return nil;	nameCp(is->name, name);	is->version = ISectVersion;	is->part = part;	is->blockSize = blockSize;	is->start = 0;	is->stop = 0;	tabBase = (PartBlank + HeadSize + blockSize - 1) & ~(blockSize - 1);	is->blockBase = (tabBase + tabSize + blockSize - 1) & ~(blockSize - 1);	is->blocks = is->part->size / blockSize - is->blockBase / blockSize;	is = initISect1(is);	if(is == nil)		return nil;	return is;}/* * initialize the computed paramaters for an index */static ISect*initISect1(ISect *is){	u64int v;	is->buckMax = (is->blockSize - IBucketSize) / IEntrySize;	is->blockLog = u64log2(is->blockSize);	if(is->blockSize != (1 << is->blockLog)){		setErr(ECorrupt, "illegal non-power-of-2 bucket size %d\n", is->blockSize);		freeISect(is);		return nil;	}	partBlockSize(is->part, is->blockSize);	is->tabBase = (PartBlank + HeadSize + is->blockSize - 1) & ~(is->blockSize - 1);	if(is->tabBase >= is->blockBase){		setErr(ECorrupt, "index section config table overlaps bucket storage");		freeISect(is);		return nil;	}	is->tabSize = is->blockBase - is->tabBase;	v = is->part->size & ~(u64int)(is->blockSize - 1);	if(is->blockBase + (u64int)is->blocks * is->blockSize != v){		setErr(ECorrupt, "invalid blocks in index section %s", is->name);//ZZZZZZZZZ//		freeISect(is);//		return nil;	}	if(is->stop - is->start > is->blocks){		setErr(ECorrupt, "index section overflows available space");		freeISect(is);		return nil;	}	if(is->start > is->stop){		setErr(ECorrupt, "invalid index section range");		freeISect(is);		return nil;	}if(indexLock == nil)indexLock = vtLockAlloc();	return is;}intwbISect(ISect *is){	ZBlock *b;	b = allocZBlock(HeadSize, 1);	if(b == nil)//ZZZ set error?		return 0;	if(!packISect(is, b->data)){		setErr(ECorrupt, "can't make index section header: %R");		freeZBlock(b);		return 0;	}	if(!writePart(is->part, PartBlank, b->data, HeadSize)){		setErr(EAdmin, "can't write index section header: %R");		freeZBlock(b);		return 0;	}	freeZBlock(b);	return 1;}voidfreeISect(ISect *is){	if(is == nil)		return;	free(is);}voidfreeIndex(Index *ix){	int i;	if(ix == nil)		return;	free(ix->amap);	free(ix->arenas);	for(i = 0; i < ix->nsects; i++)		freeISect(ix->sects[i]);	free(ix->sects);	free(ix->smap);	free(ix);}/* * write a clump to an available arena in the index * and return the address of the clump within the index.ZZZ question: should this distinguish between an arenafilling up and real errors writing the clump? */u64intwriteIClump(Index *ix, Clump *c, u8int *clbuf){	u64int a;	int i;	for(i = ix->mapAlloc; i < ix->narenas; i++){		a = writeAClump(ix->arenas[i], c, clbuf);		if(a != TWID64)			return a + ix->amap[i].start;	}	setErr(EAdmin, "no space left in arenas");	return 0;}/* * convert an arena index to an relative address address */Arena*amapItoA(Index *ix, u64int a, u64int *aa){	int r, l, m;	l = 1;	r = ix->narenas - 1;	while(l <= r){		m = (r + l) / 2;		if(ix->amap[m].start <= a)			l = m + 1;		else			r = m - 1;	}	l--;	if(a > ix->amap[l].stop){		setErr(ECrash, "unmapped address passed to amapItoA");		return nil;	}	if(ix->arenas[l] == nil){		setErr(ECrash, "unmapped arena selected in amapItoA");		return nil;	}	*aa = a - ix->amap[l].start;	return ix->arenas[l];}intiAddrEq(IAddr *ia1, IAddr *ia2){	return ia1->type == ia2->type		&& ia1->size == ia2->size		&& ia1->blocks == ia2->blocks		&& ia1->addr == ia2->addr;}/* * lookup the the score int the partition * * nothing needs to be explicitly locked: * only static parts of ix are used, and * the bucket is locked by the DBlock lock. */intloadIEntry(Index *ix, u8int *score, int type, IEntry *ie){	ISect *is;	DBlock *b;	IBucket ib;	u32int buck;	int h, ok;	buck = hashBits(score, 32) / ix->div;	ok = 0;	for(;;){		vtLock(stats.lock);		stats.indexReads++;		vtUnlock(stats.lock);		is = findISect(ix, buck);		if(is == nil){			setErr(EAdmin, "bad math in loadIEntry");			return 0;		}		buck -= is->start;		b = getDBlock(is->part, is->blockBase + ((u64int)buck << is->blockLog), 1);		if(b == nil)			break;		unpackIBucket(&ib, b->data);		if(!okIBucket(&ib, is))			break;		h = buckLook(score, type, ib.data, ib.n);		if(h & 1){			h ^= 1;			unpackIEntry(ie, &ib.data[h]);			ok = 1;			break;		}		break;	}	putDBlock(b);	return ok;}/* * insert or update an index entry into the appropriate bucket */intstoreIEntry(Index *ix, IEntry *ie){	ISect *is;	DBlock *b;	IBucket ib;	u32int buck;	int h, ok;	buck = hashBits(ie->score, 32) / ix->div;	ok = 0;	for(;;){		vtLock(stats.lock);		stats.indexWReads++;		vtUnlock(stats.lock);		is = findISect(ix, buck);		if(is == nil){			setErr(EAdmin, "bad math in storeIEntry");			return 0;		}		buck -= is->start;		b = getDBlock(is->part, is->blockBase + ((u64int)buck << is->blockLog), 1);		if(b == nil)			break;		unpackIBucket(&ib, b->data);		if(!okIBucket(&ib, is))			break;		h = buckLook(ie->score, ie->ia.type, ib.data, ib.n);		if(h & 1){			h ^= 1;			packIEntry(ie, &ib.data[h]);			ok = writeBucket(is, buck, &ib, b);			break;		}		if(ib.n < is->buckMax){			memmove(&ib.data[h + IEntrySize], &ib.data[h], ib.n * IEntrySize - h);			ib.n++;			packIEntry(ie, &ib.data[h]);			ok = writeBucket(is, buck, &ib, b);			break;		}		break;	}	putDBlock(b);	return ok;}static intwriteBucket(ISect *is, u32int buck, IBucket *ib, DBlock *b){	if(buck >= is->blocks)		setErr(EAdmin, "index write out of bounds: %d >= %d\n",				buck, is->blocks);	vtLock(stats.lock);	stats.indexWrites++;	vtUnlock(stats.lock);	packIBucket(ib, b->data);	return writePart(is->part, is->blockBase + ((u64int)buck << is->blockLog), b->data, is->blockSize);}/* * find the number of the index section holding score */intindexSect(Index *ix, u8int *score){	u32int buck;	int r, l, m;	buck = hashBits(score, 32) / ix->div;	l = 1;	r = ix->nsects - 1;	while(l <= r){		m = (r + l) >> 1;		if(ix->sects[m]->start <= buck)			l = m + 1;		else			r = m - 1;	}	return l - 1;}/* * find the index section which holds buck */ISect*findISect(Index *ix, u32int buck){	ISect *is;	int r, l, m;	l = 1;	r = ix->nsects - 1;	while(l <= r){		m = (r + l) >> 1;		if(ix->sects[m]->start <= buck)			l = m + 1;		else			r = m - 1;	}	is = ix->sects[l - 1];	if(is->start <= buck && is->stop > buck)		return is;	return nil;}static intokIBucket(IBucket *ib, ISect *is){	if(ib->n <= is->buckMax && (ib->next == 0 || ib->next >= is->start && ib->next < is->stop))		return 1;	setErr(EICorrupt, "corrupted disk index bucket: n=%ud max=%ud, next=%lud range=[%lud,%lud)",		ib->n, is->buckMax, ib->next, is->start, is->stop);	return 0;}/* * look for score within data; * return 1 | byte index of matching index, * or 0 | index of least element > score */static intbuckLook(u8int *score, int type, u8int *data, int n){	int i, r, l, m, h, c, cc;	l = 0;	r = n - 1;	while(l <= r){		m = (r + l) >> 1;		h = m * IEntrySize;		for(i = 0; i < VtScoreSize; i++){			c = score[i];			cc = data[h + i];			if(c != cc){				if(c > cc)					l = m + 1;				else					r = m - 1;				goto cont;			}		}		cc = data[h + IEntryTypeOff];		if(type != cc){			if(type > cc)				l = m + 1;			else				r = m - 1;			goto cont;		}		return h | 1;	cont:;	}	return l * IEntrySize;}/* * compare two IEntries; consistent with buckLook */intientryCmp(void *vie1, void *vie2){	u8int *ie1, *ie2;	int i, v1, v2;	ie1 = vie1;	ie2 = vie2;	for(i = 0; i < VtScoreSize; i++){		v1 = ie1[i];		v2 = ie2[i];		if(v1 != v2){			if(v1 < v2)				return -1;			return 1;		}	}	v1 = ie1[IEntryTypeOff];	v2 = ie2[IEntryTypeOff];	if(v1 != v2){		if(v1 < v2)			return -1;		return 1;	}	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -