1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.store.fs; |
7 | |
8 | import java.io.IOException; |
9 | import java.io.RandomAccessFile; |
10 | import java.nio.ByteBuffer; |
11 | import java.nio.channels.FileChannel; |
12 | import java.nio.channels.FileLock; |
13 | import java.nio.channels.NonWritableChannelException; |
14 | |
15 | /** |
16 | * This file system stores files on disk and uses java.nio to access the files. |
17 | * This class uses FileChannel. |
18 | */ |
19 | public class FilePathNio extends FilePathWrapper { |
20 | |
21 | @Override |
22 | public FileChannel open(String mode) throws IOException { |
23 | return new FileNio(name.substring(getScheme().length() + 1), mode); |
24 | } |
25 | |
26 | @Override |
27 | public String getScheme() { |
28 | return "nio"; |
29 | } |
30 | |
31 | } |
32 | |
33 | /** |
34 | * File which uses NIO FileChannel. |
35 | */ |
36 | class FileNio extends FileBase { |
37 | |
38 | private final String name; |
39 | private final FileChannel channel; |
40 | |
41 | FileNio(String fileName, String mode) throws IOException { |
42 | this.name = fileName; |
43 | channel = new RandomAccessFile(fileName, mode).getChannel(); |
44 | } |
45 | |
46 | @Override |
47 | public void implCloseChannel() throws IOException { |
48 | channel.close(); |
49 | } |
50 | |
51 | @Override |
52 | public long position() throws IOException { |
53 | return channel.position(); |
54 | } |
55 | |
56 | @Override |
57 | public long size() throws IOException { |
58 | return channel.size(); |
59 | } |
60 | |
61 | @Override |
62 | public int read(ByteBuffer dst) throws IOException { |
63 | return channel.read(dst); |
64 | } |
65 | |
66 | @Override |
67 | public FileChannel position(long pos) throws IOException { |
68 | channel.position(pos); |
69 | return this; |
70 | } |
71 | |
72 | @Override |
73 | public int read(ByteBuffer dst, long position) throws IOException { |
74 | return channel.read(dst, position); |
75 | } |
76 | |
77 | @Override |
78 | public int write(ByteBuffer src, long position) throws IOException { |
79 | return channel.write(src, position); |
80 | } |
81 | |
82 | @Override |
83 | public FileChannel truncate(long newLength) throws IOException { |
84 | long size = channel.size(); |
85 | if (newLength < size) { |
86 | long pos = channel.position(); |
87 | channel.truncate(newLength); |
88 | long newPos = channel.position(); |
89 | if (pos < newLength) { |
90 | // position should stay |
91 | // in theory, this should not be needed |
92 | if (newPos != pos) { |
93 | channel.position(pos); |
94 | } |
95 | } else if (newPos > newLength) { |
96 | // looks like a bug in this FileChannel implementation, as |
97 | // the documentation says the position needs to be changed |
98 | channel.position(newLength); |
99 | } |
100 | } |
101 | return this; |
102 | } |
103 | |
104 | @Override |
105 | public void force(boolean metaData) throws IOException { |
106 | channel.force(metaData); |
107 | } |
108 | |
109 | @Override |
110 | public int write(ByteBuffer src) throws IOException { |
111 | try { |
112 | return channel.write(src); |
113 | } catch (NonWritableChannelException e) { |
114 | throw new IOException("read only"); |
115 | } |
116 | } |
117 | |
118 | @Override |
119 | public synchronized FileLock tryLock(long position, long size, |
120 | boolean shared) throws IOException { |
121 | return channel.tryLock(position, size, shared); |
122 | } |
123 | |
124 | @Override |
125 | public String toString() { |
126 | return "nio:" + name; |
127 | } |
128 | |
129 | } |