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 /* Defines `hashpjw' function by P.J. Weinberger
26 [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
29 unsigned int hashString(char *strVal
)
37 hval
+= (unsigned int) *str
++;
38 g
= hval
& ((unsigned int) 0xf << (32 - 4));
41 hval
^= g
>> (32 - 8);
48 unsigned int HashIndex::computeHashBucket(DataType type
, void *key
, int noOfBuckets
)
56 return val
% noOfBuckets
;
61 long val
= *(long*)key
;
62 return val
% noOfBuckets
;
67 unsigned long val
= *(unsigned long*)key
;
68 return val
% noOfBuckets
;
73 long long val
= *(long long*)key
;
74 return val
% noOfBuckets
;
79 short val
= *(short*)key
;
80 return val
% noOfBuckets
;
85 ByteInt val
= *(ByteInt
*)key
;
86 return val
% noOfBuckets
;
92 return val
% noOfBuckets
;
98 return val
% noOfBuckets
;
103 TimeStamp val
= *(TimeStamp
*)key
;
104 //TODO return val % noOfBuckets;
123 unsigned int val
= hashString((char*)key
);
124 return val
% noOfBuckets
;
138 //TODO::composite keys are not supported currently
139 DbRetVal
HashIndex::insert(TableImpl
*tbl
, Transaction
*tr
, void *indexPtr
, IndexInfo
*indInfo
, void *tuple
, bool undoFlag
)
141 SingleFieldHashIndexInfo
*info
= (SingleFieldHashIndexInfo
*) indInfo
;
142 INDEX
*iptr
= (INDEX
*)indexPtr
;
144 DataType type
= info
->type
;
145 char *name
= info
->fldName
;
146 int offset
= info
->offset
;
147 int noOfBuckets
= info
->noOfBuckets
;
148 int length
= info
->length
;
150 printDebug(DM_HashIndex
, "Inserting hash index node for field %s", name
);
151 ChunkIterator citer
= CatalogTableINDEX::getIterator(indexPtr
);
152 Bucket
* buckets
= (Bucket
*)citer
.nextElement();
153 void *keyPtr
=(void*)((char*)tuple
+ offset
);
155 int bucketNo
= computeHashBucket(type
,
156 keyPtr
, noOfBuckets
);
157 printDebug(DM_HashIndex
, "HashIndex insert bucketno %d", bucketNo
);
158 Bucket
*bucket
= &(buckets
[bucketNo
]);
160 int ret
= bucket
->mutex_
.getLock(tbl
->db_
->procSlot
);
163 printError(ErrLockTimeOut
,"Unable to acquire bucket Mutex for bucket %d",bucketNo
);
164 return ErrLockTimeOut
;
166 HashIndexNode
*head
= (HashIndexNode
*) bucket
->bucketList_
;
169 BucketList
list(head
);
170 BucketIter iter
= list
.getIterator();
173 printDebug(DM_HashIndex
, "HashIndex insert Checking for unique");
174 while((node
= iter
.next()) != NULL
)
176 bucketTuple
= node
->ptrToTuple_
;
177 if (AllDataType::compareVal((void*)((char*)bucketTuple
+offset
),
178 (void*)((char*)tuple
+offset
), OpEquals
,type
, length
))
180 printError(ErrUnique
, "Unique key violation");
181 bucket
->mutex_
.releaseLock(tbl
->db_
->procSlot
);
187 printDebug(DM_HashIndex
, "HashIndex insert into bucket list");
190 printDebug(DM_HashIndex
, "HashIndex insert head is empty");
191 HashIndexNode
*firstNode
= (HashIndexNode
*)(((Chunk
*)iptr
->hashNodeChunk_
)->allocate(tbl
->db_
));
192 firstNode
->ptrToKey_
= keyPtr
;
193 firstNode
->ptrToTuple_
= tuple
;
194 firstNode
->next_
= NULL
;
195 bucket
->bucketList_
= (HashIndexNode
*)firstNode
;
196 printDebug(DM_HashIndex
, "HashIndex insert new node %x in empty bucket", bucket
->bucketList_
);
200 BucketList
list(head
);
201 rc
= list
.insert((Chunk
*)iptr
->hashNodeChunk_
, tbl
->db_
, keyPtr
, tuple
);
203 bucket
->mutex_
.releaseLock(tbl
->db_
->procSlot
);
210 rc
= tr
->appendLogicalUndoLog(tbl
->sysDB_
, InsertHashIndexOperation
,
211 tuple
, sizeof(void*), indexPtr
);
214 BucketList
list(head
);
215 rc
= list
.remove((Chunk
*)iptr
->hashNodeChunk_
, tbl
->db_
, keyPtr
);
216 if (rc
!=OK
) printError(ErrSysFatal
, "double failure on undo log insert followed by hash bucket list remove\n");
220 bucket
->mutex_
.releaseLock(tbl
->db_
->procSlot
);
225 //TODO::composite keys are not supported currently
226 DbRetVal
HashIndex::remove(TableImpl
*tbl
, Transaction
*tr
, void *indexPtr
, IndexInfo
*indInfo
, void *tuple
, bool undoFlag
)
228 INDEX
*iptr
= (INDEX
*)indexPtr
;
230 SingleFieldHashIndexInfo
*info
= (SingleFieldHashIndexInfo
*) indInfo
;
231 DataType type
= info
->type
;
232 char *name
= info
->fldName
;
233 int offset
= info
->offset
;
234 int noOfBuckets
= info
->noOfBuckets
;
236 printDebug(DM_HashIndex
, "Removing hash index node for field %s", name
);
237 ChunkIterator citer
= CatalogTableINDEX::getIterator(indexPtr
);
238 Bucket
* buckets
= (Bucket
*)citer
.nextElement();
239 void *keyPtr
=(void*)((char*)tuple
+ offset
);
241 int bucket
= HashIndex::computeHashBucket(type
, keyPtr
, noOfBuckets
);
243 Bucket
*bucket1
= &buckets
[bucket
];
245 int ret
= bucket1
->mutex_
.getLock(tbl
->db_
->procSlot
);
248 printError(ErrLockTimeOut
,"Unable to acquire bucket Mutex for bucket %d",bucket
);
249 return ErrLockTimeOut
;
251 HashIndexNode
*head
= (HashIndexNode
*) bucket1
->bucketList_
;
253 if (!head
) { printError(ErrNotExists
, "Hash index does not exist:should never happen\n"); return ErrNotExists
; }
254 BucketList
list(head
);
255 printDebug(DM_HashIndex
, "Removing hash index node from head %x", head
);
257 DbRetVal rc
= list
.remove((Chunk
*)iptr
->hashNodeChunk_
, tbl
->db_
, keyPtr
);
260 printDebug(DM_HashIndex
, "Removing hash index node from head with only none node");
261 bucket1
->bucketList_
= 0;
265 rc
=tr
->appendLogicalUndoLog(tbl
->sysDB_
, DeleteHashIndexOperation
,
266 tuple
, sizeof(void*), indexPtr
);
269 //TODO::add it back to the bucketlist
272 bucket1
->mutex_
.releaseLock(tbl
->db_
->procSlot
);
276 //TODO::composite keys are not supported currently
277 DbRetVal
HashIndex::update(TableImpl
*tbl
, Transaction
*tr
, void *indexPtr
, IndexInfo
*indInfo
, void *tuple
, bool undoFlag
)
279 INDEX
*iptr
= (INDEX
*)indexPtr
;
281 SingleFieldHashIndexInfo
*info
= (SingleFieldHashIndexInfo
*) indInfo
;
282 DataType type
= info
->type
;
283 char *name
= info
->fldName
;
284 int offset
= info
->offset
;
285 int noOfBuckets
= info
->noOfBuckets
;
287 printDebug(DM_HashIndex
, "Updating hash index node for field %s", name
);
289 //check whether the index key is updated or not
290 //if it is not updated return from here
291 void *keyPtr
=(void*)((char*)tuple
+ offset
);
292 //Iterate through the bind list and check
293 FieldIterator fldIter
= tbl
->fldList_
.getIterator();
295 while (fldIter
.hasElement())
297 FieldDef def
= fldIter
.nextElement();
298 if (0 == strcmp(def
.fldName_
, name
))
300 if (NULL
== def
.bindVal_
)
302 bool result
= AllDataType::compareVal(keyPtr
, def
.bindVal_
,
303 OpEquals
, def
.type_
, def
.length_
);
304 if (result
) return OK
; else newKey
= def
.bindVal_
;
307 printDebug(DM_HashIndex
, "Updating hash index node: Key value is updated");
311 printError(ErrSysInternal
,"Internal Error:: newKey is Null");
312 return ErrSysInternal
;
314 ChunkIterator citer
= CatalogTableINDEX::getIterator(indexPtr
);
316 Bucket
* buckets
= (Bucket
*)citer
.nextElement();
318 //remove the node whose key is updated
319 int bucketNo
= computeHashBucket(type
,
320 keyPtr
, noOfBuckets
);
321 printDebug(DM_HashIndex
, "Updating hash index node: Bucket for old value is %d", bucketNo
);
322 Bucket
*bucket
= &buckets
[bucketNo
];
324 //it may run into deadlock, when two threads updates tuples which falls in
325 //same buckets.So take both the mutex one after another, which will reduce the
327 int ret
= bucket
->mutex_
.getLock(tbl
->db_
->procSlot
);
330 printError(ErrLockTimeOut
,"Unable to acquire bucket Mutex for bucket %d",bucketNo
);
331 return ErrLockTimeOut
;
333 //insert node for the updated key value
334 int newBucketNo
= computeHashBucket(type
,
335 newKey
, noOfBuckets
);
336 printDebug(DM_HashIndex
, "Updating hash index node: Bucket for new value is %d", newBucketNo
);
338 Bucket
*bucket1
= &buckets
[newBucketNo
];
339 bucket1
->mutex_
.getLock(tbl
->db_
->procSlot
);
342 printError(ErrLockTimeOut
,"Unable to acquire bucket Mutex for bucket %d",newBucketNo
);
343 return ErrLockTimeOut
;
346 HashIndexNode
*head1
= (HashIndexNode
*) bucket
->bucketList_
;
349 BucketList
list1(head1
);
350 printDebug(DM_HashIndex
, "Updating hash index node: Removing node from list with head %x", head1
);
351 list1
.remove((Chunk
*)iptr
->hashNodeChunk_
, tbl
->db_
, keyPtr
);
355 printError(ErrSysInternal
,"Update: Bucket list is null");
356 return ErrSysInternal
;
360 rc
= tr
->appendLogicalUndoLog(tbl
->sysDB_
, DeleteHashIndexOperation
,
361 tuple
, sizeof(void*), indexPtr
);
364 //TODO::add it back to the bucket list
365 bucket1
->mutex_
.releaseLock(tbl
->db_
->procSlot
);
366 bucket
->mutex_
.releaseLock(tbl
->db_
->procSlot
);
370 HashIndexNode
*head2
= (HashIndexNode
*) bucket1
->bucketList_
;
371 //Note:: the tuple will be in the same address location
372 //so not changing the keyptr and tuple during append
373 //only bucket where this node resides will only change
374 //if the index key is updated.
377 HashIndexNode
*firstNode
= (HashIndexNode
*)(((Chunk
*)iptr
->hashNodeChunk_
)->allocate(tbl
->db_
));
378 firstNode
->ptrToKey_
= keyPtr
;
379 firstNode
->ptrToTuple_
= tuple
;
380 firstNode
->next_
= NULL
;
381 bucket1
->bucketList_
= (HashIndexNode
*)firstNode
;
382 printDebug(DM_HashIndex
, "Updating hash index node: Adding new node %x:Head is empty", firstNode
);
386 BucketList
list2(head2
);
387 printDebug(DM_HashIndex
, "Updating hash index node: Adding node to list with head %x", head2
);
388 list2
.insert((Chunk
*)iptr
->hashNodeChunk_
, tbl
->db_
, keyPtr
, tuple
);
392 rc
= tr
->appendLogicalUndoLog(tbl
->sysDB_
, InsertHashIndexOperation
,
393 tuple
, sizeof(void*), indexPtr
);
396 //TODO::revert back the changes:delete and add the node + remove the logical undo log
397 //of the DeleteHashIndexOperation
400 bucket1
->mutex_
.releaseLock(tbl
->db_
->procSlot
);
401 bucket
->mutex_
.releaseLock(tbl
->db_
->procSlot
);