Rework JournalSegment writer access
[controller.git] / atomix-storage / src / main / java / io / atomix / storage / journal / SegmentedJournalWriter.java
1 /*
2  * Copyright 2017-present Open Networking Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package io.atomix.storage.journal;
17
18 import java.nio.BufferOverflowException;
19
20 /**
21  * Raft log writer.
22  */
23 public final class SegmentedJournalWriter<E> implements JournalWriter<E> {
24   private final SegmentedJournal<E> journal;
25   private JournalSegment<E> currentSegment;
26   private MappableJournalSegmentWriter<E> currentWriter;
27
28   SegmentedJournalWriter(SegmentedJournal<E> journal) {
29     this.journal = journal;
30     this.currentSegment = journal.getLastSegment();
31     this.currentWriter = currentSegment.acquireWriter();
32   }
33
34   @Override
35   public long getLastIndex() {
36     return currentWriter.getLastIndex();
37   }
38
39   @Override
40   public Indexed<E> getLastEntry() {
41     return currentWriter.getLastEntry();
42   }
43
44   @Override
45   public long getNextIndex() {
46     return currentWriter.getNextIndex();
47   }
48
49   @Override
50   public void reset(long index) {
51     if (index > currentSegment.index()) {
52       currentSegment.releaseWriter();
53       currentSegment = journal.resetSegments(index);
54       currentWriter = currentSegment.acquireWriter();
55     } else {
56       truncate(index - 1);
57     }
58     journal.resetHead(index);
59   }
60
61   @Override
62   public void commit(long index) {
63     if (index > journal.getCommitIndex()) {
64       journal.setCommitIndex(index);
65       if (journal.isFlushOnCommit()) {
66         flush();
67       }
68     }
69   }
70
71   @Override
72   public <T extends E> Indexed<T> append(T entry) {
73     try {
74       return currentWriter.append(entry);
75     } catch (BufferOverflowException e) {
76       if (currentSegment.index() == currentWriter.getNextIndex()) {
77         throw e;
78       }
79     }
80
81     moveToNextSegment();
82     return currentWriter.append(entry);
83   }
84
85   @Override
86   public void append(Indexed<E> entry) {
87     try {
88       currentWriter.append(entry);
89       return;
90     } catch (BufferOverflowException e) {
91       if (currentSegment.index() == currentWriter.getNextIndex()) {
92         throw e;
93       }
94     }
95
96     moveToNextSegment();
97     currentWriter.append(entry);
98   }
99
100   private void moveToNextSegment() {
101     currentWriter.flush();
102     currentSegment.releaseWriter();
103     currentSegment = journal.getNextSegment();
104     currentWriter = currentSegment.acquireWriter();
105   }
106
107   @Override
108   public void truncate(long index) {
109     if (index < journal.getCommitIndex()) {
110       throw new IndexOutOfBoundsException("Cannot truncate committed index: " + index);
111     }
112
113     // Delete all segments with first indexes greater than the given index.
114     while (index < currentSegment.index() && currentSegment != journal.getFirstSegment()) {
115       currentSegment.releaseWriter();
116       journal.removeSegment(currentSegment);
117       currentSegment = journal.getLastSegment();
118       currentWriter = currentSegment.acquireWriter();
119     }
120
121     // Truncate the current index.
122     currentWriter.truncate(index);
123
124     // Reset segment readers.
125     journal.resetTail(index + 1);
126   }
127
128   @Override
129   public void flush() {
130     currentWriter.flush();
131   }
132
133   @Override
134   public void close() {
135     currentWriter.close();
136   }
137 }