Implemented pageOrientedList, also did some bug fixing, and added some support functions to alloc.c
This commit is contained in:
parent
05934d296a
commit
17f76264aa
20 changed files with 826 additions and 86 deletions
149
lladd.pws
149
lladd.pws
|
@ -11,24 +11,50 @@ filter.file.ignore.hidden=0
|
|||
filter.dir.ignore.hidden=0
|
||||
|
||||
[filenumbers]
|
||||
0=22
|
||||
1=1
|
||||
2=12
|
||||
3=2
|
||||
4=50
|
||||
5=3
|
||||
6=25
|
||||
7=24
|
||||
8=30
|
||||
0=170
|
||||
1=70
|
||||
2=21
|
||||
3=50
|
||||
4=1
|
||||
5=1
|
||||
6=89
|
||||
7=22
|
||||
8=1
|
||||
9=1
|
||||
10=67
|
||||
11=1
|
||||
12=17
|
||||
13=1
|
||||
14=104
|
||||
15=387
|
||||
16=58
|
||||
17=8
|
||||
10=153
|
||||
11=102
|
||||
12=4
|
||||
13=6
|
||||
14=1
|
||||
15=69
|
||||
16=148
|
||||
17=1
|
||||
18=1
|
||||
19=1
|
||||
20=13
|
||||
21=43
|
||||
22=87
|
||||
23=2
|
||||
24=1
|
||||
25=106
|
||||
26=106
|
||||
27=124
|
||||
28=151
|
||||
29=158
|
||||
30=324
|
||||
31=145
|
||||
32=46
|
||||
33=5
|
||||
34=38
|
||||
35=49
|
||||
36=11
|
||||
37=47
|
||||
38=76
|
||||
39=29
|
||||
40=1
|
||||
41=324
|
||||
42=66
|
||||
43=167
|
||||
|
||||
[filemarkers]
|
||||
0=
|
||||
|
@ -49,16 +75,78 @@ filter.dir.ignore.hidden=0
|
|||
15=
|
||||
16=
|
||||
17=
|
||||
18=
|
||||
19=
|
||||
20=
|
||||
21=
|
||||
22=
|
||||
23=
|
||||
24=
|
||||
25=
|
||||
26=
|
||||
27=
|
||||
28=
|
||||
29=
|
||||
30=
|
||||
31=
|
||||
32=
|
||||
33=
|
||||
34=
|
||||
35=
|
||||
36=
|
||||
37=
|
||||
38=
|
||||
39=
|
||||
40=
|
||||
41=
|
||||
42=
|
||||
43=
|
||||
|
||||
[filelist]
|
||||
0=/home/sears/lladd/libdfa/messages.h
|
||||
1=/home/sears/lladd/test/dfa/Makefile.am
|
||||
2=/home/sears/lladd/test/lladd/Makefile.am
|
||||
3=/home/sears/lladd/test/lladd/check_blobRecovery.c
|
||||
4=/home/sears/lladd/test/dfa/check_networksetup.c
|
||||
5=/home/sears/lladd/libdfa/networksetup.sample
|
||||
6=/home/sears/lladd/src/libdfa/networksetup.c
|
||||
7=/home/sears/lladd/libdfa/networksetup.h
|
||||
0=/home/sears/lladd/src/lladd/page/slotted.h
|
||||
1=/home/sears/lladd/lladd/operations/pageOrientedListNTA.h
|
||||
2=/home/sears/lladd/src/lladd/operations/pageOrientedListNTA.c
|
||||
3=/home/sears/lladd/lladd/operations/linkedListNTA.h
|
||||
4=/home/sears/lladd/src/lladd/operations/linkedListNTA.c
|
||||
5=/home/sears/lladd/lladd/operations/linearHashNTA.h
|
||||
6=/home/sears/lladd/lladd/operations/prepare.h
|
||||
7=/home/sears/lladd/lladd/operations/alloc.h
|
||||
8=/home/sears/lladd/benchmarks/berkeleyDB/Makefile.am
|
||||
9=/home/sears/lladd/benchmarks/berkeleyDB/bdbRaw.c
|
||||
10=/home/sears/lladd/lladd/transactional.h
|
||||
11=/home/sears/lladd/doc/index.html
|
||||
12=/home/sears/lladd/test/cht/run
|
||||
13=/home/sears/lladd/test/cht/Makefile.am
|
||||
14=/home/sears/lladd/src/apps/cht/Makefile.am
|
||||
15=/home/sears/lladd/configure.in
|
||||
16=/home/sears/lladd/src/lladd/logger/logWriter.c
|
||||
17=/home/sears/lladd/src/lladd/operations/alloc.c
|
||||
18=/home/sears/lladd/lladd/constants.h
|
||||
19=/home/sears/lladd/src/lladd/operations.c
|
||||
20=/home/sears/lladd/test/cht/subordinate.c
|
||||
21=/home/sears/lladd/src/libdfa/callbacks.c
|
||||
22=/home/sears/lladd/src/2pc/2pc.h
|
||||
23=/home/sears/lladd/test/2pc/Makefile.am
|
||||
24=/home/sears/lladd/test/cht/cht_server.c
|
||||
25=/home/sears/lladd/test/cht/simple.c
|
||||
26=/home/sears/lladd/test/2pc/always_commit.c
|
||||
27=/home/sears/lladd/test/dfa/star.c
|
||||
28=/home/sears/lladd/src/apps/cht/cht.h
|
||||
29=/home/sears/lladd/libdfa/libdfa.h
|
||||
30=/home/sears/lladd/src/libdfa/libdfa.c
|
||||
31=/home/sears/lladd/src/apps/cht/cht_client.c
|
||||
32=/home/sears/lladd/src/lladd/operations/linearHashNTA.c
|
||||
33=/home/sears/lladd/test/cht/client.conf
|
||||
34=/home/sears/lladd/libdfa/networksetup.h
|
||||
35=/home/sears/lladd/src/apps/cht/cht.c
|
||||
36=/home/sears/lladd/test/cht/cluster.conf
|
||||
37=/home/sears/lladd/test/cht/client.c
|
||||
38=/home/sears/lladd/src/libdfa/networksetup.c
|
||||
39=/home/sears/lladd/src/apps/cht/cht_server.c
|
||||
40=/home/sears/lladd/src/apps/cht/cht_message.c
|
||||
41=/home/sears/lladd/src/libdfa/messages.c
|
||||
42=/home/sears/lladd/libdfa/messages.h
|
||||
43=/home/sears/lladd/src/2pc/2pc.c
|
||||
|
||||
[Project Tree]
|
||||
0=0
|
||||
|
@ -73,11 +161,12 @@ filter.dir.ignore.hidden=0
|
|||
|
||||
[File Tree]
|
||||
0=0
|
||||
1=0:5
|
||||
2=0:6
|
||||
3=0:9
|
||||
4=0:10
|
||||
5=0:11
|
||||
1=0:6
|
||||
2=0:6:2
|
||||
3=0:10
|
||||
4=0:10:4
|
||||
5=0:10:4:4
|
||||
6=0:12
|
||||
|
||||
[executer args]
|
||||
0=check_linearHash
|
||||
|
|
|
@ -164,6 +164,7 @@ typedef struct {
|
|||
#include "operations/nestedTopActions.h"
|
||||
#include "operations/linkedListNTA.h"
|
||||
#include "operations/linearHashNTA.h"
|
||||
#include "operations/pageOrientedListNTA.h"
|
||||
|
||||
|
||||
extern Operation operationsTable[]; /* [MAX_OPERATIONS]; memset somewhere */
|
||||
|
|
|
@ -30,6 +30,8 @@ Operation getRealloc();
|
|||
*/
|
||||
recordid Talloc(int xid, long size);
|
||||
|
||||
recordid TallocFromPage(int xid, long page, long size);
|
||||
|
||||
/**
|
||||
Free a record.
|
||||
@todo Currently, we just leak store space on dealloc.
|
||||
|
@ -37,12 +39,33 @@ recordid Talloc(int xid, long size);
|
|||
void Tdealloc(int xid, recordid rid);
|
||||
|
||||
/**
|
||||
Return the type of a record, as returned by getRecordType.
|
||||
Obtain the type of a record, as returned by getRecordType.
|
||||
|
||||
@param xid the transaction id.
|
||||
|
||||
@param rid the record of interest. The size field will be ignored,
|
||||
allowing this function to be used to probe for records in pages.
|
||||
|
||||
@return UNINITIALIZED_RECORD, BLOB_RECORD, SLOTTED_RECORD, or FIXED_RECORD.
|
||||
|
||||
@todo document TrecordType
|
||||
@see getRecordType
|
||||
|
||||
*/
|
||||
int TrecordType(int xid, recordid rid);
|
||||
|
||||
/**
|
||||
Obtain the length of the data stored in a record.
|
||||
|
||||
@param xid the transaction id.
|
||||
|
||||
@param rid the record of interest. The size field will be ignored,
|
||||
allowing this function to be used to probe for records in pages.
|
||||
|
||||
@return -1 if the record does not exist, the size of the record otherwise.
|
||||
*/
|
||||
int TrecordSize(int xid, recordid rid);
|
||||
|
||||
/** Return the number of records stored in page pageid */
|
||||
int TrecordsInPage(int xid, int pageid);
|
||||
|
||||
#endif
|
||||
|
|
89
lladd/operations/pageOrientedListNTA.h
Normal file
89
lladd/operations/pageOrientedListNTA.h
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*---
|
||||
This software is copyrighted by the Regents of the University of
|
||||
California, and other parties. The following terms apply to all files
|
||||
associated with the software unless explicitly disclaimed in
|
||||
individual files.
|
||||
|
||||
The authors hereby grant permission to use, copy, modify, distribute,
|
||||
and license this software and its documentation for any purpose,
|
||||
provided that existing copyright notices are retained in all copies
|
||||
and that this notice is included verbatim in any distributions. No
|
||||
written agreement, license, or royalty fee is required for any of the
|
||||
authorized uses. Modifications to this software may be copyrighted by
|
||||
their authors and need not follow the licensing terms described here,
|
||||
provided that the new terms are clearly indicated on the first page of
|
||||
each file where they apply.
|
||||
|
||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
||||
U.S. government, the Government shall have only "Restricted Rights" in
|
||||
the software and related documentation as defined in the Federal
|
||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
||||
acquiring the software on behalf of the Department of Defense, the
|
||||
software shall be classified as "Commercial Computer Software" and the
|
||||
Government shall have only "Restricted Rights" as defined in Clause
|
||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
||||
authors grant the U.S. Government and others acting in its behalf
|
||||
permission to use and distribute the software in accordance with the
|
||||
terms specified in this license.
|
||||
---*/
|
||||
|
||||
/**
|
||||
@file
|
||||
|
||||
A linked list implementation designed to handle variable length entries, and
|
||||
minimize the number of pages spanned by each list.
|
||||
|
||||
The data is stored using the slotted page implementation.
|
||||
|
||||
slot 0 is a long that points to the next page in the list.
|
||||
|
||||
The rest of the slots store data.
|
||||
|
||||
$Id $
|
||||
*/
|
||||
|
||||
#ifndef __pageOrientedListNTA_H
|
||||
#define __pageOrientedListNTA_H
|
||||
|
||||
|
||||
typedef struct {
|
||||
long page;
|
||||
/* The slot of the next record to be returned. */
|
||||
int slot;
|
||||
} lladd_pagedList_iterator;
|
||||
|
||||
//recordid dereferencePagedListRID(int xid, recordid rid);
|
||||
/** @return 1 if the key was already in the list. */
|
||||
int TpagedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize);
|
||||
int TpagedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value);
|
||||
int TpagedListRemove(int xid, recordid list, const byte * key, int keySize);
|
||||
int TpagedListMove(int xid, recordid start_list, recordid end_list, const byte *key, int keySize);
|
||||
/** The linked list iterator can tolerate the concurrent removal of values that
|
||||
it has already returned. In the presence of such removals, the iterator
|
||||
will return the keys and values present in the list as it existed when next()
|
||||
was first called.
|
||||
|
||||
@return a new iterator initialized to the head of the list. */
|
||||
lladd_pagedList_iterator * TpagedListIterator(int xid, recordid list);
|
||||
/** @return 1 if there was another entry to be iterated over. 0 otherwise.
|
||||
If this function returns 1, the caller must free() the malloced memory
|
||||
returned via the key and value arguments.*/
|
||||
int TpagedListNext(int xid, lladd_pagedList_iterator * it, byte ** key, int * keySize, byte ** value, int * valueSize);
|
||||
recordid TpagedListAlloc(int xid);
|
||||
void TpagedListDelete(int xid, recordid list);
|
||||
Operation getPagedListInsert();
|
||||
Operation getPagedListRemove();
|
||||
#endif
|
|
@ -46,7 +46,7 @@ terms specified in this license.
|
|||
#include <stdlib.h>
|
||||
#include "../../2pc/2pc.h"
|
||||
#include "../../libdfa/callbacks.h"
|
||||
#include <pbl/jbhash.h>
|
||||
//#include <pbl/jbhash.h>
|
||||
#include "cht_message.h"
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,9 @@ permission to use and distribute the software in accordance with the
|
|||
terms specified in this license.
|
||||
---*/
|
||||
/*#include <sys/types.h> */
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <lladd/common.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/poll.h>
|
||||
|
|
|
@ -10,6 +10,8 @@ liblladd_a_SOURCES=crc32.c common.c stats.c io.c bufferManager.c linkedlist.c op
|
|||
operations/increment.c operations/prepare.c operations/set.c \
|
||||
operations/alloc.c operations/noop.c operations/instantSet.c \
|
||||
page/slotted.c operations/lladdhash.c page/header.c page/fixed.c \
|
||||
operations/arrayList.c hash.c operations/linearHash.c operations/naiveLinearHash.c \
|
||||
operations/nestedTopActions.c operations/linearHashNTA.c operations/linkedListNTA.c
|
||||
operations/arrayList.c hash.c operations/linearHash.c \
|
||||
operations/naiveLinearHash.c operations/nestedTopActions.c \
|
||||
operations/linearHashNTA.c operations/linkedListNTA.c \
|
||||
operations/pageOrientedListNTA.c
|
||||
AM_CFLAGS= -g -Wall -pedantic -std=gnu99
|
||||
|
|
|
@ -213,6 +213,24 @@ recordid preAllocBlob(int xid, long blobSize) {
|
|||
|
||||
}
|
||||
|
||||
recordid preAllocBlobFromPage(int xid, long page, long blobSize) {
|
||||
|
||||
/* Allocate space for the blob entry. */
|
||||
|
||||
DEBUG("Allocing blob (size %ld)\n", blobSize);
|
||||
|
||||
assert(blobSize > 0); /* Don't support zero length blobs right now... */
|
||||
|
||||
/* First in buffer manager. */
|
||||
|
||||
recordid rid = TallocFromPage(xid, page, sizeof(blob_record_t));
|
||||
|
||||
rid.size = blobSize;
|
||||
|
||||
return rid;
|
||||
|
||||
}
|
||||
|
||||
void allocBlob(int xid, Page * p, lsn_t lsn, recordid rid) {
|
||||
|
||||
long fileSize;
|
||||
|
|
|
@ -78,6 +78,7 @@ typedef struct {
|
|||
|
||||
|
||||
recordid preAllocBlob(int xid, long blobsize);
|
||||
recordid preAllocBlobFromPage(int xid, long page, long blobsize);
|
||||
|
||||
/**
|
||||
Allocate a blob of size blobSize.
|
||||
|
|
|
@ -109,6 +109,7 @@ recordid Talloc(int xid, long size) {
|
|||
recordid rid;
|
||||
Page * p = NULL;
|
||||
if(size >= BLOB_THRESHOLD_SIZE) {
|
||||
/**@todo is it OK that Talloc doesn't pin the page when a blob is alloced?*/
|
||||
rid = preAllocBlob(xid, size);
|
||||
} else {
|
||||
pthread_mutex_lock(&talloc_mutex);
|
||||
|
@ -133,6 +134,29 @@ recordid Talloc(int xid, long size) {
|
|||
|
||||
}
|
||||
|
||||
recordid TallocFromPage(int xid, long page, long size) {
|
||||
recordid rid;
|
||||
|
||||
Page * p = NULL;
|
||||
if(size >= BLOB_THRESHOLD_SIZE) {
|
||||
rid = preAllocBlobFromPage(xid, page, size);
|
||||
} else {
|
||||
pthread_mutex_lock(&talloc_mutex);
|
||||
rid = slottedPreRallocFromPage(xid, page, size, &p);
|
||||
assert(p != NULL);
|
||||
}
|
||||
Tupdate(xid,rid, NULL, OPERATION_ALLOC);
|
||||
|
||||
if(p != NULL) {
|
||||
/* release the page that preRallocFromPage pinned for us. */
|
||||
/* @todo alloc.c pins multiple pages -> Will deadlock with small buffer sizes.. */
|
||||
releasePage(p);
|
||||
pthread_mutex_unlock(&talloc_mutex);
|
||||
}
|
||||
|
||||
return rid;
|
||||
}
|
||||
|
||||
void Tdealloc(int xid, recordid rid) {
|
||||
void * preimage = malloc(rid.size);
|
||||
Page * p = loadPage(rid.page);
|
||||
|
@ -149,3 +173,20 @@ int TrecordType(int xid, recordid rid) {
|
|||
releasePage(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TrecordSize(int xid, recordid rid) {
|
||||
int ret;
|
||||
Page * p = loadPage(rid.page);
|
||||
ret = getRecordSize(xid, p, rid);
|
||||
releasePage(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TrecordsInPage(int xid, int pageid) {
|
||||
Page * p = loadPage(pageid);
|
||||
readlock(p->rwlatch, 187);
|
||||
int ret = *numslots_ptr(p);
|
||||
unlock(p->rwlatch);
|
||||
releasePage(p);
|
||||
return ret;
|
||||
}
|
||||
|
|
247
src/lladd/operations/pageOrientedListNTA.c
Normal file
247
src/lladd/operations/pageOrientedListNTA.c
Normal file
|
@ -0,0 +1,247 @@
|
|||
#include <lladd/transactional.h>
|
||||
#include "../blobManager.h"
|
||||
#include "../page.h"
|
||||
#include "../page/slotted.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
/**
|
||||
Low level function that looks at the page structure, and finds the 'real' recordid
|
||||
of a page oriented list rid */
|
||||
/*recordid dereferencePagedListRID(int xid, recordid rid) {
|
||||
Page * p = loadPage(rid.page);
|
||||
while((*numslots_ptr(p)-POLL_NUM_RESERVED) <= rid.slot) {
|
||||
int oldSlot = rid.slot;
|
||||
oldSlot -= (*numslots_ptr(p) - POLL_NUM_RESERVED);
|
||||
rid.slot = POLL_NEXT;
|
||||
readRecord(xid, p , rid, &rid);
|
||||
rid.slot = oldSlot;
|
||||
releasePage(p);
|
||||
p = loadPage(rid.page);
|
||||
}
|
||||
releasePage(p);
|
||||
rid.slot+=POLL_NUM_RESERVED;
|
||||
return rid;
|
||||
}*/
|
||||
|
||||
recordid TpagedListAlloc(int xid) {
|
||||
long page = TpageAlloc(xid);
|
||||
recordid list = TallocFromPage(xid, page, sizeof(long));
|
||||
long zero = 0;
|
||||
Tset(xid, list, &zero);
|
||||
assert(list.slot == 0);
|
||||
assert(list.size == sizeof(long));
|
||||
return list;
|
||||
}
|
||||
|
||||
int TpagedListInsert(int xid, recordid list, const byte * key, int keySize, const byte * value, int valueSize) {
|
||||
int ret = 0;
|
||||
// if find in list, return 1
|
||||
byte * val;
|
||||
if(keySize == TpagedListFind(xid, list, key, keySize, &val)) {
|
||||
|
||||
free(val);
|
||||
ret = 1;
|
||||
int removed = TpagedListRemove(xid, list, key, keySize);
|
||||
assert(removed);
|
||||
// delete from list
|
||||
}
|
||||
Page * p = loadPage(list.page);
|
||||
int recordSize = (sizeof(short)+keySize+valueSize);
|
||||
int isBlob = recordSize >= BLOB_THRESHOLD_SIZE;
|
||||
int realSize = recordSize;
|
||||
if(isBlob) {
|
||||
recordSize = sizeof(blob_record_t);
|
||||
}
|
||||
while(slottedFreespace(p) < recordSize) {
|
||||
// load next page, update some rid somewhere
|
||||
list.slot = 0;
|
||||
list.size = sizeof(long);
|
||||
long nextPage;
|
||||
readRecord(xid, p, list, &nextPage);
|
||||
// printf("+ page = %d nextpage=%ld freespace: %d recordsize: %d\n", list.page, nextPage, slottedFreespace(p), recordSize); fflush(stdout);
|
||||
if(nextPage == 0) {
|
||||
releasePage(p);
|
||||
nextPage = TpageAlloc(xid);
|
||||
Tset(xid, list, &nextPage);
|
||||
p = loadPage(nextPage);
|
||||
// slottedPageInitialize(p);
|
||||
// ** @todo shouldn't a log entry be generated here?? */
|
||||
list.page = nextPage;
|
||||
assert(slottedFreespace(p) >= recordSize);
|
||||
long zero = 0;
|
||||
TallocFromPage(xid, list.page, sizeof(long));
|
||||
Tset(xid, list, &zero);
|
||||
} else {
|
||||
releasePage(p);
|
||||
list.page = nextPage;
|
||||
p = loadPage(nextPage);
|
||||
}
|
||||
}
|
||||
|
||||
if(isBlob) {
|
||||
recordSize = realSize;
|
||||
}
|
||||
|
||||
releasePage(p);
|
||||
|
||||
recordid rid = TallocFromPage(xid, list.page, recordSize); // Allocates a record at a location given by the caller
|
||||
short* record = malloc(recordSize);
|
||||
*record = keySize;
|
||||
memcpy((record+1), key, keySize);
|
||||
memcpy(((char*)(record+1))+keySize, value, valueSize);
|
||||
Tset(xid, rid, record);
|
||||
|
||||
return ret;
|
||||
}
|
||||
int TpagedListFind(int xid, recordid list, const byte * key, int keySize, byte ** value) {
|
||||
|
||||
long nextPage = 1;
|
||||
|
||||
while (nextPage) {
|
||||
int i;
|
||||
int pageCount = TrecordsInPage(xid, list.page);
|
||||
|
||||
// printf("%ld\n", nextPage);
|
||||
fflush(stdout);
|
||||
|
||||
for(i = 1; i < pageCount; i++) {
|
||||
recordid entry = list;
|
||||
entry.slot = i;
|
||||
int length = TrecordSize(xid, entry);
|
||||
if(length != -1) { // then entry is defined.
|
||||
short * dat = malloc(length);
|
||||
entry.size = length;
|
||||
Tread(xid, entry, dat);
|
||||
|
||||
if(*dat == keySize && !memcmp(dat+1, key, keySize)) {
|
||||
int valueSize = length-keySize-sizeof(short);
|
||||
*value = malloc(valueSize);
|
||||
|
||||
memcpy(*value, ((byte*)(dat+1))+keySize, valueSize);
|
||||
|
||||
free(dat);
|
||||
return valueSize;
|
||||
}
|
||||
free(dat);
|
||||
}
|
||||
}
|
||||
|
||||
// recordid rid = list;
|
||||
|
||||
list.slot = 0;
|
||||
list.size = sizeof(long);
|
||||
|
||||
Tread(xid, list, &nextPage);
|
||||
|
||||
list.page = nextPage;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int TpagedListRemove(int xid, recordid list, const byte * key, int keySize) {
|
||||
long nextPage = 1;
|
||||
|
||||
while (nextPage) {
|
||||
int i;
|
||||
int pageCount = TrecordsInPage(xid, list.page);
|
||||
|
||||
// printf("%ld\n", nextPage);
|
||||
fflush(stdout);
|
||||
|
||||
for(i = 1; i < pageCount; i++) {
|
||||
recordid entry = list;
|
||||
entry.slot = i;
|
||||
int length = TrecordSize(xid, entry);
|
||||
if(length != -1) { // then entry is defined.
|
||||
short * dat = malloc(length);
|
||||
entry.size = length;
|
||||
Tread(xid, entry, dat);
|
||||
|
||||
if(*dat == keySize && !memcmp(dat+1, key, keySize)) {
|
||||
Tdealloc(xid, entry);
|
||||
|
||||
free(dat);
|
||||
return 1;
|
||||
}
|
||||
free(dat);
|
||||
}
|
||||
}
|
||||
|
||||
list.slot = 0;
|
||||
list.size = sizeof(long);
|
||||
|
||||
Tread(xid, list, &nextPage);
|
||||
|
||||
list.page = nextPage;
|
||||
}
|
||||
return 0;
|
||||
|
||||
}
|
||||
int TpagedListMove(int xid, recordid start_list, recordid end_list, const byte *key, int keySize) {
|
||||
byte * value;
|
||||
int valueSize = TpagedListFind(xid, start_list, key, keySize, &value);
|
||||
if(valueSize) {
|
||||
int ret = TpagedListRemove(xid, start_list, key, keySize);
|
||||
assert(ret);
|
||||
ret = TpagedListInsert(xid, end_list, key, keySize, value, valueSize);
|
||||
assert(!ret);
|
||||
free(value);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
lladd_pagedList_iterator * TpagedListIterator(int xid, recordid list) {
|
||||
lladd_pagedList_iterator * ret = malloc(sizeof(lladd_pagedList_iterator));
|
||||
|
||||
ret->page = list.page;
|
||||
ret->slot = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int TpagedListNext(int xid, lladd_pagedList_iterator * it,
|
||||
byte ** key, int * keySize,
|
||||
byte ** value, int * valueSize) {
|
||||
// printf("next: page %d slot %d\n", it->page, it->slot);
|
||||
recordid rid;
|
||||
while(it->page) {
|
||||
while(it->slot < TrecordsInPage(xid, it->page)) {
|
||||
rid.page = it->page;
|
||||
rid.slot = it->slot;
|
||||
rid.size=TrecordSize(xid, rid);
|
||||
if(rid.size != -1) {
|
||||
// found entry!
|
||||
|
||||
byte * dat = malloc(rid.size);
|
||||
Tread(xid, rid, dat);
|
||||
|
||||
// populate / alloc pointers passed in by caller.
|
||||
|
||||
*keySize = *(short*)dat;
|
||||
*valueSize = rid.size - *keySize - sizeof(short);
|
||||
|
||||
*key = malloc(*keySize);
|
||||
*value = malloc(*valueSize);
|
||||
|
||||
memcpy(*key, ((short*)dat)+1, *keySize);
|
||||
memcpy(*value, ((byte*)(((short*)dat)+1)) + *keySize, *valueSize);
|
||||
|
||||
free(dat);
|
||||
it->slot++;
|
||||
return 1;
|
||||
}
|
||||
it->slot++;
|
||||
}
|
||||
rid.page = it->page;
|
||||
rid.slot = 0;
|
||||
rid.size = sizeof(long);
|
||||
Tread(xid, rid, &(it->page));
|
||||
it->slot = 1;
|
||||
|
||||
}
|
||||
free(it);
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
|
@ -318,21 +318,17 @@ int getRecordTypeUnlocked(int xid, Page * p, recordid rid) {
|
|||
assert(rid.page == p->id);
|
||||
|
||||
int page_type = *page_type_ptr(p);
|
||||
|
||||
if(page_type == UNINITIALIZED_PAGE) {
|
||||
return UNINITIALIZED_RECORD;
|
||||
|
||||
} else if(rid.size > BLOB_THRESHOLD_SIZE) {
|
||||
// printf("%d , %d\n", *numslots_ptr(p), *slot_length_ptr(p, rid.slot));
|
||||
return(*numslots_ptr(p) > rid.slot &&
|
||||
*slot_length_ptr(p, rid.slot) == BLOB_REC_SIZE) ?
|
||||
BLOB_RECORD : UNINITIALIZED_RECORD;
|
||||
|
||||
} else if(page_type == SLOTTED_PAGE) {
|
||||
return (*numslots_ptr(p) > rid.slot &&
|
||||
*slot_length_ptr(p, rid.slot) != INVALID_SLOT) ?
|
||||
SLOTTED_RECORD : UNINITIALIZED_RECORD;
|
||||
|
||||
if(*numslots_ptr(p) <= rid.slot || *slot_length_ptr(p, rid.slot) == INVALID_SLOT) {
|
||||
return UNINITIALIZED_PAGE;
|
||||
} else if(*slot_length_ptr(p, rid.slot) == BLOB_REC_SIZE) {
|
||||
return BLOB_RECORD;
|
||||
} else {
|
||||
return SLOTTED_RECORD;
|
||||
}
|
||||
} else if(page_type == FIXED_PAGE || page_type == ARRAY_LIST_PAGE) {
|
||||
return (fixedPageCount(p) > rid.slot) ?
|
||||
FIXED_RECORD : UNINITIALIZED_RECORD;
|
||||
|
@ -348,6 +344,20 @@ int getRecordType(int xid, Page * p, recordid rid) {
|
|||
unlock(p->rwlatch);
|
||||
return ret;
|
||||
}
|
||||
/** @todo implemenet getRecordLength for blobs and fixed length pages. */
|
||||
int getRecordSize(int xid, Page * p, recordid rid) {
|
||||
readlock(p->rwlatch, 353);
|
||||
int ret = getRecordTypeUnlocked(xid, p, rid);
|
||||
if(ret == UNINITIALIZED_RECORD) {
|
||||
ret = -1;
|
||||
} else if(ret == SLOTTED_RECORD) {
|
||||
ret = *slot_length_ptr(p, rid.slot);
|
||||
} else {
|
||||
abort(); // unimplemented for fixed length pages and blobs.
|
||||
}
|
||||
unlock(p->rwlatch);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void writeRecordUnlocked(int xid, Page * p, lsn_t lsn, recordid rid, const void *dat) {
|
||||
|
||||
|
|
|
@ -298,12 +298,26 @@ void pageRealloc(Page * p, int id);
|
|||
/*int pageAlloc() ;*/
|
||||
/**
|
||||
obtains the type of the record pointed to by rid.
|
||||
|
||||
@return UNINITIALIZED_RECORD, BLOB_RECORD, SLOTTED_RECORD, or FIXED_RECORD.
|
||||
*/
|
||||
|
||||
|
||||
int getRecordType(int xid, Page * p, recordid rid);
|
||||
|
||||
int getRecordSize(int xid, Page * p, recordid rid);
|
||||
/**
|
||||
same as getRecordType(), but does not obtain a lock.
|
||||
*/
|
||||
int getRecordTypeUnlocked(int xid, Page * p, recordid rid);
|
||||
/**
|
||||
return the length of the record rid. (the rid parameter's size field will be ignored)
|
||||
|
||||
@todo implement getRecordLength for blobs and fixed length pages.
|
||||
|
||||
@return -1 if the field does not exist, the size of the field otherwise.
|
||||
*/
|
||||
int getRecordLength(int xid, Page * p, recordid rid);
|
||||
|
||||
END_C_DECLS
|
||||
|
||||
|
|
|
@ -160,17 +160,12 @@ int slottedFreespace(Page * page) {
|
|||
recordid slottedPreRalloc(int xid, long size, Page ** pp) {
|
||||
|
||||
recordid ret;
|
||||
/* Page * p; */
|
||||
|
||||
/* DEBUG("Rallocing record of size %ld\n", (long int)size); */
|
||||
|
||||
assert(size < BLOB_THRESHOLD_SIZE);
|
||||
|
||||
/* pthread_mutex_lock(&lastFreepage_mutex); */
|
||||
/** @todo is ((unsigned int) foo) == -1 portable? Gotta love C.*/
|
||||
/*printf("lastFreepage %d\n", lastFreepage); fflush(NULL); */
|
||||
|
||||
if(lastFreepage == -1) {
|
||||
lastFreepage = TpageAlloc(xid/*, SLOTTED_PAGE*/);
|
||||
lastFreepage = TpageAlloc(xid);
|
||||
*pp = loadPage(lastFreepage);
|
||||
assert(*page_type_ptr(*pp) == UNINITIALIZED_PAGE);
|
||||
slottedPageInitialize(*pp);
|
||||
|
@ -180,23 +175,33 @@ recordid slottedPreRalloc(int xid, long size, Page ** pp) {
|
|||
|
||||
if(slottedFreespace(*pp) < size ) {
|
||||
releasePage(*pp);
|
||||
lastFreepage = TpageAlloc(xid/*, SLOTTED_PAGE*/);
|
||||
lastFreepage = TpageAlloc(xid);
|
||||
*pp = loadPage(lastFreepage);
|
||||
slottedPageInitialize(*pp);
|
||||
}
|
||||
|
||||
ret = slottedRawRalloc(*pp, size);
|
||||
|
||||
/* releasePage(p); */ /* This gets called in Talloc() now. That prevents the page from being prematurely stolen. */
|
||||
|
||||
/* pthread_mutex_unlock(&lastFreepage_mutex); */
|
||||
|
||||
DEBUG("alloced rid = {%d, %d, %ld}\n", ret.page, ret.slot, ret.size);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
recordid slottedPreRallocFromPage(int xid, long page, long size, Page **pp) {
|
||||
recordid ret;
|
||||
|
||||
*pp = loadPage(page);
|
||||
|
||||
assert(slottedFreespace(*pp) >= size);
|
||||
if(*page_type_ptr(*pp) == UNINITIALIZED_PAGE) {
|
||||
slottedPageInitialize(*pp);
|
||||
}
|
||||
assert(*page_type_ptr(*pp) == SLOTTED_PAGE);
|
||||
ret = slottedRawRalloc(*pp, size);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
recordid slottedRawRalloc(Page * page, int size) {
|
||||
|
||||
|
|
|
@ -92,6 +92,12 @@ void slottedPageInitialize(Page * p);
|
|||
*
|
||||
*/
|
||||
recordid slottedPreRalloc(int xid, long size, Page**p);
|
||||
/**
|
||||
Identical to slottedPreRalloc, but allows the user to specify which page the
|
||||
record should be allocated in.
|
||||
*/
|
||||
recordid slottedPreRallocFromPage(int xid, long page, long size, Page**p);
|
||||
|
||||
/**
|
||||
* The second phase of slot allocation. Called after the log entry
|
||||
* has been produced, and during recovery.
|
||||
|
|
|
@ -39,10 +39,10 @@ authors grant the U.S. Government and others acting in its behalf
|
|||
permission to use and distribute the software in accordance with the
|
||||
terms specified in this license.
|
||||
---*/
|
||||
#include <string.h>
|
||||
#include "../../src/apps/cht/cht.h"
|
||||
#include <assert.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
/** Thanks, jbhtsimple.c!! */
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
INCLUDES = @CHECK_CFLAGS@
|
||||
if HAVE_CHECK
|
||||
## Had to disable check_lht because lht needs to be rewritten.
|
||||
TESTS = check_logEntry check_logWriter check_page check_operations check_transactional2 check_recovery check_blobRecovery check_bufferManager check_indirect check_lladdhash check_pageOperations check_linearHash check_logicalLinearHash check_header check_linkedListNTA check_linearHashNTA
|
||||
TESTS = check_logEntry check_logWriter check_page check_operations check_transactional2 check_recovery check_blobRecovery check_bufferManager check_indirect check_lladdhash check_pageOperations check_linearHash check_logicalLinearHash check_header check_linkedListNTA check_linearHashNTA check_pageOrientedList
|
||||
else
|
||||
TESTS =
|
||||
endif
|
||||
noinst_PROGRAMS = $(TESTS)
|
||||
LDADD = @CHECK_LIBS@ $(top_builddir)/src/lladd/liblladd.a $(top_builddir)/src/pbl/libpbl.a $(top_builddir)/src/libdfa/librw.a # -lefence
|
||||
CLEANFILES = check_lht.log check_logEntry.log storefile.txt logfile.txt blob0_file.txt blob1_file.txt check_blobRecovery.log check_logWriter.log check_operations.log check_recovery.log check_transactional2.log check_page.log check_bufferManager.log check_indirect.log check_bufferMananger.log check_lladdhash.log check_pageOperations.log check_linearhash.log check_linkedListNTA.log check_linearHashNTA.log
|
||||
CLEANFILES = check_lht.log check_logEntry.log storefile.txt logfile.txt blob0_file.txt blob1_file.txt check_blobRecovery.log check_logWriter.log check_operations.log check_recovery.log check_transactional2.log check_page.log check_bufferManager.log check_indirect.log check_bufferMananger.log check_lladdhash.log check_pageOperations.log check_linearhash.log check_linkedListNTA.log check_linearHashNTA.log check_pageOrientedListNTA.log
|
||||
AM_CFLAGS= -g -Wall -pedantic -std=gnu99
|
||||
|
|
|
@ -208,7 +208,7 @@ START_TEST(transactionalLinearHashTest)
|
|||
|
||||
int xid = Tbegin();
|
||||
|
||||
recordid foo = Talloc(xid, 1);
|
||||
Talloc(xid, 1); // discard alloced rid...
|
||||
|
||||
// printf("%d %d %ld\n", foo.page, foo.slot, foo.size);
|
||||
|
||||
|
|
|
@ -399,11 +399,9 @@ START_TEST(pageCheckSlotTypeTest) {
|
|||
assert(getRecordType(xid, p, bad) == UNINITIALIZED_RECORD);
|
||||
bad.size = 100000;
|
||||
assert(getRecordType(xid, p, bad) == UNINITIALIZED_RECORD);
|
||||
/** @todo this test could be better... The behavior for getRecordType in this
|
||||
case (valid slot, invalid size) is a bit ambiguous. Maybe an INVALID_RECORDID
|
||||
would be an appropriate return value... */
|
||||
/** getRecordType now ignores the size field, so this (correctly) returns SLOTTED_RECORD */
|
||||
bad.slot = slot.slot;
|
||||
assert(getRecordType(xid, p, bad) == UNINITIALIZED_RECORD);
|
||||
assert(getRecordType(xid, p, bad) == SLOTTED_RECORD);
|
||||
|
||||
releasePage(p);
|
||||
|
||||
|
@ -447,11 +445,9 @@ START_TEST(pageTrecordTypeTest) {
|
|||
assert(TrecordType(xid, bad) == UNINITIALIZED_RECORD);
|
||||
bad.size = 100000;
|
||||
assert(TrecordType(xid, bad) == UNINITIALIZED_RECORD);
|
||||
/** @todo this test could be better... The behavior for getRecordType in this
|
||||
case (valid slot, invalid size) is a bit ambiguous. Maybe an INVALID_RECORDID
|
||||
would be an appropriate return value... */
|
||||
|
||||
bad.slot = slot.slot;
|
||||
assert(TrecordType(xid, bad) == UNINITIALIZED_RECORD);
|
||||
assert(TrecordType(xid, bad) == SLOTTED_RECORD);
|
||||
|
||||
Tcommit(xid);
|
||||
|
||||
|
|
195
test/lladd/check_pageOrientedList.c
Normal file
195
test/lladd/check_pageOrientedList.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*---
|
||||
This software is copyrighted by the Regents of the University of
|
||||
California, and other parties. The following terms apply to all files
|
||||
associated with the software unless explicitly disclaimed in
|
||||
individual files.
|
||||
|
||||
The authors hereby grant permission to use, copy, modify, distribute,
|
||||
and license this software and its documentation for any purpose,
|
||||
provided that existing copyright notices are retained in all copies
|
||||
and that this notice is included verbatim in any distributions. No
|
||||
written agreement, license, or royalty fee is required for any of the
|
||||
authorized uses. Modifications to this software may be copyrighted by
|
||||
their authors and need not follow the licensing terms described here,
|
||||
provided that the new terms are clearly indicated on the first page of
|
||||
each file where they apply.
|
||||
|
||||
IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
|
||||
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
|
||||
ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
|
||||
DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
|
||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND
|
||||
NON-INFRINGEMENT. THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, AND
|
||||
THE AUTHORS AND DISTRIBUTORS HAVE NO OBLIGATION TO PROVIDE
|
||||
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
|
||||
|
||||
GOVERNMENT USE: If you are acquiring this software on behalf of the
|
||||
U.S. government, the Government shall have only "Restricted Rights" in
|
||||
the software and related documentation as defined in the Federal
|
||||
Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2). If you are
|
||||
acquiring the software on behalf of the Department of Defense, the
|
||||
software shall be classified as "Commercial Computer Software" and the
|
||||
Government shall have only "Restricted Rights" as defined in Clause
|
||||
252.227-7013 (c) (1) of DFARs. Notwithstanding the foregoing, the
|
||||
authors grant the U.S. Government and others acting in its behalf
|
||||
permission to use and distribute the software in accordance with the
|
||||
terms specified in this license.
|
||||
---*/
|
||||
|
||||
#include <config.h>
|
||||
#include <check.h>
|
||||
|
||||
#include <lladd/transactional.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include "../check_includes.h"
|
||||
|
||||
#define LOG_NAME "check_pageOrientedListNTA.log"
|
||||
/** @test */
|
||||
#define NUM_ENTRIES 2000
|
||||
START_TEST(pagedListCheck) {
|
||||
Tinit();
|
||||
|
||||
int xid = Tbegin();
|
||||
|
||||
recordid list = TpagedListAlloc(xid);
|
||||
|
||||
int a;
|
||||
recordid b;
|
||||
int i;
|
||||
|
||||
printf("\n");
|
||||
for(i = 0; i < NUM_ENTRIES; i++) {
|
||||
|
||||
if(!(i % (NUM_ENTRIES/10))) {
|
||||
printf("."); fflush(stdout);
|
||||
}
|
||||
|
||||
a = i;
|
||||
b.page = i+1;
|
||||
b.slot = i+2;
|
||||
b.size = i+3;
|
||||
|
||||
int ret = TpagedListInsert(xid, list, (byte*)&a, sizeof(int), (byte*)&b, sizeof(recordid));
|
||||
|
||||
assert(!ret);
|
||||
|
||||
recordid * bb;
|
||||
ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb);
|
||||
|
||||
assert(ret == sizeof(recordid));
|
||||
assert(!memcmp(bb, &b, sizeof(recordid)));
|
||||
}
|
||||
Tcommit(xid);
|
||||
printf("\n");
|
||||
xid = Tbegin();
|
||||
for(i = 0; i < NUM_ENTRIES; i++ ) {
|
||||
|
||||
if(!(i % (NUM_ENTRIES/10))) {
|
||||
printf("."); fflush(stdout);
|
||||
}
|
||||
|
||||
a = i;
|
||||
b.page = i+1;
|
||||
b.slot = i+2;
|
||||
b.size = i+3;
|
||||
|
||||
recordid * bb;
|
||||
int ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb);
|
||||
|
||||
assert(ret == sizeof(recordid));
|
||||
assert(!memcmp(bb, &b, sizeof(recordid)));
|
||||
|
||||
|
||||
if(!(i % 10)) {
|
||||
|
||||
ret = TpagedListRemove(xid, list, (byte*)&a, sizeof(int));
|
||||
|
||||
assert(ret);
|
||||
|
||||
free(bb);
|
||||
bb = 0;
|
||||
|
||||
ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb);
|
||||
|
||||
assert(!ret);
|
||||
assert(!bb);
|
||||
}
|
||||
}
|
||||
Tabort(xid);
|
||||
|
||||
xid = Tbegin();
|
||||
printf("\n");
|
||||
for(i = 0; i < NUM_ENTRIES; i++) {
|
||||
|
||||
if(!(i % (NUM_ENTRIES/10))) {
|
||||
printf("."); fflush(stdout);
|
||||
}
|
||||
|
||||
a = i;
|
||||
b.page = i+1;
|
||||
b.slot = i+2;
|
||||
b.size = i+3;
|
||||
|
||||
recordid * bb;
|
||||
int ret = TpagedListFind(xid, list, (byte*)&a, sizeof(int), (byte**)&bb);
|
||||
|
||||
assert(ret == sizeof(recordid));
|
||||
assert(!memcmp(bb, &b, sizeof(recordid)));
|
||||
}
|
||||
|
||||
byte * seen = calloc(NUM_ENTRIES, sizeof(byte));
|
||||
|
||||
lladd_pagedList_iterator * it = TpagedListIterator(xid, list);
|
||||
|
||||
int keySize;
|
||||
int valueSize;
|
||||
int * key = 0;
|
||||
recordid * value = 0;
|
||||
|
||||
while(TpagedListNext(xid, it, (byte**)&key, &keySize, (byte**)&value, &valueSize)) {
|
||||
assert(!seen[*key]);
|
||||
seen[*key] = 1;
|
||||
|
||||
assert(value->page == *key+1);
|
||||
assert(value->slot == *key+2);
|
||||
assert(value->size == *key+3);
|
||||
|
||||
|
||||
free(key);
|
||||
free(value);
|
||||
key = 0;
|
||||
value = 0;
|
||||
}
|
||||
|
||||
for(i = 0; i < NUM_ENTRIES; i++) {
|
||||
assert(seen[i] == 1);
|
||||
}
|
||||
|
||||
Tcommit(xid);
|
||||
Tdeinit();
|
||||
|
||||
} END_TEST
|
||||
|
||||
Suite * check_suite(void) {
|
||||
Suite *s = suite_create("pageOrientedList");
|
||||
/* Begin a new test */
|
||||
TCase *tc = tcase_create("pageOrientedList");
|
||||
|
||||
/* Sub tests are added, one per line, here */
|
||||
|
||||
tcase_add_test(tc, pagedListCheck);
|
||||
|
||||
/* --------------------------------------------- */
|
||||
|
||||
tcase_add_checked_fixture(tc, setup, teardown);
|
||||
|
||||
suite_add_tcase(s, tc);
|
||||
return s;
|
||||
}
|
||||
|
||||
#include "../check_setup.h"
|
Loading…
Reference in a new issue