1 /***************************************************************************
2 * Copyright (C) 2007 by www.databasecache.com *
3 * Contact: praba_tuty@databasecache.com *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
15 ***************************************************************************/
17 #include<CatalogTables.h>
23 #include<PredicateImpl.h>
25 //converts the given value into 0 to TRIE_SIZE
26 //value could be 0-9, A-Z, a-z and special chars
27 char hashString(char value
)
29 if (value
> 47 && value
<58) return value
- 48;
30 else if (value
> 64 && value
<91 ) return (value
- 64)/3;
31 else if (value
> 96 && value
<123) return (value
- 96)/3;
32 //for all special and other chars return 9
36 void TrieIndex::computeHashValues(DataType type
, void *key
, char *in
, int length
)
38 if (typeInt
== type
) {
40 sprintf(in
, "%d", val
);
44 in
[i
] = hashString(in
[i
]);
45 printDebug(DM_TrieIndex
, "Hash Value Pos:%d Hash:%d\n", i
, in
[i
]);
49 }else if (typeLongLong
== type
) {
50 long val
= *(long*)key
;
51 sprintf(in
, "%lld", val
);
55 in
[i
] = hashString(in
[i
]);
56 printDebug(DM_TrieIndex
, "Hash Value Pos:%d Hash:%d\n", i
, in
[i
]);
60 }else if (typeString
== type
|| typeVarchar
== type
) {
61 char *val
= (char*) key
;
65 in
[i
] = hashString(*val
);
66 printDebug(DM_TrieIndex
, "Hash Value Pos:%d Hash:%d\n", i
, in
[i
]);
72 printError(ErrSysFatal
,"Type not supported for trie hashing\n");
76 bool TrieIndex::checkForUniqueKey(IndexNode
*head
, IndexInfo
*info
, void *tuple
)
78 if (!head
) return false;
79 int offset
= info
->fldOffset
;
80 DataType type
= info
->type
;
81 BucketList
list(head
);
82 BucketIter iter
= list
.getIterator();
85 printDebug(DM_TrieIndex
, "TrieIndex insert Checking for unique");
87 while((node
= iter
.next()) != NULL
)
89 bucketTuple
= node
->ptrToTuple_
;
90 if (type
!= typeVarchar
)
91 res
= AllDataType::compareVal((void*)((char*)bucketTuple
+offset
),
92 (void*)((char*)tuple
+offset
), OpEquals
,type
, info
->compLength
);
94 res
= AllDataType::compareVal((void*)*(long *)((char*)bucketTuple
+offset
),
95 (void*)*(long *)((char*)tuple
+offset
), OpEquals
,type
, info
->compLength
);
98 printError(ErrUnique
, "Unique key violation");
106 DbRetVal
TrieIndex::insert(TableImpl
*tbl
, Transaction
*tr
, void *indexPtr
, IndexInfo
*indInfo
, void *tuple
, bool loadFlag
)
109 HashIndexInfo
*info
= (HashIndexInfo
*) indInfo
;
110 CINDEX
*iptr
= (CINDEX
*)indexPtr
;
111 char hashValue
[TRIE_MAX_LENGTH
];
112 void *keyPtr
=(void*)((char*)tuple
+ info
->fldOffset
);
113 //for varchar ptr to value is stored in tuple
114 if (info
->type
== typeVarchar
) keyPtr
= (void *) *(long *) keyPtr
;
115 computeHashValues(info
->type
, keyPtr
, hashValue
, info
->compLength
);
116 Chunk
*hIdxNodeChunk
= (Chunk
*)iptr
->hashNodeChunk_
;
117 Chunk
*chunk
= (Chunk
*) iptr
->chunkPtr_
;
118 ChunkIterator citer
= CatalogTableINDEX::getIterator(indexPtr
);
119 TrieNode
* start
= (TrieNode
*)citer
.nextElement();
120 //if(start) displayAll(start);
123 //first value is inserted into the trie index
124 start
= (TrieNode
*) chunk
->tryAllocate(tbl
->db_
, &rv
);
126 printError(ErrSysInternal
, "Could not allocate trie node %d\n", rv
);
131 while(-1 != hashValue
[cnt
+1]) {
132 prev
= (char**)&(start
->next_
[hashValue
[cnt
]]);
135 start
= (TrieNode
*) *prev
;
140 TrieNode
*newNode
= (TrieNode
*) chunk
->tryAllocate(tbl
->db_
, &rv
);
141 if (NULL
== newNode
) {
142 printError(ErrSysInternal
, "Could not allocate trie node %d\n", rv
);
145 //set the previous trie node ptr to this node
146 *prev
= (char*)newNode
;
150 void **ptr
= (void**)&(start
->head_
[hashValue
[cnt
]]);
151 rv
= addToValueList(tbl
->db_
, ptr
, hIdxNodeChunk
, indInfo
, tuple
, keyPtr
);
152 if (OK
!= rv
) return rv
;
154 //create logical undo log
155 TrieUndoLogInfo hInfo
;
156 hInfo
.metaData_
= tbl
->db_
->getMetaDataPtr();
157 hInfo
.bucket_
= NULL
;
158 hInfo
.tuple_
= tuple
;
159 hInfo
.keyPtr_
= keyPtr
;
162 rv
= tr
->appendLogicalTrieUndoLog(tbl
->sysDB_
, InsertTrieIndexOperation
, &hInfo
, sizeof(TrieUndoLogInfo
));
163 //TODO:: if it fails need to remove the element from the bucket
167 DbRetVal
TrieIndex::addToValueList(Database
*db
, void **ptr
, Chunk
*hIdxNodeChunk
,
168 IndexInfo
*info
, void *tuple
, void *keyPtr
)
170 IndexNode
*head
= (IndexNode
*) *ptr
;
173 bool isKeyPresent
= checkForUniqueKey(head
, info
, tuple
);
174 if (isKeyPresent
) return ErrUnique
;
176 printDebug(DM_TrieIndex
, "TrieIndex insert into bucket list");
180 printDebug(DM_TrieIndex
, "TrieIndex insert head is empty");
181 IndexNode
*firstNode
= NULL
;
182 firstNode
= (IndexNode
*) hIdxNodeChunk
->tryAllocate(db
, &rv
);
183 if (firstNode
== NULL
){
184 printError(rv
, "Unable to allocate index node for Trie index after retry");
187 firstNode
->ptrToKey_
= keyPtr
;
188 firstNode
->ptrToTuple_
= tuple
;
189 firstNode
->next_
= NULL
;
190 if (0 != Mutex::CASL((long*)ptr
, 0, (long)firstNode
)) {
191 printError(ErrLockTimeOut
, "Trie Index bucket lock timeout.. retry");
192 hIdxNodeChunk
->free(db
, firstNode
);
193 return ErrLockTimeOut
;
195 printDebug(DM_TrieIndex
, "TrieIndex insert new node %x in empty bucket", head
);
199 BucketList
list(head
);
200 rv
= list
.insert(hIdxNodeChunk
, db
, keyPtr
, tuple
);
202 printError(rv
, "unable to insert into Trie bucketlist rv:%d", rv
);
209 DbRetVal
TrieIndex::removeFromValueList(Database
*db
, void **ptr
, Chunk
*hIdxNodeChunk
, void *tuple
, void *keyPtr
)
211 IndexNode
*head
= (IndexNode
*) *ptr
;
212 printDebug(DM_TrieIndex
, "TrieIndex remove from bucket list");
216 printError(rv
, "Trie value list head is empty");
221 BucketList
list(head
);
222 rv
= list
.remove(hIdxNodeChunk
, db
, keyPtr
);
226 printDebug(DM_TrieIndex
, "Removing trie index node from head ");
227 if (0 != Mutex::CASL((long*)ptr
,
228 (long)head
, (long)list
.getBucketListHead())) {
229 printError(ErrSysFatal
, "Lock time out for trie bucket. retry\n");
230 return ErrLockTimeOut
;
234 printError(rv
, "unable to remove from Trie bucketlist rv:%d", rv
);
242 DbRetVal
TrieIndex::remove(TableImpl
*tbl
, Transaction
*tr
, void *indexPtr
, IndexInfo
*indInfo
, void *tuple
, bool loadFlag
)
245 HashIndexInfo
*info
= (HashIndexInfo
*) indInfo
;
246 CINDEX
*iptr
= (CINDEX
*)indexPtr
;
247 char hashValue
[TRIE_MAX_LENGTH
];
248 void *keyPtr
=(void*)((char*)tuple
+ info
->fldOffset
);
249 Chunk
*hIdxNodeChunk
= (Chunk
*)iptr
->hashNodeChunk_
;
250 //for varchar ptr to value is stored in tuple
251 if (info
->type
== typeVarchar
) keyPtr
= (void *) *(long *) keyPtr
;
252 computeHashValues(info
->type
, keyPtr
, hashValue
, info
->compLength
);
253 ChunkIterator citer
= CatalogTableINDEX::getIterator(indexPtr
);
254 TrieNode
* start
= (TrieNode
*)citer
.nextElement();
257 printError(ErrSysInternal
, "No trie nodes found %d\n", rv
);
261 while(-1 != hashValue
[cnt
+1]) {
262 iter
= (char**)&(start
->next_
[hashValue
[cnt
]]);
265 printError(ErrNotFound
, "No trie node found %d\n", rv
);
268 //traverse till the end
269 start
= (TrieNode
*) *iter
;
272 void **ptr
= (void**)&(start
->head_
[hashValue
[cnt
]]);
273 rv
= removeFromValueList(tbl
->db_
, ptr
, hIdxNodeChunk
, tuple
, keyPtr
);
274 if (OK
!= rv
) return rv
;
276 //create logical undo log
277 TrieUndoLogInfo hInfo
;
278 hInfo
.metaData_
= tbl
->db_
->getMetaDataPtr();
279 hInfo
.bucket_
= NULL
;
280 hInfo
.tuple_
= tuple
;
281 hInfo
.keyPtr_
= keyPtr
;
284 rv
= tr
->appendLogicalTrieUndoLog(tbl
->sysDB_
, DeleteTrieIndexOperation
, &hInfo
, sizeof(TrieUndoLogInfo
));
285 //TODO:: if it fails need to remove the element from the bucket
290 DbRetVal
TrieIndex::update(TableImpl
*tbl
, Transaction
*tr
, void *indexPtr
, IndexInfo
*indInfo
, void *tuple
, bool loadFlag
)
296 DbRetVal
TrieIndex::insertLogicalUndoLog(Database
*sysdb
, void *data
)
298 TrieUndoLogInfo
*info
= (TrieUndoLogInfo
*) data
;
299 Chunk
*hChunk
= (Chunk
*) info
->hChunk_
;
301 db
.setMetaDataPtr((DatabaseMetaData
*) info
->metaData_
);
302 db
.setProcSlot(sysdb
->procSlot
);
303 IndexNode
*head
= (IndexNode
*)((Bucket
*)info
->bucket_
)->bucketList_
;
304 BucketList
list(head
);
305 DbRetVal rv
= list
.insert(hChunk
, &db
, info
->keyPtr_
, info
->tuple_
);
308 printError(ErrLockTimeOut
, "Unable to add to bucket..retry\n");
309 return ErrLockTimeOut
;
314 DbRetVal
TrieIndex::deleteLogicalUndoLog(Database
*sysdb
, void *data
)
316 TrieUndoLogInfo
*info
= (TrieUndoLogInfo
*) data
;
317 Chunk
*hChunk
= (Chunk
*) info
->hChunk_
;
319 db
.setMetaDataPtr((DatabaseMetaData
*)info
->metaData_
);
320 db
.setProcSlot(sysdb
->procSlot
);
321 IndexNode
*head
= (IndexNode
*)((Bucket
*)info
->bucket_
)->bucketList_
;
322 BucketList
list(head
);
323 DbRetVal rc
= list
.remove(hChunk
, &db
, info
->keyPtr_
);
325 if (0 != Mutex::CASL((long*)& (((Bucket
*)info
->bucket_
)->bucketList_
),
326 (long)(((Bucket
*)info
->bucket_
)->bucketList_
),
327 (long)list
.getBucketListHead()))
329 printError(ErrLockTimeOut
, "Unable to set the head of trie index bucket\n");
330 return ErrLockTimeOut
;
333 }else if (rc
!= OK
) {
334 printError(ErrLockTimeOut
, "Unable to remove hash index node");
335 return ErrLockTimeOut
;
339 void TrieIndex::displayAll(TrieNode
*start
, int level
)
341 printTrieNode(start
, level
);
343 for (int i
=0; i
< TRIE_SIZE
; i
++)
345 if (start
->next_
[i
]) displayAll(start
->next_
[i
], level
);
348 void TrieIndex::printTrieNode(TrieNode
*node
, int level
)
350 printf("Trie %x Level %d child:", node
, level
);
351 for (int i
=0; i
< TRIE_SIZE
; i
++)
353 printf("%x ", node
->next_
[i
]);
355 printf("bucket:", node
);
356 for (int i
=0; i
< TRIE_SIZE
; i
++)
358 printf("%x ", node
->head_
[i
]);
359 if ( node
->head_
[i
]) {
361 BucketList
list(node
->head_
[i
]);