/** * Do a group update for data associated with a given key * * @param accessor accessor with the ability to pull from the current data * @param options see {@link AccessOption} * @param key the data identifier * @param record the data to be merged in * @return true if successful, false otherwise */ public boolean commit( BaseDataAccessor<ZNRecord> accessor, int options, String key, ZNRecord record) { Queue queue = getQueue(key); Entry entry = new Entry(key, record); queue._pending.add(entry); while (!entry._sent.get()) { if (queue._running.compareAndSet(null, Thread.currentThread())) { ArrayList<Entry> processed = new ArrayList<Entry>(); try { if (queue._pending.peek() == null) return true; // remove from queue Entry first = queue._pending.poll(); processed.add(first); String mergedKey = first._key; // ZNRecord merged = _cache.get(mergedKey); ZNRecord merged = null; try { // accessor will fallback to zk if not found in cache merged = accessor.get(mergedKey, null, options); } catch (ZkNoNodeException e) { // OK. } /** * If the local cache does not contain a value, need to check if there is a value in ZK; * use it as initial value if exists */ if (merged == null) { // ZNRecord valueOnZk = null; // try // { // valueOnZk = accessor.get(mergedKey, null, 0); // } // catch(Exception e) // { // LOG.info(e); // } // if(valueOnZk != null) // { // merged = valueOnZk; // merged.merge(first._record); // } // else // Zk path has null data. use the first record as initial record. { merged = new ZNRecord(first._record); } } else { merged.merge(first._record); } Iterator<Entry> it = queue._pending.iterator(); while (it.hasNext()) { Entry ent = it.next(); if (!ent._key.equals(mergedKey)) continue; processed.add(ent); merged.merge(ent._record); // System.out.println("After merging:" + merged); it.remove(); } // System.out.println("size:"+ processed.size()); accessor.set(mergedKey, merged, options); // accessor.set(mergedKey, merged, BaseDataAccessor.Option.PERSISTENT); // _cache.put(mergedKey, merged); } finally { queue._running.set(null); for (Entry e : processed) { synchronized (e) { e._sent.set(true); e.notify(); } } } } else { synchronized (entry) { try { entry.wait(10); } catch (InterruptedException e) { e.printStackTrace(); return false; } } } } return true; }