⛏️ index : haiku.git

/*
 * Copyright 2017, ChαΊΏ VΕ© Gia Hy, cvghy116@gmail.com.
 * Copyright 2001-2012, Axel DΓΆrfler, axeld@pinc-software.de.
 * This file may be used under the terms of the MIT License.
 */


#include "Journal.h"


//#define TRACE_BTRFS
#ifdef TRACE_BTRFS
#	define TRACE(x...) dprintf("\33[34mbtrfs:\33[0m " x)
#else
#	define TRACE(x...) ;
#endif
#	define ERROR(x...) dprintf("\33[34mbtrfs:\33[0m " x)


Journal::Journal(Volume* volume)
	:
	fVolume(volume),
	fOwner(NULL),
	fTransactionID(0),
	fCurrentGeneration(volume->SuperBlock().Generation())
{
	recursive_lock_init(&fLock, "btrfs journal");
}


Journal::~Journal()
{
	recursive_lock_destroy(&fLock);
}


/*static*/ void
Journal::_TransactionWritten(int32 transactionID, int32 event, void* _journal)
{
	TRACE("TRANSACTION WRITTEN id %i\n", transactionID);
}


status_t
Journal::_TransactionDone(bool success)
{
	if (!success) {
		cache_abort_transaction(fVolume->BlockCache(), fTransactionID);
		return B_OK;
	}
	cache_end_transaction(fVolume->BlockCache(), fTransactionID,
		&_TransactionWritten, this);
	// cache_sync_transaction(fVolume->BlockCache(), fTransactionID);
	return B_OK;
}


status_t
Journal::Lock(Transaction* owner)
{
	status_t status = recursive_lock_lock(&fLock);
	if (status != B_OK)
		return status;
	if (recursive_lock_get_recursion(&fLock) > 1) {
		// we'll just use the current transaction again
		return B_OK;
	}


	if (owner != NULL)
		owner->SetParent(fOwner);

	fOwner = owner;

	if (fOwner != NULL) {
		fTransactionID = cache_start_transaction(fVolume->BlockCache());

		if (fTransactionID < B_OK) {
			recursive_lock_unlock(&fLock);
			return fTransactionID;
		}
		fCurrentGeneration++;
		TRACE("Journal::Lock() start transaction id: %i\n", fTransactionID);
	}

	return B_OK;
}


status_t
Journal::UnLock(Transaction* owner, bool success)
{
	if (recursive_lock_get_recursion(&fLock) == 1) {
		if (owner != NULL) {
			status_t status = _TransactionDone(success);
			if (status != B_OK)
				return status;
			fOwner = owner->Parent();
		} else {
			fOwner = NULL;
		}
	}
	recursive_lock_unlock(&fLock);
	return B_OK;
}


// Transaction


Transaction::Transaction(Volume* volume)
	:
	fJournal(NULL),
	fParent(NULL)
{
	Start(volume);
}


Transaction::Transaction()
	:
	fJournal(NULL),
	fParent(NULL)
{
}


Transaction::~Transaction()
{
	if (fJournal != NULL) {
		fJournal->UnLock(this, false);
	}
}


bool
Transaction::HasBlock(fsblock_t blockNumber) const
{
	return cache_has_block_in_transaction(fJournal->GetVolume()->BlockCache(),
		ID(), blockNumber);
}


status_t
Transaction::Start(Volume* volume)
{
	if (fJournal != NULL)
		return B_OK;

	fJournal = volume->GetJournal();
	if (fJournal != NULL && fJournal->Lock(this) == B_OK) {
		return B_OK;
	}
	fJournal = NULL;
	return B_ERROR;
}


status_t
Transaction::Done()
{
	status_t status = B_OK;
	if (fJournal != NULL) {
		status = fJournal->UnLock(this, true);
		if (status == B_OK)
			fJournal = NULL;
	}
	return status;
}