001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.fusesource.hawtdb.api; 018 019 import org.fusesource.hawtbuf.codec.Codec; 020 import org.fusesource.hawtbuf.codec.ObjectCodec; 021 import org.fusesource.hawtdb.internal.index.HashIndex; 022 023 /** 024 * <p> 025 * Uses to create Hash based storage of key/values. The hash index 026 * consists of contiguous array of pages allocated on the page file. 027 * Each page is considered a bucket. keys get hashed to a bucket 028 * indexes and the key and value are stored in the bucket. Each 029 * bucket is actually a BTree root and can therefore store multiple 030 * keys and values and overflow to additional pages if needed. 031 * </p> 032 * <p> 033 * Once the percentage of hash buckets used passes the configured 034 * load factor, the hash index will "resize" to use a larger number 035 * of buckets to keep the number items per bucket low which increases 036 * access time of the items as there are fewer page access required. 037 * </p> 038 * <p> 039 * Unlike BTree indexes, Hash indexes are not kept in key sorted order. 040 * </p> 041 * 042 * @author <a href="http://hiramchirino.com">Hiram Chirino</a> 043 */ 044 public class HashIndexFactory<Key, Value> implements IndexFactory<Key, Value> { 045 046 public static final String PROPERTY_PREFIX = HashIndex.class.getName()+"."; 047 public static final int DEFAULT_BUCKET_CAPACITY = Integer.parseInt(System.getProperty(PROPERTY_PREFIX+"DEFAULT_BUCKET_CAPACITY", "1024")); 048 public static final int DEFAULT_MAXIMUM_BUCKET_CAPACITY = Integer.parseInt(System.getProperty(PROPERTY_PREFIX+"DEFAULT_MAXIMUM_BUCKET_CAPACITY", "16384")); 049 public static final int DEFAULT_MINIMUM_BUCKET_CAPACITY = Integer.parseInt(System.getProperty(PROPERTY_PREFIX+"DEFAULT_MINIMUM_BUCKET_CAPACITY", "16")); 050 public static final int DEFAULT_LOAD_FACTOR = Integer.parseInt(System.getProperty(PROPERTY_PREFIX+"DEFAULT_LOAD_FACTOR", "75")); 051 052 private Codec<Key> keyCodec = new ObjectCodec<Key>(); 053 private Codec<Value> valueCodec = new ObjectCodec<Value>(); 054 private int initialBucketCapacity = DEFAULT_BUCKET_CAPACITY; 055 private int maximumBucketCapacity = DEFAULT_MAXIMUM_BUCKET_CAPACITY; 056 private int minimumBucketCapacity = DEFAULT_MINIMUM_BUCKET_CAPACITY; 057 private int loadFactor = DEFAULT_LOAD_FACTOR; 058 private boolean deferredEncoding=true; 059 060 /** 061 * Loads an existing hash index from the paged object. 062 */ 063 public Index<Key, Value> open(Paged paged, int indexNumber) { 064 return createInstance(paged, indexNumber).open(); 065 } 066 067 /** 068 * Loads an existing hash index from the paged object. 069 */ 070 public Index<Key, Value> open(Paged paged) { 071 return createInstance(paged, 0).open(); 072 } 073 074 /** 075 * Creates a new hash index on the Paged object. 076 */ 077 public Index<Key, Value> create(Paged paged) { 078 return createInstance(paged, paged.alloc()).create(); 079 } 080 081 private HashIndex<Key, Value> createInstance(Paged paged, int page) { 082 return new HashIndex<Key, Value>(paged, page, this); 083 } 084 085 /** 086 * Defaults to an {@link org.fusesource.hawtbuf.codec.ObjectCodec} if not explicitly set. 087 * 088 * @return the marshaller used for keys. 089 */ 090 public Codec<Key> getKeyCodec() { 091 return keyCodec; 092 } 093 094 /** 095 * Allows you to configure custom marshalling logic to encode the index keys. 096 * 097 * @param codec the marshaller used for keys. 098 */ 099 public void setKeyCodec(Codec<Key> codec) { 100 this.keyCodec = codec; 101 } 102 103 /** 104 * Defaults to an {@link org.fusesource.hawtbuf.codec.ObjectCodec} if not explicitly set. 105 * 106 * @return the marshaller used for values. 107 */ 108 public Codec<Value> getValueCodec() { 109 return valueCodec; 110 } 111 112 /** 113 * Allows you to configure custom marshalling logic to encode the index values. 114 * 115 * @param codec the marshaller used for values 116 */ 117 public void setValueCodec(Codec<Value> codec) { 118 this.valueCodec = codec; 119 } 120 121 /** 122 * @return the maximum bucket capacity 123 */ 124 public int getMaximumBucketCapacity() { 125 return maximumBucketCapacity; 126 } 127 128 /** 129 * Sets the maximum bucket capacity. 130 * 131 * @param value the new capacity 132 */ 133 public void setMaximumBucketCapacity(int value) { 134 this.maximumBucketCapacity = value; 135 } 136 137 /** 138 * 139 * @return the minimum bucket capacity 140 */ 141 public int getMinimumBucketCapacity() { 142 return minimumBucketCapacity; 143 } 144 145 /** 146 * Sets the minimum bucket capacity. 147 * 148 * @param value the new capacity 149 */ 150 public void setMinimumBucketCapacity(int value) { 151 this.minimumBucketCapacity = value; 152 } 153 154 /** 155 * @return the index load factor 156 */ 157 public int getLoadFactor() { 158 return loadFactor; 159 } 160 161 /** 162 * Sets the index load factor. When this load factor percentage 163 * of used buckets is execeeded, the index will resize to increase the bucket capacity. 164 * @param loadFactor 165 */ 166 public void setLoadFactor(int loadFactor) { 167 this.loadFactor = loadFactor; 168 } 169 170 /** 171 * @return the initial bucket capacity 172 */ 173 public int getBucketCapacity() { 174 return initialBucketCapacity; 175 } 176 177 /** 178 * sets the initial bucket capacity. 179 * @param binCapacity 180 */ 181 public void setBucketCapacity(int binCapacity) { 182 this.initialBucketCapacity = binCapacity; 183 } 184 185 /** 186 * Convenience method which sets the maximum, minimum and initial bucket capacity to be the specified value. 187 * @param value 188 */ 189 public void setFixedCapacity(int value) { 190 this.minimumBucketCapacity = this.maximumBucketCapacity = this.initialBucketCapacity = value; 191 } 192 193 /** 194 * 195 * @return true if deferred encoding enabled 196 */ 197 public boolean isDeferredEncoding() { 198 return deferredEncoding; 199 } 200 201 /** 202 * <p> 203 * When deferred encoding is enabled, the index avoids encoding keys and values 204 * for as long as possible so take advantage of collapsing multiple updates of the 205 * same key/value into a single update operation and single encoding operation. 206 * </p><p> 207 * Using this feature requires the keys and values to be immutable objects since 208 * unexpected errors would occur if they are changed after they have been handed 209 * to to the index for storage. 210 * </p> 211 * @param enable should deferred encoding be enabled. 212 */ 213 public void setDeferredEncoding(boolean enable) { 214 this.deferredEncoding = enable; 215 } 216 217 }