1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.channel.uring;
17
18 import io.netty.channel.DefaultFileRegion;
19 import io.netty.channel.FileRegion;
20 import io.netty.channel.unix.FileDescriptor;
21 import io.netty.util.internal.logging.InternalLogger;
22 import io.netty.util.internal.logging.InternalLoggerFactory;
23
24 import java.io.IOException;
25 import java.nio.channels.WritableByteChannel;
26
27 final class IoUringFileRegion implements FileRegion {
28 private static final InternalLogger logger = InternalLoggerFactory.getInstance(IoUringFileRegion.class);
29
30 private static final short SPLICE_TO_PIPE = 1;
31 private static final short SPLICE_TO_SOCKET = 2;
32
33 final DefaultFileRegion fileRegion;
34 private FileDescriptor[] pipe;
35 private int transferred;
36 private int pipeLen = -1;
37
38 IoUringFileRegion(DefaultFileRegion fileRegion) {
39 this.fileRegion = fileRegion;
40 }
41
42 void open() throws IOException {
43 fileRegion.open();
44 if (pipe == null) {
45 pipe = FileDescriptor.pipe();
46 }
47 }
48
49 IoUringIoOps splice(int fd) {
50 if (pipeLen == -1) {
51 return spliceToPipe();
52 }
53 return spliceToSocket(fd, pipeLen);
54 }
55
56 IoUringIoOps spliceToPipe() {
57 int fileRegionFd = Native.getFd(fileRegion);
58 int len = (int) (count() - transferred());
59 int offset = (int) (position() + transferred());
60 return IoUringIoOps.newSplice(
61 fileRegionFd, offset,
62 pipe[1].intValue(), -1L,
63 len, Native.SPLICE_F_MOVE, SPLICE_TO_PIPE);
64 }
65
66 private IoUringIoOps spliceToSocket(int socket, int len) {
67 return IoUringIoOps.newSplice(
68 pipe[0].intValue(), -1L,
69 socket, -1L,
70 len, Native.SPLICE_F_MOVE, SPLICE_TO_SOCKET);
71 }
72
73
74
75
76
77
78
79
80 int handleResult(int result, short data) {
81 assert result >= 0;
82 if (data == SPLICE_TO_PIPE) {
83
84 transferred += result;
85 pipeLen = result;
86 return 0;
87 }
88 if (data == SPLICE_TO_SOCKET) {
89
90 pipeLen -= result;
91 assert pipeLen >= 0;
92 if (pipeLen == 0) {
93 if (transferred() >= count()) {
94
95 return -1;
96 }
97 pipeLen = -1;
98 }
99 return result;
100 }
101 throw new IllegalArgumentException("Unknown data: " + data);
102 }
103
104 @Override
105 public long position() {
106 return fileRegion.position();
107 }
108
109 @Override
110 public long transfered() {
111 return transferred;
112 }
113
114 @Override
115 public long transferred() {
116 return transferred;
117 }
118
119 @Override
120 public long count() {
121 return fileRegion.count();
122 }
123
124 @Override
125 public long transferTo(WritableByteChannel target, long position) {
126 throw new UnsupportedOperationException();
127 }
128
129 @Override
130 public FileRegion retain() {
131 fileRegion.retain();
132 return this;
133 }
134
135 @Override
136 public FileRegion retain(int increment) {
137 fileRegion.retain(increment);
138 return this;
139 }
140
141 @Override
142 public FileRegion touch() {
143 fileRegion.touch();
144 return this;
145 }
146
147 @Override
148 public FileRegion touch(Object hint) {
149 fileRegion.touch(hint);
150 return this;
151 }
152
153 @Override
154 public int refCnt() {
155 return fileRegion.refCnt();
156 }
157
158 @Override
159 public boolean release() {
160 if (fileRegion.release()) {
161 closePipeIfNeeded();
162 return true;
163 }
164 return false;
165 }
166
167 @Override
168 public boolean release(int decrement) {
169 if (fileRegion.release(decrement)) {
170 closePipeIfNeeded();
171 return true;
172 }
173 return false;
174 }
175
176 private void closePipeIfNeeded() {
177 if (pipe != null) {
178 closeSilently(pipe[0]);
179 closeSilently(pipe[1]);
180 }
181 }
182
183 private static void closeSilently(FileDescriptor fd) {
184 try {
185 fd.close();
186 } catch (IOException e) {
187 logger.debug("Error while closing a pipe", e);
188 }
189 }
190 }