1 /* 2 * Copyright (C) 2011, Google Inc. 3 * and other copyright owners as documented in the project's IP log. 4 * 5 * This program and the accompanying materials are made available 6 * under the terms of the Eclipse Distribution License v1.0 which 7 * accompanies this distribution, is reproduced below, and is 8 * available at http://www.eclipse.org/org/documents/edl-v10.php 9 * 10 * All rights reserved. 11 * 12 * Redistribution and use in source and binary forms, with or 13 * without modification, are permitted provided that the following 14 * conditions are met: 15 * 16 * - Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 19 * - Redistributions in binary form must reproduce the above 20 * copyright notice, this list of conditions and the following 21 * disclaimer in the documentation and/or other materials provided 22 * with the distribution. 23 * 24 * - Neither the name of the Eclipse Foundation, Inc. nor the 25 * names of its contributors may be used to endorse or promote 26 * products derived from this software without specific prior 27 * written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 30 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 31 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 32 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 34 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 35 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 36 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 37 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 38 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 40 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 41 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 package org.eclipse.jgit.internal.storage.dfs; 45 46 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION; 47 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_SECTION; 48 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_LIMIT; 49 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_SIZE; 50 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONCURRENCY_LEVEL; 51 import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_RATIO; 52 53 import java.text.MessageFormat; 54 import java.util.function.Consumer; 55 56 import org.eclipse.jgit.internal.JGitText; 57 import org.eclipse.jgit.lib.Config; 58 59 /** 60 * Configuration parameters for 61 * {@link org.eclipse.jgit.internal.storage.dfs.DfsBlockCache}. 62 */ 63 public class DfsBlockCacheConfig { 64 /** 1024 (number of bytes in one kibibyte/kilobyte) */ 65 public static final int KB = 1024; 66 67 /** 1024 {@link #KB} (number of bytes in one mebibyte/megabyte) */ 68 public static final int MB = 1024 * KB; 69 70 private long blockLimit; 71 private int blockSize; 72 private double streamRatio; 73 private int concurrencyLevel; 74 75 private Consumer<Long> refLock; 76 77 /** 78 * Create a default configuration. 79 */ 80 public DfsBlockCacheConfig() { 81 setBlockLimit(32 * MB); 82 setBlockSize(64 * KB); 83 setStreamRatio(0.30); 84 setConcurrencyLevel(32); 85 } 86 87 /** 88 * Get maximum number bytes of heap memory to dedicate to caching pack file 89 * data. 90 * 91 * @return maximum number bytes of heap memory to dedicate to caching pack 92 * file data. <b>Default is 32 MB.</b> 93 */ 94 public long getBlockLimit() { 95 return blockLimit; 96 } 97 98 /** 99 * Set maximum number bytes of heap memory to dedicate to caching pack file 100 * data. 101 * <p> 102 * It is strongly recommended to set the block limit to be an integer multiple 103 * of the block size. This constraint is not enforced by this method (since 104 * it may be called before {@link #setBlockSize(int)}), but it is enforced by 105 * {@link #fromConfig(Config)}. 106 * 107 * @param newLimit 108 * maximum number bytes of heap memory to dedicate to caching 109 * pack file data; must be positive. 110 * @return {@code this} 111 */ 112 public DfsBlockCacheConfig setBlockLimit(long newLimit) { 113 if (newLimit <= 0) { 114 throw new IllegalArgumentException(MessageFormat.format( 115 JGitText.get().blockLimitNotPositive, 116 Long.valueOf(newLimit))); 117 } 118 blockLimit = newLimit; 119 return this; 120 } 121 122 /** 123 * Get size in bytes of a single window mapped or read in from the pack 124 * file. 125 * 126 * @return size in bytes of a single window mapped or read in from the pack 127 * file. <b>Default is 64 KB.</b> 128 */ 129 public int getBlockSize() { 130 return blockSize; 131 } 132 133 /** 134 * Set size in bytes of a single window read in from the pack file. 135 * 136 * @param newSize 137 * size in bytes of a single window read in from the pack file. 138 * The value must be a power of 2. 139 * @return {@code this} 140 */ 141 public DfsBlockCacheConfig setBlockSize(int newSize) { 142 int size = Math.max(512, newSize); 143 if ((size & (size - 1)) != 0) { 144 throw new IllegalArgumentException( 145 JGitText.get().blockSizeNotPowerOf2); 146 } 147 blockSize = size; 148 return this; 149 } 150 151 /** 152 * Get the estimated number of threads concurrently accessing the cache. 153 * 154 * @return the estimated number of threads concurrently accessing the cache. 155 * <b>Default is 32.</b> 156 */ 157 public int getConcurrencyLevel() { 158 return concurrencyLevel; 159 } 160 161 /** 162 * Set the estimated number of threads concurrently accessing the cache. 163 * 164 * @param newConcurrencyLevel 165 * the estimated number of threads concurrently accessing the 166 * cache. 167 * @return {@code this} 168 */ 169 public DfsBlockCacheConfig setConcurrencyLevel( 170 final int newConcurrencyLevel) { 171 concurrencyLevel = newConcurrencyLevel; 172 return this; 173 } 174 175 /** 176 * Get highest percentage of {@link #getBlockLimit()} a single pack can 177 * occupy while being copied by the pack reuse strategy. 178 * 179 * @return highest percentage of {@link #getBlockLimit()} a single pack can 180 * occupy while being copied by the pack reuse strategy. <b>Default 181 * is 0.30, or 30%</b>. 182 */ 183 public double getStreamRatio() { 184 return streamRatio; 185 } 186 187 /** 188 * Set percentage of cache to occupy with a copied pack. 189 * 190 * @param ratio 191 * percentage of cache to occupy with a copied pack. 192 * @return {@code this} 193 */ 194 public DfsBlockCacheConfig setStreamRatio(double ratio) { 195 streamRatio = Math.max(0, Math.min(ratio, 1.0)); 196 return this; 197 } 198 199 /** 200 * Get the consumer of the object reference lock wait time in milliseconds. 201 * 202 * @return consumer of wait time in milliseconds. 203 */ 204 public Consumer<Long> getRefLockWaitTimeConsumer() { 205 return refLock; 206 } 207 208 /** 209 * Set the consumer for lock wait time. 210 * 211 * @param c 212 * consumer of wait time in milliseconds. 213 * @return {@code this} 214 */ 215 public DfsBlockCacheConfig setRefLockWaitTimeConsumer(Consumer<Long> c) { 216 refLock = c; 217 return this; 218 } 219 220 /** 221 * Update properties by setting fields from the configuration. 222 * <p> 223 * If a property is not defined in the configuration, then it is left 224 * unmodified. 225 * <p> 226 * Enforces certain constraints on the combination of settings in the config, 227 * for example that the block limit is a multiple of the block size. 228 * 229 * @param rc 230 * configuration to read properties from. 231 * @return {@code this} 232 */ 233 public DfsBlockCacheConfig fromConfig(Config rc) { 234 long cfgBlockLimit = rc.getLong( 235 CONFIG_CORE_SECTION, 236 CONFIG_DFS_SECTION, 237 CONFIG_KEY_BLOCK_LIMIT, 238 getBlockLimit()); 239 int cfgBlockSize = rc.getInt( 240 CONFIG_CORE_SECTION, 241 CONFIG_DFS_SECTION, 242 CONFIG_KEY_BLOCK_SIZE, 243 getBlockSize()); 244 if (cfgBlockLimit % cfgBlockSize != 0) { 245 throw new IllegalArgumentException(MessageFormat.format( 246 JGitText.get().blockLimitNotMultipleOfBlockSize, 247 Long.valueOf(cfgBlockLimit), 248 Long.valueOf(cfgBlockSize))); 249 } 250 251 setBlockLimit(cfgBlockLimit); 252 setBlockSize(cfgBlockSize); 253 254 setConcurrencyLevel(rc.getInt( 255 CONFIG_CORE_SECTION, 256 CONFIG_DFS_SECTION, 257 CONFIG_KEY_CONCURRENCY_LEVEL, 258 getConcurrencyLevel())); 259 260 String v = rc.getString( 261 CONFIG_CORE_SECTION, 262 CONFIG_DFS_SECTION, 263 CONFIG_KEY_STREAM_RATIO); 264 if (v != null) { 265 try { 266 setStreamRatio(Double.parseDouble(v)); 267 } catch (NumberFormatException e) { 268 throw new IllegalArgumentException(MessageFormat.format( 269 JGitText.get().enumValueNotSupported3, 270 CONFIG_CORE_SECTION, 271 CONFIG_DFS_SECTION, 272 CONFIG_KEY_STREAM_RATIO, v)); 273 } 274 } 275 return this; 276 } 277 }