2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * $XConsortium: disk_hash.cc /main/5 1996/07/18 14:28:19 drk $
26 * Copyright (c) 1993 HAL Computer Systems International, Ltd.
27 * All rights reserved. Unpublished -- rights reserved under
28 * the Copyright Laws of the United States. USE OF A COPYRIGHT
29 * NOTICE IS PRECAUTIONARY ONLY AND DOES NOT IMPLY PUBLICATION
32 * THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION AND TRADE
33 * SECRETS OF HAL COMPUTER SYSTEMS INTERNATIONAL, LTD. USE,
34 * DISCLOSURE, OR REPRODUCTION IS PROHIBITED WITHOUT THE
35 * PRIOR EXPRESS WRITTEN PERMISSION OF HAL COMPUTER SYSTEMS
38 * RESTRICTED RIGHTS LEGEND
39 * Use, duplication, or disclosure by the Government is subject
40 * to the restrictions as set forth in subparagraph (c)(l)(ii)
41 * of the Rights in Technical Data and Computer Software clause
42 * at DFARS 252.227-7013.
44 * HAL COMPUTER SYSTEMS INTERNATIONAL, LTD.
51 #include "diskhash/disk_hash.h"
52 #include "api/transaction.h"
54 extern transaction* g_transac;
56 int dsteps[] = { 2, 3, 5, 7, 11, 13, 17, 21, 23, 29, 31 };
59 #define KPB 20 // keys per bucket
60 #define REHASHS 5 // number of rehashs in a row with
62 #define TOP_LEVEL_PARAMS (sizeof(k) + sizeof(p) + sizeof(M) + \
63 sizeof(n) + sizeof(v))
65 //static buffer buf(LBUFSIZ);
67 disk_hash::disk_hash(page_storage* store, int prime, int expected_n) :
68 index_agent(), key_store(store), buf(store -> aux_buf())
71 g_transac -> book(store);
74 buf.set_swap_order(store -> swap_order());
76 rand_generator.seed();
77 no_dsteps = sizeof(dsteps) / sizeof(int);
79 init_params(prime, expected_n);
81 bucket_vector = new bucket_array(M+v, store);
82 hash_vector = new void_ptr_array(2*MAX(expected_n, (int) n));
84 k_vector = new void_ptr_array(M+v);
85 r_vector = new void_ptr_array(M+v);
87 k_vector -> reset_vptr(voidPtr(1));
91 disk_hash::~disk_hash()
100 void disk_hash::init_params(int prime, int expected_n)
102 int pgs = key_store -> pages();
105 if ( (*key_store)(1, page_storage::READ) -> count() != 2 ) {
106 throw(stringException("corruptted primary bucket"));
109 /////////////////////////////////
110 // read in params from the store
111 /////////////////////////////////
114 (*key_store)(1, page_storage::READ) -> get(1, buf);
116 buf.get(k).get(p).get(M).get(n).get(v);
119 ///////////////////////////////////////
120 // init the store. bucket 1 is reserved
121 // for top level function params
122 ///////////////////////////////////////
124 set_k(rand_generator.rand());
125 set_M(MAX(1, expected_n/KPB));
129 key_store -> add_page_frames(1);
131 int slot_num; char* z;
132 (*key_store)(1, page_storage::WRITE) ->
133 alloc_slot(slot_num, TOP_LEVEL_PARAMS, z);
135 if ( slot_num != 1 ) {
136 throw(stringException("corruptted primary bucket"));
143 void disk_hash::sync_params()
146 buf.put(k).put(p).put(M).put(n).put(v);
147 (*key_store)(1, page_storage::WRITE) -> update_slot(1, buf);
150 void disk_hash::clean()
152 throw(stringException("void disk_hash::clean(): not implemented yet"));
155 ///////////////////////////////////////////////////////////////
157 ///////////////////////////////////////////////////////////////
158 Boolean disk_hash::rehash(data_t& w)
160 //MESSAGE(cerr, "REHASH:");
161 char tmp_name[PATHSIZ];
162 snprintf(tmp_name, sizeof(tmp_name), "%s.tmp", key_store -> my_name());
164 fstream pool(form("%s/%s", key_store -> my_path(), tmp_name),
168 for ( int i=0; i<bucket_vector -> count(); i++ ) {
169 pool << bucket_vector -> get_bucket(i);
176 for ( int rehashs=0; rehashs<REHASHS; rehashs++ ) {
178 /////////////////////
180 /////////////////////
184 set_M(MAX(n/KPB, 2*M));
187 int delta = M + v - old_M - old_v;
189 k_vector -> expandWith(delta);
190 r_vector -> expandWith(delta);
192 //////////////////////////////////////////
193 // expand the buckets and the hash table
194 //////////////////////////////////////////
195 bucket_vector -> expandWith(MAX(0, M+v - bucket_vector -> count()));
196 hash_vector -> expandWith(MAX(0, 2*n - hash_vector -> count()));
198 /////////////////////
200 /////////////////////
201 for ( int i=0; i<bucket_vector -> count(); i++ ) {
202 bucket_vector -> get_bucket(i).remove_all();
205 if ( _rehash(pool) == true ) {
212 throw(stringException("rehash() failed"));
214 del_file(tmp_name, key_store -> my_path());
219 Boolean disk_hash::_rehash(fstream& pool)
221 pool.clear(); pool.seekg(0, ios::beg);
223 hash_vector -> reset_vptr(voidPtr(0));
224 k_vector -> reset_vptr(voidPtr(1));
225 r_vector -> reset_vptr(voidPtr(0));
227 set_k(rand_generator.rand());
229 data_t x((char*)0, 0, 0);
231 while ( pool >> x ) {
232 if ( _insert(x, false) == false )
239 /************************************/
241 /************************************/
242 Boolean disk_hash::insert(data_t& w)
244 if ( _insert(w, true) == false )
245 throw(stringException("disk_hash::insert() failed"));
253 Boolean disk_hash::_insert(data_t& w, Boolean rehash_if_fail)
255 int hash = w.bucket_num(k, p, M);
257 //int hash = w.key.int_key;
260 disk_bucket& b = bucket_vector -> get_bucket(hash);
262 int slot_num = b.insert(&w);
264 if ( slot_num != 0 ) {
265 caching(b, w, slot_num);
267 ///////////////////////////////////
268 // insert into the overflow bucket
269 ///////////////////////////////////
271 //MESSAGE(cerr, "INSERT to overflow buckets");
274 for ( hash %= v; hash < (int) v; hash++ ) {
276 disk_bucket& overflowb = bucket_vector -> get_bucket(hash+M);
278 slot_num = overflowb.insert(&w);
280 if ( slot_num != 0 ) {
281 caching(overflowb, w, slot_num);
286 if ( slot_num == 0 && rehash_if_fail == true )
296 void disk_hash::caching(disk_bucket& b, data_t& w, int slot_num)
298 //debug(cerr, b.bnum());
299 //debug(cerr, k_vector -> count());
301 int kv = int((long)(*k_vector)[b.bnum()]);
302 int rv = int((long)(*r_vector)[b.bnum()]);
304 ///////////////////////////////////////////
305 // cache all keys in the bycket except w.
306 // In fact, only need to cache keys whose
307 // hash vector slots have been updated.
308 // It is to be enhanced.
309 ///////////////////////////////////////////
312 while ( ind != 0 && ind != slot_num ) {
317 hash_vector -> insert(
318 (voidPtr)(size_t)ind,
319 x -> slot_num(kv, rv, p, hash_vector -> count())
328 ////////////////////////////////////////
329 // cache w. it is always in the cache.
330 // others may be overwritten.
331 ////////////////////////////////////////
332 hash_vector -> insert(
333 (voidPtr)(size_t)slot_num,
334 w.slot_num(kv, rv, p, hash_vector -> count())
338 /******************************************/
340 /******************************************/
341 Boolean disk_hash::remove(data_t& w)
345 if ( member(w, b, slot_num) == true ) {
347 b -> remove(slot_num);
357 Boolean disk_hash::member(data_t& w)
359 //MESSAGE(cerr, "disk_hash::member():");
361 //MESSAGE(cerr, "+++++++++++++");
364 return member(w, b, slot_num);
367 Boolean disk_hash::member(data_t& w, disk_bucket*& b, int& slot_num) const
369 int hash = w.bucket_num(k, p, M);
371 //int hash = w.key.int_key;
374 b = &bucket_vector -> get_bucket(hash);
376 int kv = int((long)(*k_vector)[b -> bnum()]);
377 int rv = int((long)(*r_vector)[b -> bnum()]);
380 int((long)(*hash_vector)[w.slot_num(kv, rv, p, hash_vector -> count())]);
382 //debug(cerr, slot_num);
384 if ( b -> member(w, slot_num) == true )
387 if ( b -> overflow() == true ) {
389 for ( hash %= v; hash < (int) v; hash++ ) {
391 b = &bucket_vector -> get_bucket(hash+M);
393 if ( b -> member(w, slot_num) == true ) {
402 int disk_hash::first_bucket()
404 return ( M > 0 ) ? 0 : -1;
407 disk_bucket* disk_hash::get_bucket(int& ind)
409 return &bucket_vector -> get_bucket(ind);
412 void disk_hash::next_bucket(int& ind)
414 ind = ( ind >= (int)(M+v-1) ) ? -1 : (ind+1);
418 /*******************************************************/
420 /*******************************************************/
421 ostream& disk_hash::asciiOut(ostream& out)
423 int ind = first_bucket();
425 while ( ind != -1 ) {
427 //MESSAGE(cerr, "New Bucket:");
429 disk_bucket* bucket = get_bucket(ind);
441 istream& disk_hash::asciiIn(istream& in)
445 while ( in >> actor ) {
446 _insert(actor, true);
455 ostream& disk_hash::asciiOut(ostream& out, print_func_ptr_t print_f)
458 int ind = first_bucket();
460 while ( ind != -1 ) {
462 disk_bucket* bucket = get_bucket(ind);
465 bucket -> asciiOut(out, print_f);
474 void disk_hash::out_params()