private void releaseDirtyBuffer(DataBuffer buf) throws IOException, AssertionError {
		synchronized (snapshotLock) {
			synchronized (this) {

				int id = buf.getId();
				BufferNode node = getCachedBufferNode(id);

				if (node != null && !node.locked) {
					throw new AssertException();
				}

				++modCount;
				modifiedSinceSnapshot = true;

				// Establish current checkpoint if necessary
				if (currentCheckpointHead == null) {
					startCheckpoint();
				}

				// Create new buffer node if necessary
				if (node == null) {
					node = createNewBufferNode(id, currentCheckpointHead, null);
				}

				// Handle update of existing buffer node
				else {

					// Buffer should not be in memory cache
					if (node.buffer != null) {
						throw new AssertionError("Invalid buffer state");
					}

					// Create new buffer version if needed
					if (currentCheckpoint != node.checkpoint) {
						BufferNode head = node.prevVersion;
						if (head.id != HEAD) {
							throw new AssertException("Head expected");
						}
						node.locked = false; // unlock old node
						node = createNewBufferNode(id, currentCheckpointHead, head);
					}
				}
				buf.setDirty(false);
				node.isDirty = true;
				node.modified = true;
				node.empty = buf.isEmpty();

				// Add deleted buffer ID to free stack - node remains empty unless re-created
				if (node.empty) {
					indexProvider.freeIndex(id);
				}

				// reintroduce unlocked buffer node into cache
				node.locked = false;
				--lockCount;
				returnToCache(node, buf);
			}
		}
	}
Handle exception which indicates a potential corruption of the BufferMgr state
@param exception exception
@param errorText associated error text
@throws IOException exception thrown if instance of IOException
Ghidra/Framework/DB/src/main/java/db/buffers/BufferMgr.java