View Javadoc
1   /*
2    * Copyright (C) 2011, Google Inc. and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
9    */
10  
11  package org.eclipse.jgit.internal.storage.dfs;
12  
13  import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_CORE_SECTION;
14  import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DFS_SECTION;
15  import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_LIMIT;
16  import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_BLOCK_SIZE;
17  import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_CONCURRENCY_LEVEL;
18  import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_STREAM_RATIO;
19  
20  import java.text.MessageFormat;
21  import java.util.function.Consumer;
22  
23  import org.eclipse.jgit.internal.JGitText;
24  import org.eclipse.jgit.lib.Config;
25  
26  /**
27   * Configuration parameters for
28   * {@link org.eclipse.jgit.internal.storage.dfs.DfsBlockCache}.
29   */
30  public class DfsBlockCacheConfig {
31  	/** 1024 (number of bytes in one kibibyte/kilobyte) */
32  	public static final int KB = 1024;
33  
34  	/** 1024 {@link #KB} (number of bytes in one mebibyte/megabyte) */
35  	public static final int MB = 1024 * KB;
36  
37  	private long blockLimit;
38  	private int blockSize;
39  	private double streamRatio;
40  	private int concurrencyLevel;
41  
42  	private Consumer<Long> refLock;
43  
44  	/**
45  	 * Create a default configuration.
46  	 */
47  	public DfsBlockCacheConfig() {
48  		setBlockLimit(32 * MB);
49  		setBlockSize(64 * KB);
50  		setStreamRatio(0.30);
51  		setConcurrencyLevel(32);
52  	}
53  
54  	/**
55  	 * Get maximum number bytes of heap memory to dedicate to caching pack file
56  	 * data.
57  	 *
58  	 * @return maximum number bytes of heap memory to dedicate to caching pack
59  	 *         file data. <b>Default is 32 MB.</b>
60  	 */
61  	public long getBlockLimit() {
62  		return blockLimit;
63  	}
64  
65  	/**
66  	 * Set maximum number bytes of heap memory to dedicate to caching pack file
67  	 * data.
68  	 * <p>
69  	 * It is strongly recommended to set the block limit to be an integer multiple
70  	 * of the block size. This constraint is not enforced by this method (since
71  	 * it may be called before {@link #setBlockSize(int)}), but it is enforced by
72  	 * {@link #fromConfig(Config)}.
73  	 *
74  	 * @param newLimit
75  	 *            maximum number bytes of heap memory to dedicate to caching
76  	 *            pack file data; must be positive.
77  	 * @return {@code this}
78  	 */
79  	public DfsBlockCacheConfig setBlockLimit(long newLimit) {
80  		if (newLimit <= 0) {
81  			throw new IllegalArgumentException(MessageFormat.format(
82  					JGitText.get().blockLimitNotPositive,
83  					Long.valueOf(newLimit)));
84  		}
85  		blockLimit = newLimit;
86  		return this;
87  	}
88  
89  	/**
90  	 * Get size in bytes of a single window mapped or read in from the pack
91  	 * file.
92  	 *
93  	 * @return size in bytes of a single window mapped or read in from the pack
94  	 *         file. <b>Default is 64 KB.</b>
95  	 */
96  	public int getBlockSize() {
97  		return blockSize;
98  	}
99  
100 	/**
101 	 * Set size in bytes of a single window read in from the pack file.
102 	 *
103 	 * @param newSize
104 	 *            size in bytes of a single window read in from the pack file.
105 	 *            The value must be a power of 2.
106 	 * @return {@code this}
107 	 */
108 	public DfsBlockCacheConfig setBlockSize(int newSize) {
109 		int size = Math.max(512, newSize);
110 		if ((size & (size - 1)) != 0) {
111 			throw new IllegalArgumentException(
112 					JGitText.get().blockSizeNotPowerOf2);
113 		}
114 		blockSize = size;
115 		return this;
116 	}
117 
118 	/**
119 	 * Get the estimated number of threads concurrently accessing the cache.
120 	 *
121 	 * @return the estimated number of threads concurrently accessing the cache.
122 	 *         <b>Default is 32.</b>
123 	 */
124 	public int getConcurrencyLevel() {
125 		return concurrencyLevel;
126 	}
127 
128 	/**
129 	 * Set the estimated number of threads concurrently accessing the cache.
130 	 *
131 	 * @param newConcurrencyLevel
132 	 *            the estimated number of threads concurrently accessing the
133 	 *            cache.
134 	 * @return {@code this}
135 	 */
136 	public DfsBlockCacheConfig setConcurrencyLevel(
137 			final int newConcurrencyLevel) {
138 		concurrencyLevel = newConcurrencyLevel;
139 		return this;
140 	}
141 
142 	/**
143 	 * Get highest percentage of {@link #getBlockLimit()} a single pack can
144 	 * occupy while being copied by the pack reuse strategy.
145 	 *
146 	 * @return highest percentage of {@link #getBlockLimit()} a single pack can
147 	 *         occupy while being copied by the pack reuse strategy. <b>Default
148 	 *         is 0.30, or 30%</b>.
149 	 */
150 	public double getStreamRatio() {
151 		return streamRatio;
152 	}
153 
154 	/**
155 	 * Set percentage of cache to occupy with a copied pack.
156 	 *
157 	 * @param ratio
158 	 *            percentage of cache to occupy with a copied pack.
159 	 * @return {@code this}
160 	 */
161 	public DfsBlockCacheConfig setStreamRatio(double ratio) {
162 		streamRatio = Math.max(0, Math.min(ratio, 1.0));
163 		return this;
164 	}
165 
166 	/**
167 	 * Get the consumer of the object reference lock wait time in milliseconds.
168 	 *
169 	 * @return consumer of wait time in milliseconds.
170 	 */
171 	public Consumer<Long> getRefLockWaitTimeConsumer() {
172 		return refLock;
173 	}
174 
175 	/**
176 	 * Set the consumer for lock wait time.
177 	 *
178 	 * @param c
179 	 *            consumer of wait time in milliseconds.
180 	 * @return {@code this}
181 	 */
182 	public DfsBlockCacheConfig setRefLockWaitTimeConsumer(Consumer<Long> c) {
183 		refLock = c;
184 		return this;
185 	}
186 
187 	/**
188 	 * Update properties by setting fields from the configuration.
189 	 * <p>
190 	 * If a property is not defined in the configuration, then it is left
191 	 * unmodified.
192 	 * <p>
193 	 * Enforces certain constraints on the combination of settings in the config,
194 	 * for example that the block limit is a multiple of the block size.
195 	 *
196 	 * @param rc
197 	 *            configuration to read properties from.
198 	 * @return {@code this}
199 	 */
200 	public DfsBlockCacheConfig fromConfig(Config rc) {
201 		long cfgBlockLimit = rc.getLong(
202 				CONFIG_CORE_SECTION,
203 				CONFIG_DFS_SECTION,
204 				CONFIG_KEY_BLOCK_LIMIT,
205 				getBlockLimit());
206 		int cfgBlockSize = rc.getInt(
207 				CONFIG_CORE_SECTION,
208 				CONFIG_DFS_SECTION,
209 				CONFIG_KEY_BLOCK_SIZE,
210 				getBlockSize());
211 		if (cfgBlockLimit % cfgBlockSize != 0) {
212 			throw new IllegalArgumentException(MessageFormat.format(
213 					JGitText.get().blockLimitNotMultipleOfBlockSize,
214 					Long.valueOf(cfgBlockLimit),
215 					Long.valueOf(cfgBlockSize)));
216 		}
217 
218 		setBlockLimit(cfgBlockLimit);
219 		setBlockSize(cfgBlockSize);
220 
221 		setConcurrencyLevel(rc.getInt(
222 				CONFIG_CORE_SECTION,
223 				CONFIG_DFS_SECTION,
224 				CONFIG_KEY_CONCURRENCY_LEVEL,
225 				getConcurrencyLevel()));
226 
227 		String v = rc.getString(
228 				CONFIG_CORE_SECTION,
229 				CONFIG_DFS_SECTION,
230 				CONFIG_KEY_STREAM_RATIO);
231 		if (v != null) {
232 			try {
233 				setStreamRatio(Double.parseDouble(v));
234 			} catch (NumberFormatException e) {
235 				throw new IllegalArgumentException(MessageFormat.format(
236 						JGitText.get().enumValueNotSupported3,
237 						CONFIG_CORE_SECTION,
238 						CONFIG_DFS_SECTION,
239 						CONFIG_KEY_STREAM_RATIO, v), e);
240 			}
241 		}
242 		return this;
243 	}
244 }