View Javadoc
1   /*
2    * Prometheus: Application Framework
3    * Copyright 2012-2026. Tony Washer
4    *
5    * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6    * use this file except in compliance with the License.  You may obtain a copy
7    * of the License at
8    *
9    *   http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
14   * License for the specific language governing permissions and limitations under
15   * the License.
16   */
17  package io.github.tonywasher.joceanus.prometheus.database;
18  
19  import io.github.tonywasher.joceanus.metis.data.MetisDataState;
20  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataItem;
21  import io.github.tonywasher.joceanus.prometheus.data.PrometheusDataList;
22  
23  import java.util.ArrayList;
24  import java.util.Iterator;
25  import java.util.List;
26  import java.util.ListIterator;
27  import java.util.Objects;
28  
29  /**
30   * Batch control class. This controls updating data lists after the commit of the batch.
31   */
32  public class PrometheusBatchControl {
33      /**
34       * Capacity of Batch Control (0=Unlimited).
35       */
36      private final int theCapacity;
37  
38      /**
39       * Number of items in this batch.
40       */
41      private int theItems;
42  
43      /**
44       * The List of tables associated with this batch.
45       */
46      private final List<PrometheusBatchTable> theList;
47  
48      /**
49       * The Currently active Database table.
50       */
51      private PrometheusTableInstance<?> theCurrTable;
52  
53      /**
54       * The Currently active Mode.
55       */
56      private MetisDataState theCurrMode;
57  
58      /**
59       * Is the current table in use.
60       */
61      private boolean isTableActive;
62  
63      /**
64       * Constructor.
65       *
66       * @param pBatchSize the batch size
67       */
68      protected PrometheusBatchControl(final Integer pBatchSize) {
69          /* Create the batch table list */
70          theList = new ArrayList<>();
71  
72          /* Store capacity and capacity */
73          theCapacity = pBatchSize;
74      }
75  
76      /**
77       * Is the batch full.
78       *
79       * @return true/false is the batch full
80       */
81      protected boolean isFull() {
82          return theCapacity != 0
83                  && theItems >= theCapacity;
84      }
85  
86      /**
87       * Is the batch active.
88       *
89       * @return true/false is the batch active
90       */
91      protected boolean isActive() {
92          return theItems >= 0;
93      }
94  
95      /**
96       * Set the currently active state.
97       *
98       * @param pTable the Table being operated on
99       * @param pMode  the Mode that is in operation
100      */
101     protected void setCurrentTable(final PrometheusTableInstance<?> pTable,
102                                    final MetisDataState pMode) {
103         /* Store details */
104         theCurrTable = pTable;
105         theCurrMode = pMode;
106         isTableActive = false;
107     }
108 
109     /**
110      * Add item to the batch.
111      */
112     protected void addBatchItem() {
113         /* Increment batch count */
114         theItems++;
115 
116         /* If the current table is not active */
117         if (!isTableActive) {
118             /* Create the batch entry */
119             final PrometheusBatchTable myTable = new PrometheusBatchTable();
120 
121             /* Add to the batch list */
122             theList.add(myTable);
123             isTableActive = true;
124         }
125     }
126 
127     /**
128      * Commit the batch.
129      */
130     protected void commitItems() {
131         /* Access iterator for the list */
132 
133         /* Loop through the items */
134         for (PrometheusBatchTable myTable : theList) {
135             /* Access the next entry */
136             /* Commit batch items in the table */
137             if (Objects.requireNonNull(myTable.theState) == MetisDataState.DELETED) {
138                 myTable.commitDeleteBatch();
139             } else {
140                 myTable.commitBatch();
141             }
142         }
143 
144         /* Clear the list */
145         theList.clear();
146         isTableActive = false;
147         theItems = 0;
148     }
149 
150     /**
151      * Table step.
152      */
153     private final class PrometheusBatchTable {
154         /**
155          * The table that is being controlled.
156          */
157         private final PrometheusTableInstance<?> theTable;
158 
159         /**
160          * The State of the table.
161          */
162         private final MetisDataState theState;
163 
164         /**
165          * Constructor.
166          */
167         private PrometheusBatchTable() {
168             /* Store the details */
169             theTable = theCurrTable;
170             theState = theCurrMode;
171         }
172 
173         /**
174          * Mark updates in the table as committed for insert/change.
175          */
176         private void commitBatch() {
177             /* Access the iterator */
178             final Iterator<?> myIterator = theTable.getList().iterator();
179 
180             /* Loop through the list */
181             while (myIterator.hasNext()) {
182                 final PrometheusDataItem myCurr = (PrometheusDataItem) myIterator.next();
183 
184                 /* Ignore items that are not this type, otherwise commit and break if required */
185                 if (myCurr.getState() == theState
186                         && commitItem(myCurr)) {
187                     break;
188                 }
189             }
190         }
191 
192         /**
193          * Mark updates in the table as committed for delete.
194          */
195         private void commitDeleteBatch() {
196             /* Access the iterator */
197             final PrometheusDataList<?> myList = theTable.getList();
198             final ListIterator<?> myIterator = myList.listIterator(myList.size());
199 
200             /* Loop through the list */
201             while (myIterator.hasPrevious()) {
202                 final PrometheusDataItem myCurr = (PrometheusDataItem) myIterator.previous();
203 
204                 /* Ignore items that are not this type, otherwise commit and break if necessary */
205                 final MetisDataState myState = myCurr.getState();
206                 if ((myState == MetisDataState.DELETED
207                         || myState == MetisDataState.DELNEW)
208                         && commitItem(myCurr)) {
209                     break;
210                 }
211             }
212         }
213 
214         /**
215          * Mark an item in the table as committed.
216          *
217          * @param pItem the item to commit
218          * @return have we reached the end of the batch?
219          */
220         private boolean commitItem(final PrometheusDataItem pItem) {
221             /* Access the underlying element */
222             final PrometheusDataItem myBase = pItem.getBase();
223 
224             /* If we are handling deletions */
225             if (theState == MetisDataState.DELETED) {
226                 /* Unlink the underlying item */
227                 myBase.unLink();
228 
229                 /* Remove any registration */
230                 myBase.deRegister();
231 
232                 /* else we are handling new/changed items */
233             } else {
234                 /* Clear the history */
235                 myBase.clearHistory();
236             }
237 
238             /* Mark this item as clean */
239             pItem.clearHistory();
240 
241             /* If we have to worry about batch space */
242             /* Adjust batch and note if we are finished */
243             return theCapacity > 0
244                     && --theItems == 0;
245         }
246     }
247 }