4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
25 * Copyright (c) 1988-2000 by Sun Microsystems, Inc.
26 * All Rights Reserved.
29 #pragma ident "%Z%%M% %I% %E% SMI"
33 #include "db_headers.h"
34 #include "db_index_entry.h"
37 /* Constructor: create an entry using given string and location info. */
38 db_index_entry::db_index_entry(char* name
, int nlen
, entryp ep
)
40 if ((key
= new item(name
, nlen
)) == NULL
)
41 FATAL("db_index_entry::db_index_entry: cannot allocate space",
44 next_result
= next
= NULL
;
45 /* what about hashval ? */
49 * Constructor: create an entry using the given info.
50 * A copy of the item is made. New entry is added to head of list of 'n'.
52 db_index_entry::db_index_entry(unsigned long hval
, item
* k
,
53 entryp ep
, db_index_entry_p rest
)
55 if ((key
= new item(k
)) == NULL
)
57 "db_index_entry::db_index_entry: cannot allocate space (2)",
66 * Join two lists (entry as identified by its 'location' occurs on both list,
67 * then it is included in the list returned).
68 * Returns pointer to resulting list; size of list
69 * returned in 'newsize'. List is chained using the 'nextresult' pointer.
72 db_index_entry::join(long /* size1 */, long /* size2 */,
73 db_index_entry_p list2
, long * newsize
)
75 db_index_entry_p mergedlist
= NULL
, // records that occur on both lists
76 mergedtail
= NULL
, // tail pointer of mergedlist
77 current
, // current pointer of this list
78 other
, // current pointer of updated list2
79 otherprev
, // previous pointer of updated list2
80 otherstart
= list2
; // head of updated list2
84 * algorithm is straightforward:
86 * for each item, traverse list2,
87 * if item on list1 matches item on list2,
88 * add to merged list and delete it from list2.
91 for (current
= this; (current
!= NULL
) && (otherstart
!= NULL
);
92 current
= current
->next_result
) {
93 /* find 'current' in 'other' list */
95 for (other
= otherstart
;
97 other
= other
->next_result
) {
98 if (current
->location
== other
->location
)
103 if (other
!= NULL
) { /* found */
104 /* delete 'other' from future consideration */
105 if (otherprev
== NULL
) {
107 otherstart
= otherstart
->next_result
;
110 otherprev
->next_result
= other
->next_result
;
112 /* add 'current' to list of items found so far */
113 if (mergedlist
== NULL
)
114 mergedlist
= current
; /* first one found */
116 mergedtail
->next_result
= current
; /* append */
117 mergedtail
= current
; /* point to last entry found */
121 if (mergedtail
) mergedtail
->next_result
= NULL
; /* set end to null */
126 /* Relocate bucket starting with this entry to new hashtable 'new_tab'. */
128 db_index_entry::relocate(db_index_entry_p
*new_tab
, unsigned long hashsize
)
130 db_index_entry_p np
, next_np
, *hp
;
132 for (np
= this; np
!= NULL
; np
= next_np
) {
134 hp
= &new_tab
[np
->hashval
% hashsize
];
140 /* Return the next entry in the bucket starting with this entry
141 with the same hashvalue, key and location as this entry. */
143 db_index_entry::getnext(bool_t casein
, unsigned long hval
, item
*i
, entryp l
)
147 for (np
= this; np
!= NULL
; np
= np
->next
) {
148 if ((np
->hashval
== hval
) &&
149 (np
->key
->equal(i
, casein
)) && l
== location
) {
161 * Return pointer to index entry with same hash value, same key,
162 * and same record number as those supplied. Returns NULL if not found.
165 db_index_entry::lookup(bool_t casein
, unsigned long hval
,
166 item
*i
, entryp recnum
)
170 for (np
= this; np
!= NULL
; np
= np
->next
) {
171 if (np
->hashval
== hval
&& np
->key
->equal(i
, casein
) &&
172 np
->location
== recnum
) {
176 if (np
) np
->next_result
= NULL
; /* should only be 1 */
181 * Returns pointer to a list of index entries with the same hash value and
182 * key as those given. Returns in 'how_many' the number of entries in the
183 * list returned. The list is linked by the 'next_result' field of the
184 * index entries. These may be changed after the next call to 'lookup'
188 db_index_entry::lookup(bool_t casein
, unsigned long hval
,
189 item
*i
, long * how_many
)
191 db_index_entry_p fst
, prev
, curr
;
194 for (fst
= this; fst
!= NULL
; fst
= fst
->next
) {
195 if ((fst
->hashval
== hval
) && (fst
->key
->equal(i
, casein
))) {
201 * gather all the ones with the same key; assume that all entries
202 * with same key are located contiguously.
206 for (curr
= fst
->next
; curr
!= NULL
; curr
= curr
->next
) {
207 if ((curr
->hashval
== hval
) &&
208 (curr
->key
->equal(i
, casein
))) {
209 prev
->addresult(curr
);
216 prev
->addresult(NULL
); /* terminate the list -CM */
223 * Remove entry with the specified hashvalue, key, and record number.
224 * Returns 'TRUE' if successful, FALSE otherwise.
225 * If the entry being removed is at the head of the list, then
226 * the head is updated to reflect the removal. The storage for the index
227 * entry is freed. The record pointed to by 'recnum' must be removed
228 * through another means. All that is updated in this operation is the
232 db_index_entry::remove(db_index_entry_p
*head
, bool_t casein
,
233 unsigned long hval
, item
*i
, entryp recnum
)
235 db_index_entry_p np
, dp
;
237 /* Search for it in the bucket */
238 for (dp
= np
= this; np
!= NULL
; np
= np
->next
) {
239 if (np
->hashval
== hval
&& np
->key
->equal(i
, casein
) &&
240 np
->location
== recnum
) {
247 if (np
== NULL
) return FALSE
; // cannot delete if it is not there
250 *head
= np
->next
; // deleting head of bucket
252 dp
->next
= np
->next
; // deleting interior link
259 /* Replace the 'location' field of the index entry with the given one. */
262 db_index_entry::replace(entryp ep)
269 * Create and add an entry with the given hashvalue, key value, and record
270 * location, to the bucket pointed to by 'hashvalue'.
271 * If an entry with the same hashvalue and key value is found,
272 * the entry is added after the first entry with this property. Otherwise,
273 * the entry is added to the head of the bucket. This way, entries
274 * with the same hashvalue and key are not scattered throughout the bucket
275 * but they occur together. Copy is made of given key.
278 db_index_entry::add(db_index_entry
**head
, bool_t casein
,
279 unsigned long hval
, item
*i
, entryp recnum
)
282 db_index_entry_p curr
, prev
, rp
, save
;
284 /* Search for it in the bucket */
285 for (prev
= curr
= this; curr
!= NULL
; curr
= curr
->next
) {
286 if (curr
->hashval
== hval
&& curr
->key
->equal(i
, casein
)) {
296 /* none with same hashvalue/key found. Add to head of list. */
298 *head
= new db_index_entry(hval
, i
, recnum
, * head
);
300 *head
= save
; // restore previous state
302 "db_index_entry::add: cannot allocate space for head",
303 DB_MEMORY_LIMIT
, FALSE
);
306 /* Found same hashvalue/key. Add entry after that one. */
308 prev
->next
= new db_index_entry(hval
, i
, recnum
, prev
->next
);
309 if (prev
->next
== NULL
) {
310 prev
->next
= save
; // restore previous state
312 "db_index_entry::add: cannot allocate space for entry",
313 DB_MEMORY_LIMIT
, FALSE
);
320 /* Print this entry to stdout. */
322 db_index_entry::print()
328 printf(": %d\n", location
);
331 /* Print bucket starting with this entry. */
333 db_index_entry::print_all()
336 for (np
= this; np
!= NULL
; np
= np
->next
) {
341 /* Print result list starting with this entry. */
343 db_index_entry::print_results()
346 for (np
= this; np
!= NULL
; np
= np
->next_result
) {