mm.c 11.7 KB
Newer Older
1 2
/*-------------------------------------------------------------------------
 *
3
 * mm.c
4
 *	  main memory storage manager
5
 *
6 7
 *	  This code manages relations that reside in (presumably stable)
 *	  main memory.
8
 *
9
 * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
Bruce Momjian's avatar
Add:  
Bruce Momjian committed
10
 * Portions Copyright (c) 1994, Regents of the University of California
11 12 13
 *
 *
 * IDENTIFICATION
14
 *	  $Header: /cvsroot/pgsql/src/backend/storage/smgr/Attic/mm.c,v 1.24 2001/06/27 23:31:39 tgl Exp $
15 16 17 18
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"
19
#include "miscadmin.h"
20

21
#ifdef STABLE_MEMORY_STORAGE
22 23 24 25 26

#include <math.h>


/*
27 28
 *	MMCacheTag -- Unique triplet for blocks stored by the main memory
 *				  storage manager.
29 30
 */

31 32
typedef struct MMCacheTag
{
33 34 35 36
	Oid			mmct_dbid;
	Oid			mmct_relid;
	BlockNumber mmct_blkno;
}			MMCacheTag;
37 38

/*
39 40
 *	Shared-memory hash table for main memory relations contains
 *	entries of this form.
41 42
 */

43 44
typedef struct MMHashEntry
{
45 46 47
	MMCacheTag	mmhe_tag;
	int			mmhe_bufno;
}			MMHashEntry;
48 49 50

/*
 * MMRelTag -- Unique identifier for each relation that is stored in the
51
 *					main-memory storage manager.
52 53
 */

54 55
typedef struct MMRelTag
{
56 57 58
	Oid			mmrt_dbid;
	Oid			mmrt_relid;
}			MMRelTag;
59 60

/*
61 62
 *	Shared-memory hash table for # blocks in main memory relations contains
 *	entries of this form.
63 64
 */

65 66
typedef struct MMRelHashEntry
{
67 68 69
	MMRelTag	mmrhe_tag;
	int			mmrhe_nblocks;
}			MMRelHashEntry;
70

71
#define MMNBUFFERS		10
72 73
#define MMNRELATIONS	2

74
SPINLOCK	MMCacheLock;
75

76 77
static int *MMCurTop;
static int *MMCurRelno;
78
static MMCacheTag *MMBlockTags;
79 80 81
static char *MMBlockCache;
static HTAB *MMCacheHT;
static HTAB *MMRelCacheHT;
82 83 84 85

int
mminit()
{
86 87 88 89
	char	   *mmcacheblk;
	int			mmsize = 0;
	bool		found;
	HASHCTL		info;
90

91
	SpinAcquire(MMCacheLock);
92

93 94 95 96 97
	mmsize += MAXALIGN(BLCKSZ * MMNBUFFERS);
	mmsize += MAXALIGN(sizeof(*MMCurTop));
	mmsize += MAXALIGN(sizeof(*MMCurRelno));
	mmsize += MAXALIGN((MMNBUFFERS * sizeof(MMCacheTag)));
	mmcacheblk = (char *) ShmemInitStruct("Main memory smgr", mmsize, &found);
98

99 100 101
	if (mmcacheblk == (char *) NULL)
	{
		SpinRelease(MMCacheLock);
102
		return SM_FAIL;
103
	}
104

105
	info.keysize = sizeof(MMCacheTag);
106
	info.datasize = sizeof(MMHashEntry) - sizeof(MMCacheTag);
107
	info.hash = tag_hash;
108

109 110 111
	MMCacheHT = (HTAB *) ShmemInitHash("Main memory store HT",
									   MMNBUFFERS, MMNBUFFERS,
									 &info, (HASH_ELEM | HASH_FUNCTION));
112

113 114 115
	if (MMCacheHT == (HTAB *) NULL)
	{
		SpinRelease(MMCacheLock);
116
		return SM_FAIL;
117
	}
118

119
	info.keysize = sizeof(MMRelTag);
120
	info.datasize = sizeof(MMRelHashEntry) - sizeof(MMRelTag);
121
	info.hash = tag_hash;
122

123 124 125
	MMRelCacheHT = (HTAB *) ShmemInitHash("Main memory rel HT",
										  MMNRELATIONS, MMNRELATIONS,
									 &info, (HASH_ELEM | HASH_FUNCTION));
126

127 128 129
	if (MMRelCacheHT == (HTAB *) NULL)
	{
		SpinRelease(MMCacheLock);
130
		return SM_FAIL;
131
	}
132

133
	if (IsUnderPostmaster)		/* was IsPostmaster bjm */
134
	{
Bruce Momjian's avatar
Bruce Momjian committed
135
		MemSet(mmcacheblk, 0, mmsize);
136
		SpinRelease(MMCacheLock);
137
		return SM_SUCCESS;
138
	}
139

140
	SpinRelease(MMCacheLock);
141

142 143 144 145 146 147 148
	MMCurTop = (int *) mmcacheblk;
	mmcacheblk += sizeof(int);
	MMCurRelno = (int *) mmcacheblk;
	mmcacheblk += sizeof(int);
	MMBlockTags = (MMCacheTag *) mmcacheblk;
	mmcacheblk += (MMNBUFFERS * sizeof(MMCacheTag));
	MMBlockCache = mmcacheblk;
149

150
	return SM_SUCCESS;
151 152 153 154 155
}

int
mmshutdown()
{
156
	return SM_SUCCESS;
157 158 159 160 161
}

int
mmcreate(Relation reln)
{
162
	MMRelHashEntry *entry;
163 164
	bool		found;
	MMRelTag	tag;
165

166
	SpinAcquire(MMCacheLock);
167

168 169 170
	if (*MMCurRelno == MMNRELATIONS)
	{
		SpinRelease(MMCacheLock);
171
		return SM_FAIL;
172
	}
173

174
	(*MMCurRelno)++;
175

176
	tag.mmrt_relid = RelationGetRelid(reln);
177 178 179 180
	if (reln->rd_rel->relisshared)
		tag.mmrt_dbid = (Oid) 0;
	else
		tag.mmrt_dbid = MyDatabaseId;
181

182 183
	entry = (MMRelHashEntry *) hash_search(MMRelCacheHT,
									  (char *) &tag, HASH_ENTER, &found);
184

185 186 187 188 189
	if (entry == (MMRelHashEntry *) NULL)
	{
		SpinRelease(MMCacheLock);
		elog(FATAL, "main memory storage mgr rel cache hash table corrupt");
	}
190

191 192 193 194
	if (found)
	{
		/* already exists */
		SpinRelease(MMCacheLock);
195
		return SM_FAIL;
196
	}
197

198
	entry->mmrhe_nblocks = 0;
199

200
	SpinRelease(MMCacheLock);
201

202
	return SM_SUCCESS;
203 204 205
}

/*
206
 *	mmunlink() -- Unlink a relation.
207 208
 *
 * XXX currently broken: needs to accept RelFileNode, not Relation
209 210
 */
int
211
mmunlink(RelFileNode rnode)
212
{
213 214 215
	int			i;
	Oid			reldbid;
	MMHashEntry *entry;
216
	MMRelHashEntry *rentry;
217 218
	bool		found;
	MMRelTag	rtag;
219 220 221 222 223 224 225 226 227 228 229

	if (reln->rd_rel->relisshared)
		reldbid = (Oid) 0;
	else
		reldbid = MyDatabaseId;

	SpinAcquire(MMCacheLock);

	for (i = 0; i < MMNBUFFERS; i++)
	{
		if (MMBlockTags[i].mmct_dbid == reldbid
230
			&& MMBlockTags[i].mmct_relid == RelationGetRelid(reln))
231 232 233 234 235 236 237 238 239 240 241 242 243
		{
			entry = (MMHashEntry *) hash_search(MMCacheHT,
												(char *) &MMBlockTags[i],
												HASH_REMOVE, &found);
			if (entry == (MMHashEntry *) NULL || !found)
			{
				SpinRelease(MMCacheLock);
				elog(FATAL, "mmunlink: cache hash table corrupted");
			}
			MMBlockTags[i].mmct_dbid = (Oid) 0;
			MMBlockTags[i].mmct_relid = (Oid) 0;
			MMBlockTags[i].mmct_blkno = (BlockNumber) 0;
		}
244
	}
245
	rtag.mmrt_dbid = reldbid;
246
	rtag.mmrt_relid = RelationGetRelid(reln);
247

248 249
	rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag,
											HASH_REMOVE, &found);
250

251 252 253 254 255
	if (rentry == (MMRelHashEntry *) NULL || !found)
	{
		SpinRelease(MMCacheLock);
		elog(FATAL, "mmunlink: rel cache hash table corrupted");
	}
256

257
	(*MMCurRelno)--;
258

259 260
	SpinRelease(MMCacheLock);
	return 1;
261 262 263
}

/*
264
 *	mmextend() -- Add a block to the specified relation.
265
 *
266 267
 *		This routine returns SM_FAIL or SM_SUCCESS, with errno set as
 *		appropriate.
268 269
 */
int
270
mmextend(Relation reln, BlockNumber blocknum, char *buffer)
271
{
272
	MMRelHashEntry *rentry;
273 274 275 276 277 278 279
	MMHashEntry *entry;
	int			i;
	Oid			reldbid;
	int			offset;
	bool		found;
	MMRelTag	rtag;
	MMCacheTag	tag;
280 281 282 283 284 285 286

	if (reln->rd_rel->relisshared)
		reldbid = (Oid) 0;
	else
		reldbid = MyDatabaseId;

	tag.mmct_dbid = rtag.mmrt_dbid = reldbid;
287
	tag.mmct_relid = rtag.mmrt_relid = RelationGetRelid(reln);
288 289 290 291 292 293 294 295 296 297 298 299 300 301

	SpinAcquire(MMCacheLock);

	if (*MMCurTop == MMNBUFFERS)
	{
		for (i = 0; i < MMNBUFFERS; i++)
		{
			if (MMBlockTags[i].mmct_dbid == 0 &&
				MMBlockTags[i].mmct_relid == 0)
				break;
		}
		if (i == MMNBUFFERS)
		{
			SpinRelease(MMCacheLock);
302
			return SM_FAIL;
303
		}
304
	}
305 306 307 308
	else
	{
		i = *MMCurTop;
		(*MMCurTop)++;
309 310
	}

311 312 313 314 315 316 317
	rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag,
											HASH_FIND, &found);
	if (rentry == (MMRelHashEntry *) NULL || !found)
	{
		SpinRelease(MMCacheLock);
		elog(FATAL, "mmextend: rel cache hash table corrupt");
	}
318

319
	tag.mmct_blkno = rentry->mmrhe_nblocks;
320

321 322 323 324 325 326 327
	entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag,
										HASH_ENTER, &found);
	if (entry == (MMHashEntry *) NULL || found)
	{
		SpinRelease(MMCacheLock);
		elog(FATAL, "mmextend: cache hash table corrupt");
	}
328

329 330
	entry->mmhe_bufno = i;
	MMBlockTags[i].mmct_dbid = reldbid;
331
	MMBlockTags[i].mmct_relid = RelationGetRelid(reln);
332
	MMBlockTags[i].mmct_blkno = rentry->mmrhe_nblocks;
333

334 335
	/* page numbers are zero-based, so we increment this at the end */
	(rentry->mmrhe_nblocks)++;
336

337 338 339
	/* write the extended page */
	offset = (i * BLCKSZ);
	memmove(&(MMBlockCache[offset]), buffer, BLCKSZ);
340

341 342
	SpinRelease(MMCacheLock);

343
	return SM_SUCCESS;
344 345 346
}

/*
347
 *	mmopen() -- Open the specified relation.
348 349 350 351
 */
int
mmopen(Relation reln)
{
352
	/* automatically successful */
353
	return 0;
354 355 356
}

/*
357
 *	mmclose() -- Close the specified relation.
358
 *
359
 *		Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
360 361 362 363
 */
int
mmclose(Relation reln)
{
364
	/* automatically successful */
365
	return SM_SUCCESS;
366 367 368
}

/*
369
 *	mmread() -- Read the specified block from a relation.
370
 *
371
 *		Returns SM_SUCCESS or SM_FAIL.
372 373 374 375
 */
int
mmread(Relation reln, BlockNumber blocknum, char *buffer)
{
376 377 378 379
	MMHashEntry *entry;
	bool		found;
	int			offset;
	MMCacheTag	tag;
380

381 382 383 384
	if (reln->rd_rel->relisshared)
		tag.mmct_dbid = (Oid) 0;
	else
		tag.mmct_dbid = MyDatabaseId;
385

386
	tag.mmct_relid = RelationGetRelid(reln);
387
	tag.mmct_blkno = blocknum;
388

389 390 391
	SpinAcquire(MMCacheLock);
	entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag,
										HASH_FIND, &found);
392

393 394 395 396 397
	if (entry == (MMHashEntry *) NULL)
	{
		SpinRelease(MMCacheLock);
		elog(FATAL, "mmread: hash table corrupt");
	}
398

399 400 401 402
	if (!found)
	{
		/* reading nonexistent pages is defined to fill them with zeroes */
		SpinRelease(MMCacheLock);
Bruce Momjian's avatar
Bruce Momjian committed
403
		MemSet(buffer, 0, BLCKSZ);
404
		return SM_SUCCESS;
405
	}
406

407 408
	offset = (entry->mmhe_bufno * BLCKSZ);
	memmove(buffer, &MMBlockCache[offset], BLCKSZ);
409

410
	SpinRelease(MMCacheLock);
411

412
	return SM_SUCCESS;
413 414 415
}

/*
416
 *	mmwrite() -- Write the supplied block at the appropriate location.
417
 *
418
 *		Returns SM_SUCCESS or SM_FAIL.
419 420 421 422
 */
int
mmwrite(Relation reln, BlockNumber blocknum, char *buffer)
{
423 424 425 426
	MMHashEntry *entry;
	bool		found;
	int			offset;
	MMCacheTag	tag;
427

428 429 430 431
	if (reln->rd_rel->relisshared)
		tag.mmct_dbid = (Oid) 0;
	else
		tag.mmct_dbid = MyDatabaseId;
432

433
	tag.mmct_relid = RelationGetRelid(reln);
434
	tag.mmct_blkno = blocknum;
435

436 437 438
	SpinAcquire(MMCacheLock);
	entry = (MMHashEntry *) hash_search(MMCacheHT, (char *) &tag,
										HASH_FIND, &found);
439

440 441 442 443 444
	if (entry == (MMHashEntry *) NULL)
	{
		SpinRelease(MMCacheLock);
		elog(FATAL, "mmread: hash table corrupt");
	}
445

446 447 448 449 450
	if (!found)
	{
		SpinRelease(MMCacheLock);
		elog(FATAL, "mmwrite: hash table missing requested page");
	}
451

452 453
	offset = (entry->mmhe_bufno * BLCKSZ);
	memmove(&MMBlockCache[offset], buffer, BLCKSZ);
454

455
	SpinRelease(MMCacheLock);
456

457
	return SM_SUCCESS;
458 459 460
}

/*
461
 *	mmflush() -- Synchronously write a block to stable storage.
462
 *
463
 *		For main-memory relations, this is exactly equivalent to mmwrite().
464 465 466 467
 */
int
mmflush(Relation reln, BlockNumber blocknum, char *buffer)
{
468
	return mmwrite(reln, blocknum, buffer);
469 470 471
}

/*
472
 *	mmblindwrt() -- Write a block to stable storage blind.
473
 *
474 475
 *		We have to be able to do this using only the name and OID of
 *		the database and relation in which the block belongs.
476 477 478
 */
int
mmblindwrt(char *dbstr,
479 480 481 482
		   char *relstr,
		   Oid dbid,
		   Oid relid,
		   BlockNumber blkno,
483 484
		   char *buffer,
		   bool dofsync)
485
{
486
	return SM_FAIL;
487 488 489
}

/*
490
 *	mmnblocks() -- Get the number of blocks stored in a relation.
491
 *
492
 *		Returns # of blocks or InvalidBlockNumber on error.
493
 */
494
BlockNumber
495 496
mmnblocks(Relation reln)
{
497
	MMRelTag	rtag;
498
	MMRelHashEntry *rentry;
499
	bool		found;
500
	BlockNumber	nblocks;
501

502 503 504 505
	if (reln->rd_rel->relisshared)
		rtag.mmrt_dbid = (Oid) 0;
	else
		rtag.mmrt_dbid = MyDatabaseId;
506

507
	rtag.mmrt_relid = RelationGetRelid(reln);
508

509
	SpinAcquire(MMCacheLock);
510

511 512
	rentry = (MMRelHashEntry *) hash_search(MMRelCacheHT, (char *) &rtag,
											HASH_FIND, &found);
513

514 515 516 517 518
	if (rentry == (MMRelHashEntry *) NULL)
	{
		SpinRelease(MMCacheLock);
		elog(FATAL, "mmnblocks: rel cache hash table corrupt");
	}
519

520 521 522
	if (found)
		nblocks = rentry->mmrhe_nblocks;
	else
523
		nblocks = InvalidBlockNumber;
524

525
	SpinRelease(MMCacheLock);
526

527
	return nblocks;
528 529 530
}

/*
531
 *	mmcommit() -- Commit a transaction.
532
 *
533
 *		Returns SM_SUCCESS or SM_FAIL with errno set as appropriate.
534 535 536 537
 */
int
mmcommit()
{
538
	return SM_SUCCESS;
539 540 541
}

/*
542
 *	mmabort() -- Abort a transaction.
543 544 545 546 547
 */

int
mmabort()
{
548
	return SM_SUCCESS;
549 550 551
}

/*
552
 *	MMShmemSize() -- Declare amount of shared memory we require.
553
 *
554 555 556 557
 *		The shared memory initialization code creates a block of shared
 *		memory exactly big enough to hold all the structures it needs to.
 *		This routine declares how much space the main memory storage
 *		manager will use.
558 559 560 561
 */
int
MMShmemSize()
{
562
	int			size = 0;
563 564 565 566

	/*
	 * first compute space occupied by the (dbid,relid,blkno) hash table
	 */
567
	size += hash_estimate_size(MMNBUFFERS,
Bruce Momjian's avatar
Bruce Momjian committed
568 569
							   0,		/* MMHashEntry includes key */
							   sizeof(MMHashEntry));
570 571 572 573

	/*
	 * now do the same for the rel hash table
	 */
574
	size += hash_estimate_size(MMNRELATIONS,
Bruce Momjian's avatar
Bruce Momjian committed
575 576
							   0,		/* MMRelHashEntry includes key */
							   sizeof(MMRelHashEntry));
577 578 579 580 581 582 583 584 585 586

	/*
	 * finally, add in the memory block we use directly
	 */

	size += MAXALIGN(BLCKSZ * MMNBUFFERS);
	size += MAXALIGN(sizeof(*MMCurTop));
	size += MAXALIGN(sizeof(*MMCurRelno));
	size += MAXALIGN(MMNBUFFERS * sizeof(MMCacheTag));

587
	return size;
588 589
}

590
#endif	 /* STABLE_MEMORY_STORAGE */