-
Notifications
You must be signed in to change notification settings - Fork 522
/
PretoucherState.java
executable file
·102 lines (90 loc) · 3.77 KB
/
PretoucherState.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package net.openhft.chronicle.queue.impl.single;
import net.openhft.chronicle.bytes.MappedBytes;
import net.openhft.chronicle.bytes.MappedFile;
import net.openhft.chronicle.core.Jvm;
import net.openhft.chronicle.core.OS;
import org.jetbrains.annotations.NotNull;
import java.io.File;
import java.util.Optional;
import java.util.function.LongSupplier;
/**
* Created by peter on 25/11/2016.
*/
class PretoucherState {
private static final int HEAD_ROOM = 256 << 10;
private final LongSupplier posSupplier;
private int minHeadRoom;
private long lastTouchedPage = 0,
lastTouchedPos = 0,
lastPos = 0;
private int lastBytesHashcode = -1;
private long averageMove = 0;
public PretoucherState(LongSupplier posSupplier) {
this(posSupplier, HEAD_ROOM);
}
public PretoucherState(LongSupplier posSupplier, int minHeadRoom) {
this.posSupplier = posSupplier;
this.minHeadRoom = minHeadRoom;
}
static File getFile(MappedBytes bytes) {
return Optional.ofNullable(bytes)
.map(MappedBytes::mappedFile)
.map(MappedFile::file)
.orElse(new File("none"));
}
// cannot make this @NotNull until PretoucherStateTest is fixed to not pass null
public void pretouch(MappedBytes bytes) {
long pos = posSupplier.getAsLong();
// don't retain the bytes object when it is head so keep the hashCode instead.
// small risk of a duplicate hashCode.
int pageSize = OS.pageSize();
if (lastBytesHashcode != System.identityHashCode(bytes)) {
lastTouchedPage = pos - pos % pageSize;
lastTouchedPos = pos;
lastBytesHashcode = System.identityHashCode(bytes);
averageMove = OS.pageSize();
lastPos = pos;
String message = getFile(bytes) + " - Reset pretoucher to pos " + pos + " as the underlying MappedBytes changed.";
debug(message);
} else {
long moved = pos - lastPos;
averageMove = moved / 4 + averageMove * 3 / 4;
long neededHeadRoom = Math.max(minHeadRoom, averageMove * 4); // for the next 4 ticks.
final long neededEnd = pos + neededHeadRoom;
if (lastTouchedPage < neededEnd) {
Thread thread = Thread.currentThread();
int count = 0, pretouch = 0;
for (; lastTouchedPage < neededEnd; lastTouchedPage += pageSize) {
if (thread.isInterrupted())
break;
if (touchPage(bytes, lastTouchedPage))
pretouch++;
count++;
}
onTouched(count);
if (pretouch < count) {
minHeadRoom += 256 << 10;
debug("pretouch for only " + pretouch + " of " + count + " min: " + (minHeadRoom >> 20) + " MB.");
}
long pos2 = posSupplier.getAsLong();
if (Jvm.isDebugEnabled(getClass())) {
String message = getFile(bytes) + ": Advanced " + (pos - lastTouchedPos) / 1024 + " KB, " +
"avg " + averageMove / 1024 + " KB " +
"between pretouch() and " + (pos2 - pos) / 1024 + " KB " +
"while mapping of " + pretouch * pageSize / 1024 + " KB ";
debug(message);
}
lastTouchedPos = pos;
}
lastPos = pos;
}
}
protected void debug(String message) {
Jvm.debug().on(getClass(), message);
}
protected boolean touchPage(@NotNull MappedBytes bytes, long offset) {
return bytes.compareAndSwapLong(offset, 0L, 0L);
}
protected void onTouched(int count) {
}
}