/** * @param state State to update. * @return Modified state. */ private long releaseWithTag(long state, int newTag) { int lock = lockCount(state); int readersWait = readersWaitCount(state); int writersWait = writersWaitCount(state); int tag = newTag == TAG_LOCK_ALWAYS ? tag(state) : newTag & 0xFFFF; lock += 1; assert readersWait >= 0 : readersWait; assert writersWait >= 0 : writersWait; assert lock >= -1; return buildState(writersWait, readersWait, tag, lock); }
int writeWaitCnt = writersWaitCount(state); if (!checkTag(state, tag)) return false; if (canReadLock(state)) { if (GridUnsafe.compareAndSwapLong(null, lock, state, updateState(state, 1, 0, 0))) return true; else int idx = lockIndex(lock); updateReadersWaitCount(lock, lockObj, 1); return waitAcquireReadLock(lock, idx, tag);
/** * @param lock Lock address. */ public boolean writeLock(long lock, int tag) { assert tag != 0; for (int i = 0; i < SPIN_CNT; i++) { long state = GridUnsafe.getLongVolatile(null, lock); assert state != 0; if (!checkTag(state, tag)) return false; if (canWriteLock(state)) { if (GridUnsafe.compareAndSwapLong(null, lock, state, updateState(state, -1, 0, 0))) return true; else // Retry CAS, do not count as spin cycle. i--; } } int idx = lockIndex(lock); ReentrantLock lockObj = locks[idx]; lockObj.lock(); try { updateWritersWaitCount(lock, lockObj, 1); return waitAcquireWriteLock(lock, idx, tag); } finally { lockObj.unlock(); } }
/** * @param lock Lock address. */ public boolean tryWriteLock(long lock, int tag) { long state = GridUnsafe.getLongVolatile(null, lock); return checkTag(state, tag) && canWriteLock(state) && GridUnsafe.compareAndSwapLong(null, lock, state, updateState(state, -1, 0, 0)); }
/** * @param lock Lock address. */ public void writeUnlock(long lock, int tag) { long updated; assert tag != 0; while (true) { long state = GridUnsafe.getLongVolatile(null, lock); if (lockCount(state) != -1) throw new IllegalMonitorStateException("Attempted to release write lock while not holding it " + "[lock=" + U.hexLong(lock) + ", state=" + U.hexLong(state) + ']'); updated = releaseWithTag(state, tag); assert updated != 0; if (GridUnsafe.compareAndSwapLong(null, lock, state, updated)) break; } int writeWaitCnt = writersWaitCount(updated); int readWaitCnt = readersWaitCount(updated); if (writeWaitCnt > 0 || readWaitCnt > 0) { int idx = lockIndex(lock); ReentrantLock lockObj = locks[idx]; lockObj.lock(); try { signalNextWaiter(writeWaitCnt, readWaitCnt, idx); } finally { lockObj.unlock(); } } }
long state = GridUnsafe.getLongVolatile(null, lock); if (!checkTag(state, tag)) { long updated = updateState(state, 0, -1, 0); int writeWaitCnt = writersWaitCount(updated); int readWaitCnt = readersWaitCount(updated); signalNextWaiter(writeWaitCnt, readWaitCnt, lockIdx); else if (canReadLock(state)) { long updated = updateState(state, 1, -1, 0);
long state = GridUnsafe.getLongVolatile(null, lock); if (!checkTag(state, tag)) { long updated = updateState(state, 0, 0, -1); int writeWaitCnt = writersWaitCount(updated); int readWaitCnt = readersWaitCount(updated); signalNextWaiter(writeWaitCnt, readWaitCnt, lockIdx); else if (canWriteLock(state)) { long updated = updateState(state, -1, 0, -1);
long state = GridUnsafe.getLongVolatile(null, lock); if (!checkTag(state, tag)) return null; if (lockCount(state) == 1) { if (GridUnsafe.compareAndSwapLong(null, lock, state, updateState(state, -2, 0, 0))) return true; else int idx = lockIndex(lock); long state = GridUnsafe.getLongVolatile(null, lock); if (!checkTag(state, tag)) return null; if (lockCount(state) == 1) { if (GridUnsafe.compareAndSwapLong(null, lock, state, updateState(state, -2, 0, 0))) return true; else if (GridUnsafe.compareAndSwapLong(null, lock, state, updateState(state, -1, 0, 1))) break; return waitAcquireWriteLock(lock, idx, tag);
/** * @param lock Lock address. */ public void readUnlock(long lock) { while (true) { long state = GridUnsafe.getLongVolatile(null, lock); if (lockCount(state) <= 0) throw new IllegalMonitorStateException("Attempted to release a read lock while not holding it " + "[lock=" + U.hexLong(lock) + ", state=" + U.hexLong(state) + ']'); long updated = updateState(state, -1, 0, 0); assert updated != 0; if (GridUnsafe.compareAndSwapLong(null, lock, state, updated)) { // Notify monitor if we were CASed to zero and there is a write waiter. if (lockCount(updated) == 0 && writersWaitCount(updated) > 0) { int idx = lockIndex(lock); ReentrantLock lockObj = locks[idx]; lockObj.lock(); try { // Note that we signal all waiters for this stripe. Since not all waiters in this // stripe/index belong to this particular lock, we can't wake up just one of them. writeConditions[idx].signalAll(); } finally { lockObj.unlock(); } } return; } } }
rwLock.init(absPtr + PAGE_LOCK_OFFSET, PageIdUtils.tag(pageId)); boolean locked = rwLock.writeLock(absPtr + PAGE_LOCK_OFFSET, OffheapReadWriteLock.TAG_LOCK_ALWAYS); ", absPtr=" + U.hexLong(absPtr) + ']'; rwLock.init(absPtr + PAGE_LOCK_OFFSET, PageIdUtils.tag(pageId)); rwLock.writeUnlock(lockedPageAbsPtr + PAGE_LOCK_OFFSET, actualPageId == 0 ? OffheapReadWriteLock.TAG_LOCK_ALWAYS : PageIdUtils.tag(actualPageId));
/** * @param state Lock state. * @return {@code True} if no read locks are acquired. */ private boolean canWriteLock(long state) { return lockCount(state) == 0; }
/** * @param tag Tag to initialize RW lock. * @return Relative pointer of the allocated page. * @throws GridOffHeapOutOfMemoryException If failed to allocate. */ private long allocateFreePage(int tag) throws GridOffHeapOutOfMemoryException { long limit = region.address() + region.size(); while (true) { long lastIdx = GridUnsafe.getLongVolatile(null, lastAllocatedIdxPtr); // Check if we have enough space to allocate a page. if (pagesBase + (lastIdx + 1) * sysPageSize > limit) return INVALID_REL_PTR; if (GridUnsafe.compareAndSwapLong(null, lastAllocatedIdxPtr, lastIdx, lastIdx + 1)) { long absPtr = pagesBase + lastIdx * sysPageSize; assert lastIdx <= PageIdUtils.MAX_PAGE_NUM : lastIdx; long pageIdx = fromSegmentIndex(idx, lastIdx); assert pageIdx != INVALID_REL_PTR; writePageId(absPtr, pageIdx); GridUnsafe.putLong(absPtr, PAGE_MARKER); rwLock.init(absPtr + LOCK_OFFSET, tag); allocatedPages.incrementAndGet(); memMetrics.updateTotalAllocatedPages(1L); return pageIdx; } } }
rwLock = new OffheapReadWriteLock(lockConcLvl);
/** * @param absPtr Absolute pointer to the page. * @return {@code True} if read lock acquired for the page. */ boolean isPageReadLocked(long absPtr) { return rwLock.isReadLocked(absPtr + PAGE_LOCK_OFFSET); }
/** * @param absPtr Absolute pointer to the page. * @return {@code True} if write lock acquired for the page. */ boolean isPageWriteLocked(long absPtr) { return rwLock.isWriteLocked(absPtr + PAGE_LOCK_OFFSET); }
/** * @param lock Lock address. */ public void writeUnlock(long lock, int tag) { long updated; assert tag != 0; while (true) { long state = GridUnsafe.getLongVolatile(null, lock); if (lockCount(state) != -1) throw new IllegalMonitorStateException("Attempted to release write lock while not holding it " + "[lock=" + U.hexLong(lock) + ", state=" + U.hexLong(state)); updated = releaseWithTag(state, tag); assert updated != 0; if (GridUnsafe.compareAndSwapLong(null, lock, state, updated)) break; } int writeWaitCnt = writersWaitCount(updated); int readWaitCnt = readersWaitCount(updated); if (writeWaitCnt > 0 || readWaitCnt > 0) { int idx = lockIndex(lock); ReentrantLock lockObj = locks[idx]; lockObj.lock(); try { signalNextWaiter(writeWaitCnt, readWaitCnt, idx); } finally { lockObj.unlock(); } } }
long state = GridUnsafe.getLongVolatile(null, lock); if (!checkTag(state, tag)) { long updated = updateState(state, 0, -1, 0); int writeWaitCnt = writersWaitCount(updated); int readWaitCnt = readersWaitCount(updated); signalNextWaiter(writeWaitCnt, readWaitCnt, lockIdx); else if (canReadLock(state)) { long updated = updateState(state, 1, -1, 0);
long state = GridUnsafe.getLongVolatile(null, lock); if (!checkTag(state, tag)) { long updated = updateState(state, 0, 0, -1); int writeWaitCnt = writersWaitCount(updated); int readWaitCnt = readersWaitCount(updated); signalNextWaiter(writeWaitCnt, readWaitCnt, lockIdx); else if (canWriteLock(state)) { long updated = updateState(state, -1, 0, -1);
long state = GridUnsafe.getLongVolatile(null, lock); if (!checkTag(state, tag)) return null; if (lockCount(state) == 1) { if (GridUnsafe.compareAndSwapLong(null, lock, state, updateState(state, -2, 0, 0))) return true; else int idx = lockIndex(lock); long state = GridUnsafe.getLongVolatile(null, lock); if (!checkTag(state, tag)) return null; if (lockCount(state) == 1) { if (GridUnsafe.compareAndSwapLong(null, lock, state, updateState(state, -2, 0, 0))) return true; else if (GridUnsafe.compareAndSwapLong(null, lock, state, updateState(state, -1, 0, 1))) break; return waitAcquireWriteLock(lock, idx, tag);
/** * @param lock Lock address. */ public void readUnlock(long lock) { while (true) { long state = GridUnsafe.getLongVolatile(null, lock); if (lockCount(state) <= 0) throw new IllegalMonitorStateException("Attempted to release a read lock while not holding it " + "[lock=" + U.hexLong(lock) + ", state=" + U.hexLong(state) + ']'); long updated = updateState(state, -1, 0, 0); assert updated != 0; if (GridUnsafe.compareAndSwapLong(null, lock, state, updated)) { // Notify monitor if we were CASed to zero and there is a write waiter. if (lockCount(updated) == 0 && writersWaitCount(updated) > 0) { int idx = lockIndex(lock); ReentrantLock lockObj = locks[idx]; lockObj.lock(); try { // Note that we signal all waiters for this stripe. Since not all waiters in this // stripe/index belong to this particular lock, we can't wake up just one of them. writeConditions[idx].signalAll(); } finally { lockObj.unlock(); } } return; } } }