//------------------------------------------------------------------------------ // File : SnapshotCounter.java // Author : Ms.Moran Tzafrir // Written : 13 April 2009 // // Multi-Platform C++ framework // // Copyright (C) 2009 Moran Tzafrir, Nir Shavit. // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation; either version 2 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 // General Public License for more details. // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software Foundation // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA //------------------------------------------------------------------------------ // Fixed: //------------------------------------------------------------------------------ // TODO: //------------------------------------------------------------------------------ package linkedlists.lockbased.lazyutils; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; public final class SnapshotCounter { //constants ----------------------------------- private final int _NUM_PROCESS; //helper functions ---------------------------- private static final int get_size(final long counterAndValue) { return (int)(counterAndValue & 0xFFFFFFFFL); } private static final int get_seq(final long counterAndValue) { return (int)(counterAndValue >>> 32); } private static final long build_seq_value(final int seq, final int value) { return (((long)seq << 32) | (long)value); } //inner classes ------------------------------- private static final class process_data { private long _recent_seq_value; private long _prev_seq_value; process_data() { _recent_seq_value = 0; _prev_seq_value = 0; } int recent_seq() { return get_seq(_recent_seq_value); } int recent_seq_int() { return get_seq(_recent_seq_value); } int prev_seq() { return get_seq(_prev_seq_value); } int recent_value() { return get_size(_recent_seq_value); } int prev_value() { return get_size(_prev_seq_value); } void update(final int counter, final int value) { _recent_seq_value = build_seq_value(counter, value); } void update_prev(final int counter, final int value) { _prev_seq_value = build_seq_value(counter, value); } void set_prev_to_curr() { _prev_seq_value = _recent_seq_value; } } //fields -------------------------------------- private process_data gMem[]; private AtomicInteger gSeq; private AtomicLong gView; //public operations --------------------------- public SnapshotCounter(final int num_process) { _NUM_PROCESS = num_process; gSeq = new AtomicInteger(1); gView = new AtomicLong(0); gMem = new process_data[_NUM_PROCESS]; for(int iProcess=0; iProcess < _NUM_PROCESS; ++iProcess) { gMem[iProcess] = new process_data(); } } public void update(final int iProcess, final int new_value) { final process_data pdata = gMem[iProcess]; final int update_seq = gSeq.get(); if (update_seq != pdata.recent_seq()) pdata.set_prev_to_curr(); pdata.update(update_seq, new_value); } public void inc(final int iProcess) { final process_data pdata = gMem[iProcess]; final int update_seq = gSeq.get(); if (update_seq != pdata.recent_seq()) pdata.set_prev_to_curr(); pdata.update(update_seq, pdata.recent_value()+1); } public void dec(final int iProcess) { final process_data pdata = gMem[iProcess]; final int update_seq = gSeq.get(); if (update_seq != pdata.recent_seq()) pdata.set_prev_to_curr(); pdata.update(update_seq, pdata.recent_value()-1); } public void add(final int iProcess, final int x) { final process_data pdata = gMem[iProcess]; final int update_seq = gSeq.get(); if (update_seq != pdata.recent_seq()) pdata.set_prev_to_curr(); pdata.update(update_seq, pdata.recent_value()+x); } public int valueRequest(final int iProcess) { return (int)(gMem[iProcess].recent_value()); } @SuppressWarnings("empty-statement") public int scan_sum() { final int init_seq = gSeq.get(); if(init_seq > 2) { int iTry=0; final int max_wait = (_NUM_PROCESS*2000); while((init_seq > (get_seq(gView.get()))) && iTry<max_wait) {++iTry;--iTry; ++iTry;--iTry;++iTry;} if(init_seq < get_seq(gView.get())) return get_size(gView.get()); } long start_view = gView.get(); int scan_seq = gSeq.incrementAndGet(); final int first_seq = scan_seq; do { int size=0; boolean scan_ok=true; for(int iProcess=0; iProcess < _NUM_PROCESS; ++iProcess) { final process_data pdata = gMem[iProcess]; final long prev = pdata._prev_seq_value; final long recent = pdata._recent_seq_value; if (get_seq(recent) < scan_seq) size += pdata.recent_value(); else if (get_seq(recent) == scan_seq) size += get_size(prev); else { scan_ok=false; start_view = gView.get(); scan_seq = pdata.recent_seq(); break; } } if(first_seq <= get_seq(gView.get())) return get_size(gView.get()); if(scan_ok) { if(gView.compareAndSet(start_view, build_seq_value(scan_seq, size))) return size; start_view = gView.get(); } } while (true); } }