View Javadoc
1   /*
2    * Copyright (C) 2017, 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.io;
12  
13  import java.io.FileInputStream;
14  import java.io.IOException;
15  import java.nio.ByteBuffer;
16  import java.nio.channels.FileChannel;
17  
18  /**
19   * Provides content blocks of file.
20   * <p>
21   * {@code BlockSource} implementations must decide if they will be thread-safe,
22   * or not.
23   */
24  public abstract class BlockSource implements AutoCloseable {
25  	/**
26  	 * Wrap a byte array as a {@code BlockSource}.
27  	 *
28  	 * @param content
29  	 *            input file.
30  	 * @return block source to read from {@code content}.
31  	 */
32  	public static BlockSource from(byte[] content) {
33  		return new BlockSource() {
34  			@Override
35  			public ByteBuffer read(long pos, int cnt) {
36  				ByteBuffer buf = ByteBuffer.allocate(cnt);
37  				if (pos < content.length) {
38  					int p = (int) pos;
39  					int n = Math.min(cnt, content.length - p);
40  					buf.put(content, p, n);
41  				}
42  				return buf;
43  			}
44  
45  			@Override
46  			public long size() {
47  				return content.length;
48  			}
49  
50  			@Override
51  			public void close() {
52  				// Do nothing.
53  			}
54  		};
55  	}
56  
57  	/**
58  	 * Read from a {@code FileInputStream}.
59  	 * <p>
60  	 * The returned {@code BlockSource} is not thread-safe, as it must seek the
61  	 * file channel to read a block.
62  	 *
63  	 * @param in
64  	 *            the file. The {@code BlockSource} will close {@code in}.
65  	 * @return wrapper for {@code in}.
66  	 */
67  	public static BlockSource from(FileInputStream in) {
68  		return from(in.getChannel());
69  	}
70  
71  	/**
72  	 * Read from a {@code FileChannel}.
73  	 * <p>
74  	 * The returned {@code BlockSource} is not thread-safe, as it must seek the
75  	 * file channel to read a block.
76  	 *
77  	 * @param ch
78  	 *            the file. The {@code BlockSource} will close {@code ch}.
79  	 * @return wrapper for {@code ch}.
80  	 */
81  	public static BlockSource from(FileChannel ch) {
82  		return new BlockSource() {
83  			@Override
84  			public ByteBuffer read(long pos, int blockSize) throws IOException {
85  				ByteBuffer b = ByteBuffer.allocate(blockSize);
86  				ch.position(pos);
87  				int n;
88  				do {
89  					n = ch.read(b);
90  				} while (n > 0 && b.position() < blockSize);
91  				return b;
92  			}
93  
94  			@Override
95  			public long size() throws IOException {
96  				return ch.size();
97  			}
98  
99  			@Override
100 			public void close() {
101 				try {
102 					ch.close();
103 				} catch (IOException e) {
104 					// Ignore close failures of read-only files.
105 				}
106 			}
107 		};
108 	}
109 
110 	/**
111 	 * Read a block from the file.
112 	 * <p>
113 	 * To reduce copying, the returned ByteBuffer should have an accessible
114 	 * array and {@code arrayOffset() == 0}. The caller will discard the
115 	 * ByteBuffer and directly use the backing array.
116 	 *
117 	 * @param position
118 	 *            position of the block in the file, specified in bytes from the
119 	 *            beginning of the file.
120 	 * @param blockSize
121 	 *            size to read.
122 	 * @return buffer containing the block content.
123 	 * @throws java.io.IOException
124 	 *             if block cannot be read.
125 	 */
126 	public abstract ByteBuffer read(long position, int blockSize)
127 			throws IOException;
128 
129 	/**
130 	 * Determine the size of the file.
131 	 *
132 	 * @return total number of bytes in the file.
133 	 * @throws java.io.IOException
134 	 *             if size cannot be obtained.
135 	 */
136 	public abstract long size() throws IOException;
137 
138 	/**
139 	 * Advise the {@code BlockSource} a sequential scan is starting.
140 	 *
141 	 * @param startPos
142 	 *            starting position.
143 	 * @param endPos
144 	 *            ending position.
145 	 */
146 	public void adviseSequentialRead(long startPos, long endPos) {
147 		// Do nothing by default.
148 	}
149 
150 	/** {@inheritDoc} */
151 	@Override
152 	public abstract void close();
153 }