/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#pragma once

#include <stdbool.h>

#include "block_mac.h"
#include "block_set.h"
#include "block_tree.h"
#include "fs.h"

/**
 * struct transaction - Transaction state
 * @node:                   List node used to link transaction in fs.
 * @fs:                     Pointer to file system state.
 * @open_files:             List of open files.
 * @failed:                 %true if transaction ran out of disk space, or
 *                          collided with another transaction, %false if no
 *                          error has occured since transaction_activate.
 * @invalid_block_found:    %true if a block MAC mismatch or missing block was
 *                          encountered while trying to operate on this
 *                          transaction.
 * @complete:               Transaction has been written to disk.
 * @rebuild_free_set:       %true if this transaction requires the free set to
 *                          be reuilt by a full file-system scan.
 * @repaired:               Transaction includes a repair that should increment
 *                          the file system repair count when committed.
 * @min_free_block:         Used when completing a transaction to track how much
 *                          of the free set has been updated.
 * @last_free_block:        Similar to @last_tmp_free_block, used when
 *                          completing a transaction.
 * @last_tmp_free_block:    Used by allocator to prevent ping-pong between
 *                          allocating and freeing the same block when
 *                          re-entering the same set.
 * @new_free_set:           New free set used while completing a transaction.
 * @tmp_allocated:          Blocks used while transaction is pending.
 * @allocated:              Blocks allocated by transaction.
 * @freed:                  Blocks freed by transaction.
 * @files_added:            Files added by transaction.
 * @files_updated:          Files modified by transaction.
 * @files_removed:          Files removed by transaction.
 */
struct transaction {
    struct list_node node;
    struct fs* fs;
    struct list_node open_files;
    bool failed;
    bool invalid_block_found;
    bool complete;
    bool rebuild_free_set;
    bool repaired;
    data_block_t min_free_block;
    data_block_t last_free_block;
    data_block_t last_tmp_free_block;
    struct block_set* new_free_set;
    struct block_set tmp_allocated;
    struct block_set allocated;
    struct block_set freed;

    struct block_tree files_added;
    struct block_tree files_updated;
    struct block_tree files_removed;
};

void transaction_init(struct transaction* tr, struct fs* fs, bool activate);
void transaction_free(struct transaction* tr);
void transaction_activate(struct transaction* tr);
void transaction_fail(struct transaction* tr);
void transaction_complete_etc(struct transaction* tr, bool update_checkpoint);
void transaction_initial_super_block_complete(struct transaction* tr);

static inline bool transaction_is_active(struct transaction* tr) {
    return list_in_list(&tr->allocated.node);
};

bool transaction_block_need_copy(struct transaction* tr, data_block_t block);
