예제 #1
0
  private boolean step() {
    if (next != NONE) return true;

    while (next == NONE) {
      if (buffer.isEmpty()) {
        if (completed) {
          return false;
        } else if (sourceIter.hasNext()) {
          Object iter = null;
          if (multi) iter = xf.applyTo(RT.cons(null, sourceIter.next()));
          else iter = xf.invoke(null, sourceIter.next());

          if (RT.isReduced(iter)) {
            xf.invoke(null);
            completed = true;
          }
        } else {
          xf.invoke(null);
          completed = true;
        }
      } else {
        next = buffer.remove();
      }
    }
    return true;
  }
예제 #2
0
 Object doCommute(Ref ref, IFn fn, ISeq args) {
   if (!info.running()) throw retryex;
   if (!vals.containsKey(ref)) {
     Object val = null;
     try {
       ref.lock.readLock().lock();
       val = ref.tvals == null ? null : ref.tvals.val;
     } finally {
       ref.lock.readLock().unlock();
     }
     vals.put(ref, val);
   }
   ArrayList<CFn> fns = commutes.get(ref);
   if (fns == null) commutes.put(ref, fns = new ArrayList<CFn>());
   fns.add(new CFn(fn, args));
   Object ret = fn.applyTo(RT.cons(vals.get(ref), args));
   vals.put(ref, ret);
   return ret;
 }
예제 #3
0
 public ISeq cons(Object o) {
   return RT.cons(o, seq());
 }
예제 #4
0
  Object run(Callable fn) throws Exception {
    boolean done = false;
    Object ret = null;
    ArrayList<Ref> locked = new ArrayList<Ref>();
    ArrayList<Notify> notify = new ArrayList<Notify>();

    for (int i = 0; !done && i < RETRY_LIMIT; i++) {
      try {
        getReadPoint();
        if (i == 0) {
          startPoint = readPoint;
          startTime = System.nanoTime();
        }
        info = new Info(RUNNING, startPoint);
        ret = fn.call();
        // make sure no one has killed us before this point, and can't from now on
        if (info.status.compareAndSet(RUNNING, COMMITTING)) {
          for (Map.Entry<Ref, ArrayList<CFn>> e : commutes.entrySet()) {
            Ref ref = e.getKey();
            if (sets.contains(ref)) continue;

            boolean wasEnsured = ensures.contains(ref);
            // can't upgrade readLock, so release it
            releaseIfEnsured(ref);
            tryWriteLock(ref);
            locked.add(ref);
            if (wasEnsured && ref.tvals != null && ref.tvals.point > readPoint) throw retryex;

            Info refinfo = ref.tinfo;
            if (refinfo != null && refinfo != info && refinfo.running()) {
              if (!barge(refinfo)) throw retryex;
            }
            Object val = ref.tvals == null ? null : ref.tvals.val;
            vals.put(ref, val);
            for (CFn f : e.getValue()) {
              vals.put(ref, f.fn.applyTo(RT.cons(vals.get(ref), f.args)));
            }
          }
          for (Ref ref : sets) {
            tryWriteLock(ref);
            locked.add(ref);
          }

          // validate and enqueue notifications
          for (Map.Entry<Ref, Object> e : vals.entrySet()) {
            Ref ref = e.getKey();
            ref.validate(ref.getValidator(), e.getValue());
          }

          // at this point, all values calced, all refs to be written locked
          // no more client code to be called
          long commitPoint = getCommitPoint();
          for (Map.Entry<Ref, Object> e : vals.entrySet()) {
            Ref ref = e.getKey();
            Object oldval = ref.tvals == null ? null : ref.tvals.val;
            Object newval = e.getValue();
            int hcount = ref.histCount();

            if (ref.tvals == null) {
              ref.tvals = new Ref.TVal(newval, commitPoint);
            } else if ((ref.faults.get() > 0 && hcount < ref.maxHistory)
                || hcount < ref.minHistory) {
              ref.tvals = new Ref.TVal(newval, commitPoint, ref.tvals);
              ref.faults.set(0);
            } else {
              ref.tvals = ref.tvals.next;
              ref.tvals.val = newval;
              ref.tvals.point = commitPoint;
            }
            if (ref.getWatches().count() > 0) notify.add(new Notify(ref, oldval, newval));
          }

          done = true;
          info.status.set(COMMITTED);
        }
      } catch (RetryEx retry) {
        // eat this so we retry rather than fall out
      } finally {
        for (int k = locked.size() - 1; k >= 0; --k) {
          locked.get(k).lock.writeLock().unlock();
        }
        locked.clear();
        for (Ref r : ensures) {
          r.lock.readLock().unlock();
        }
        ensures.clear();
        stop(done ? COMMITTED : RETRY);
        try {
          if (done) // re-dispatch out of transaction
          {
            for (Notify n : notify) {
              n.ref.notifyWatches(n.oldval, n.newval);
            }
            for (Agent.Action action : actions) {
              Agent.dispatchAction(action);
            }
          }
        } finally {
          notify.clear();
          actions.clear();
        }
      }
    }
    if (!done) throw Util.runtimeException("Transaction failed after reaching retry limit");
    return ret;
  }