/*
 *  Copyright 2020 Cojen.org
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Affero General Public License as
 *  published by the Free Software Foundation, either version 3 of the
 *  License, or (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.cojen.tupl.core;

import org.cojen.tupl.util.Runner;

/**
 * 
 *
 * @author Brian S O'Neill
 */
/*P*/
final class PendingTxnFinisher implements Runnable {
    // FIXME: Actually spin up more threads.
    private final int mMaxThreads;

    private PendingTxn mFirst, mLast;

    private boolean mRunning;

    PendingTxnFinisher() {
        this(Runtime.getRuntime().availableProcessors());
    }

    PendingTxnFinisher(int maxThreads) {
        mMaxThreads = maxThreads;
    }

    synchronized void enqueue(int count, PendingTxn first, PendingTxn last) {
        if (mLast == null) {
            mFirst = first;
        } else {
            mLast.mNext = first;
        }
        mLast = last;
        if (!mRunning) {
            Runner.start("PendingTxnFinisher", this);
            mRunning = true;
        } else {
            notify();
        }
    }

    @Override
    public void run() {
        while (true) {
            boolean waited = false;
            PendingTxn pending;
            synchronized (this) {
                while (true) {
                    pending = mFirst;
                    if (pending != null) {
                        if ((mFirst = pending.mNext) == null) {
                            mLast = null;
                        }
                        break;
                    }
                    if (waited) {
                        mRunning = false;
                        return;
                    }
                    try {
                        wait(10_000);
                    } catch (InterruptedException e) {
                    }
                    waited = true;
                }
            }

            pending.run();
        }
    }
}

@@ -740,16 +740,93 @@
 .core;%0A%0A
+import org.cojen.tupl.util.Latch;%0Aimport org.cojen.tupl.util.LatchCondition;%0A
 import o
@@ -932,16 +932,30 @@
 inisher 
+extends Latch 
 implemen
@@ -1049,16 +1049,62 @@
 reads;%0A%0A
+    private final LatchCondition mCondition;%0A%0A
     priv
@@ -1340,27 +1340,57 @@
     
-%7D%0A%0A
     
-synchronized
+mCondition = new LatchCondition();%0A    %7D%0A%0A   
  voi
@@ -1443,24 +1443,70 @@
 Txn last) %7B%0A
+        acquireExclusive();%0A        try %7B%0A    
         if (
@@ -1534,16 +1534,20 @@
         
+    
 mFirst =
@@ -1546,32 +1546,36 @@
 mFirst = first;%0A
+    
         %7D else %7B
@@ -1583,24 +1583,28 @@
             
+    
 mLast.mNext 
@@ -1612,34 +1612,42 @@
  first;%0A        
-%7D%0A
+    %7D%0A    
         mLast = 
@@ -1656,24 +1656,28 @@
 st;%0A        
+    
 if (!mRunnin
@@ -1677,24 +1677,28 @@
 mRunning) %7B%0A
+    
             
@@ -1743,32 +1743,36 @@
 s);%0A            
+    
 mRunning = true;
@@ -1772,32 +1772,36 @@
 = true;%0A        
+    
 %7D else %7B%0A       
@@ -1809,14 +1809,99 @@
     
-notify
+    mCondition.signal(this);%0A            %7D%0A        %7D finally %7B%0A            releaseExclusive
 ();%0A
@@ -2062,27 +2062,43 @@
     
-synchronized (this)
+acquireExclusive();%0A            try
  %7B%0A 
@@ -2547,181 +2547,161 @@
     
-try %7B%0A                        wait(10_000);%0A                    %7D catch (InterruptedException e) %7B%0A                    %7D%0A                    waited = true;%0A                %7D
+mCondition.await(this, 10_000_000_000L);%0A                    waited = true;%0A                %7D%0A            %7D finally %7B%0A                releaseExclusive();
 %0A   

Replace monitor with Latch, which tends to be more responsive.