private void doSave(BufferFile outFile, TaskMonitor monitor)
			throws IOException, CancelledException {
		int indexCnt = indexProvider.getIndexCount();
		int preSaveCnt = outFile.getIndexCount();

		if (monitor == null) {
			monitor = TaskMonitor.DUMMY;
		}
		monitor.initialize(indexCnt);
		monitor.setMessage("Saving file...");

		// Determine number of buffers to be written (required for remote stream transfer)
		// Count non-empty buffers which have been created or modified
		// Empty buffers will be flushed when outFile is closed
		int bufCount = 0;
		for (int id = 0; id < indexCnt; id++) {
			monitor.checkCancelled();
			monitor.setProgress(id);
			BufferNode node = getCachedBufferNode(id);
			if (node != null) {
				// check nod which resides in cache
				if (!node.empty && (id >= preSaveCnt || node.checkpoint != 0 || node.modified)) {
					++bufCount;
				}
			}
			else if (id >= preSaveCnt && !indexProvider.isFree(id)) {
				// node not in cache, must be copied if not empty
				// will cause buffer to be cached for use during output below
				DataBuffer buf = getBuffer(id); // will add to cache for use during output below
				if (buf != null) {
					++bufCount;
					releaseBuffer(buf);
				}
			}
		}

		monitor.initialize(indexCnt);

		// write/update all non-empty buffers
		try (OutputBlockStream out = LocalBufferFile.getOutputBlockStream(outFile, bufCount)) {
			for (int id = 0; id < indexCnt; id++) {
				monitor.checkCancelled();
				monitor.setProgress(id);

				// get buffer node from cache
				// if not contained within cache it does not need to be stored
				BufferNode node = getCachedBufferNode(id);
				if (node != null) {
					if (!node.empty &&
						(id >= preSaveCnt || node.checkpoint != 0 || node.modified)) {
						loadCachedNode(node);
						BufferFileBlock block =
							LocalBufferFile.getBufferFileBlock(node.buffer, bufferSize);
						out.writeBlock(block);
					}
				}
			}
		}

		// Set free ID list for output file
		// It is important that this is done after the streaming is complete
		// so that the changeMap and free buffers are updated properly.
		outFile.setFreeIndexes(indexProvider.getFreeIndexes());

		// Copy file parameters from cache file
		String[] parmNames = cacheFile.getParameterNames();
		for (String name : parmNames) {
			outFile.setParameter(name, cacheFile.getParameter(name));
		}
	}
Write all changes to the specified outFile
@param outFile output buffer file
@param monitor task monitor
@throws IOException if IO error occurs
@throws CancelledException thrown if task cancelled
Ghidra/Framework/DB/src/main/java/db/buffers/BufferMgr.java