protected void recover (int session, long id) { LogEvent evt = getLog().createLogEvent ("recover"); Profiler prof = new Profiler(); evt.addMessage ("<id>" + id + "</id>"); try { String stateKey = getKey (STATE, id); String contextKey = getKey (CONTEXT, id); Integer state = (Integer) psp.rdp (stateKey); if (state == null) { evt.addMessage ("unknown stateKey " + stateKey); SpaceUtil.wipe (psp, contextKey); // just in case ... return; } Serializable context = (Serializable) psp.rdp (contextKey); if (context != null) evt.addMessage (context); if (DONE.equals (state)) { evt.addMessage ("<done/>"); } else if (COMMITTING.equals (state)) { commit (session, id, context, getParticipants (id), true, evt, prof); } else if (PREPARING.equals (state)) { abort (session, id, context, getParticipants (id), true, evt, prof); } purge (id, true); } finally { evt.addMessage (prof); Logger.log (evt); } } protected synchronized void checkRetryTask () {
private Map<String,Object> txnmgrInfo(TransactionManager txnmgr) { Map<String,Object> m = new LinkedHashMap<>(); m.put ("name", txnmgr.getName()); m.put ("type", txnmgr.getClass().getSimpleName()); m.put ("tail", txnmgr.getTail()); m.put ("head", txnmgr.getHead()); m.put ("inTransit", txnmgr.getInTransit()); m.put ("TPSAvg", txnmgr.getTPSAvg()); m.put ("TPSPeak", txnmgr.getTPSPeak()); m.put ("TPSPeakWhen", txnmgr.getTPSPeakWhen()); m.put ("TPSElapsed", txnmgr.getTPSElapsed()); m.put ("metrics", txnmgr.getMetrics().metrics()); return m; }
@Override public void run() { Thread.currentThread().setName (getName()+"-input-queue-monitor"); while (running()) { while (getOutstandingTransactions() > getActiveSessions() + threshold && running()) { ISOUtil.sleep(100L); } if (!running()) break; try { Object context = isp.in(queue, 1000L); if (context != null) { if (!running()) { isp.out(queue, context); // place it back break; } iisp.out(queue, context); } } catch (SpaceError e) { getLog().error(e); ISOUtil.sleep(1000L); // relax on error } } } }
activeSessions.incrementAndGet(); } else { getLog().warn ("Max sessions reached, new session not created"); return; getLog().info ("start " + thread); while (running()) { Serializable context = null; prof = null; paused = false; transactionActive = false; thread.setName (getName() + "-" + session + ":idle"); int action = -1; try { if (hasStatusListeners) notifyStatusListeners (session, TransactionStatusEvent.State.READY, id, "", null); if (session+1 > sessions && getActiveSessions() > sessions) break; // we are an extra session, exit else { getLog().error ( "non serializable '" + obj.getClass().getName() + "' on queue '" + queue + "'" prof = pt.getProfiler(); if (metrics != null && prof != null) metrics.record(getName(pt.getParticipant()) + "-resume", prof.getPartialInMillis());
int action; if (i > MAX_PARTICIPANTS) { getLog().warn ( "loop detected - transaction " +id + " aborted." ); if (abort) { if (hasStatusListeners) notifyStatusListeners ( session, TransactionStatusEvent.State.PREPARING_FOR_ABORT, id, getName(p), context ); action = prepareForAbort (p, id, context); evt.addMessage("prepareForAbort: " + getName(p)); if (prof != null) prof.checkPoint ("prepareForAbort: " + getName(p)); notifyStatusListeners ( session, TransactionStatusEvent.State.PREPARING, id, getName(p), context ); action = prepare (p, id, context); if (evt != null) { evt.addMessage (" prepare: " + getName(p) + (abort ? " ABORTED" : " PREPARED") + (retry ? " RETRY" : "") + ((action & NO_JOIN) == NO_JOIN ? " NO_JOIN" : ""));
@Override public void startService () throws Exception { NameRegistrar.register(getName(), this); recover(); threads = Collections.synchronizedList(new ArrayList(maxSessions)); if (tps != null) checkRetryTask(); loadMonitorExecutor.scheduleAtFixedRate( new Thread(() -> { int outstandingTransactions = getOutstandingTransactions(); int activeSessions = getActiveSessions(); if (activeSessions < maxSessions && outstandingTransactions > threshold) { int count = Math.min(outstandingTransactions, maxSessions - activeSessions); for (int i=0; i<count; i++) new Thread(this).start(); getLog().info("Created " + count + " additional sessions");
protected void commit (TransactionParticipant p, long id, Serializable context) { Chronometer c = new Chronometer(); try { setThreadName(id, "commit", p); p.commit(id, context); } catch (Throwable t) { getLog().warn ("COMMIT: " + Long.toString (id), t); } if (metrics != null) metrics.record(getName(p) + "-commit", c.elapsed()); } protected void abort
@Override public void dump (PrintStream ps, String indent) { ps.printf ("%sin-transit=%d/%d, head=%d, tail=%d, paused=%d, outstanding=%d, active-sessions=%d/%d%s%n", indent, getActiveTransactions(), getInTransit(), head, tail, pausedCounter.get(), getOutstandingTransactions(), getActiveSessions(), maxSessions, (tps != null ? ", " + tps.toString() : "") ); if (metrics != null) { metrics.dump(ps, indent); } }
protected void purge (long id, boolean full) { String stateKey = getKey (STATE, id); String contextKey = getKey (CONTEXT, id); String groupsKey = getKey (GROUPS, id); synchronized (psp) { commitOff (psp); if (full) SpaceUtil.wipe(psp, stateKey); SpaceUtil.wipe(psp, contextKey); SpaceUtil.wipe(psp, groupsKey); commitOn (psp); } }
protected void commit (int session, long id, Serializable context, List<TransactionParticipant> members, boolean recover, LogEvent evt, Profiler prof) { for (TransactionParticipant p :members) { if (recover && p instanceof ContextRecovery) { context = ((ContextRecovery) p).recover (id, context, true); if (evt != null) evt.addMessage (" commit-recover: " + getName(p)); } if (hasStatusListeners) notifyStatusListeners ( session, TransactionStatusEvent.State.COMMITING, id, getName(p), context ); commit (p, id, context); if (evt != null) { evt.addMessage (" commit: " + getName(p)); if (prof != null) prof.checkPoint (" commit: " + getName(p)); } } } protected void abort
protected void abort (int session, long id, Serializable context, List<TransactionParticipant> members, boolean recover, LogEvent evt, Profiler prof) { for (TransactionParticipant p :members) { if (recover && p instanceof ContextRecovery) { context = ((ContextRecovery) p).recover (id, context, false); if (evt != null) evt.addMessage (" abort-recover: " + getName(p)); } if (hasStatusListeners) notifyStatusListeners ( session, TransactionStatusEvent.State.ABORTING, id, getName(p), context ); abort(p, id, context); if (evt != null) { evt.addMessage (" abort: " + getName(p)); if (prof != null) prof.checkPoint (" abort: " + getName(p)); } } } protected int prepareForAbort
@Test public void testCommit2() throws Throwable { members.add(new CheckPoint()); transactionManager.commit(1, 100L, new IOException(), members, false, null, null); assertEquals("(ArrayList) members.size()", 1, members.size()); }
protected List<TransactionParticipant> getParticipants (long id) { // Use a local copy of participant to avoid adding the // GROUP participant to the DEFAULT_GROUP List<TransactionParticipant> participantsChain = new ArrayList(); List<TransactionParticipant> participants = getParticipants (DEFAULT_GROUP); // Add DEFAULT_GROUP participants participantsChain.addAll(participants); String key = getKey(GROUPS, id); String grp; // now add participants of Group while ( (grp = (String) psp.inp (key)) != null) { participantsChain.addAll (getParticipants (grp)); } return participantsChain; }
@Test public void testAbort5() throws Throwable { transactionManager.abort(1, 100L, Long.valueOf(-64L), members, members.add(new Join()), null, null); assertEquals("(ArrayList) members.size()", 1, members.size()); }
public void update(TransactionStatusEvent e) { if (ui.isDestroyed()) { return; } int row = e.getSession(); events[row] = e; model.fireTableRowsUpdated(row, row); // table.getSelectionModel().setSelectionInterval(row, row); setBackgroundColor (row, color[e.getState().intValue()]); inTransit.setText (Long.toString (txnmgr.getInTransit())); outstanding.setText (Long.toString (txnmgr.getOutstandingTransactions())); } private void setBackgroundColor (int row, Color color) {
@Override public void stopService () { NameRegistrar.unregister(getName()); if (loadMonitorExecutor != null) loadMonitorExecutor.shutdown(); Thread[] tt = threads.toArray(new Thread[threads.size()]); if (iisp != isp) for (Object o=iisp.inp(queue); o != null; o=iisp.inp(queue)) isp.out(queue, o); // push back to replicated space for (Thread t : tt) iisp.out(queue, Boolean.FALSE, 60 * 1000); for (Thread thread : tt) { try { thread.join (60*1000); threads.remove(thread); } catch (InterruptedException e) { getLog().warn ("Session " + thread.getName() +" does not respond - attempting to interrupt"); thread.interrupt(); } } tps.stop(); for (Destroyable destroyable : destroyables) { try { destroyable.destroy(); } catch (Throwable t) { getLog().warn (t); } } } public void queue (Serializable context) {
@Test public void testConstructor() throws Throwable { assertNull("transactionManager.retryTask", transactionManager.retryTask); assertEquals("transactionManager.getLog().getRealm()", "org.jpos.transaction.TransactionManager", transactionManager .getLog().getRealm()); assertEquals("transactionManager.getState()", -1, transactionManager.getState()); assertTrue("transactionManager.isModified()", transactionManager.isModified()); assertEquals("transactionManager.pauseTimeout", 0L, transactionManager.pauseTimeout); assertEquals("transactionManager.retryInterval", 5000L, transactionManager.retryInterval); }