aboutsummaryrefslogtreecommitdiffstats
path: root/storage/src/tests/persistence/common/persistenceproviderwrapper.h
blob: ec7ca70d7c70854689518244b2611b4cfad7dec6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
/**
 * \class storage::PersistenceProviderWrapper
 *
 * \brief Test utility class for intercepting all operations upon a
 * persistence layer, injecting errors and performing logging.
 *
 * The PersistenceProviderWrapper class implements the basic SPI by
 * logging all operations and then delegating handling the operation
 * to the SPI instance given during construction. If an error result
 * is specified and the operation invoked is tagged that it should be
 * failed via setFailureMask(), the operation on the wrapped SPI will
 * not be executed, but the given error result will be immediately
 * returned instead (wrapped in the proper return type).
 */
#pragma once


#include <vespa/persistence/spi/abstractpersistenceprovider.h>
#include <mutex>

namespace storage {

class PersistenceProviderWrapper : public spi::PersistenceProvider
{
public:
    enum OPERATION_FAILURE_FLAGS
    {
        FAIL_LIST_BUCKETS     = 1 << 0,
        FAIL_BUCKET_INFO      = 1 << 1,
        FAIL_GET              = 1 << 2,
        FAIL_PUT              = 1 << 3,
        FAIL_REMOVE           = 1 << 4,
        FAIL_REMOVE_IF_FOUND  = 1 << 5,
        FAIL_REPLACE_WITH_REMOVE = 1 << 6,
        FAIL_UPDATE           = 1 << 7,
        FAIL_REVERT           = 1 << 8,
        FAIL_CREATE_ITERATOR  = 1 << 10,
        FAIL_ITERATE          = 1 << 11,
        FAIL_DESTROY_ITERATOR = 1 << 12,
        FAIL_DELETE_BUCKET    = 1 << 13,
        FAIL_SPLIT            = 1 << 14,
        FAIL_JOIN             = 1 << 15,
        FAIL_CREATE_BUCKET    = 1 << 16,
        FAIL_BUCKET_PERSISTENCE = FAIL_PUT|FAIL_REMOVE|FAIL_UPDATE|FAIL_REVERT,
        FAIL_ALL_OPERATIONS   = 0xffff,
        // TODO: add more as needed
    };
private:
    spi::PersistenceProvider&        _spi;
    spi::Result                      _result;
    mutable std::mutex               _lock;
    mutable std::vector<std::string> _log;
    uint32_t                         _failureMask;
    using Guard = std::lock_guard<std::mutex>;
public:
    PersistenceProviderWrapper(spi::PersistenceProvider& spi);
    ~PersistenceProviderWrapper() override;

    /**
     * Explicitly set result to anything != NONE to have all operations
     * return the given error without the wrapped SPI ever being invoked.
     */
    void setResult(const spi::Result& result) {
        Guard guard(_lock);
        _result = result;
    }
    spi::Result getResult() const {
        Guard guard(_lock);
        return _result;
    }
    /**
     * Set a mask for operations to fail with _result
     */
    void setFailureMask(uint32_t mask) {
        Guard guard(_lock);
        _failureMask = mask;
    }
    uint32_t getFailureMask() const {
        Guard guard(_lock);
        return _failureMask;
    }

    /**
     * Get a string representation of all the operations performed on the
     * SPI with a newline separating each operation.
     */
    std::string toString() const;
    /**
     * Clear log of all operations performed.
     */
    void clearOperationLog() {
        Guard guard(_lock);
        _log.clear();
    }

    spi::Result initialize() override;
    spi::BucketIdListResult getModifiedBuckets(BucketSpace bucketSpace) const override;

    spi::Result setClusterState(BucketSpace bucketSpace, const spi::ClusterState &state) override;

    void setActiveStateAsync(const spi::Bucket &bucket, spi::BucketInfo::ActiveState state,
                             spi::OperationComplete::UP up) override;

    void createBucketAsync(const spi::Bucket&, spi::OperationComplete::UP) noexcept override;
    spi::BucketIdListResult listBuckets(BucketSpace bucketSpace) const override;
    spi::BucketInfoResult getBucketInfo(const spi::Bucket&) const override;
    void putAsync(const spi::Bucket&, spi::Timestamp, spi::DocumentSP, spi::OperationComplete::UP) override;
    void removeAsync(const spi::Bucket&, std::vector<spi::IdAndTimestamp> ids, spi::OperationComplete::UP) override;
    void removeIfFoundAsync(const spi::Bucket&, spi::Timestamp, const spi::DocumentId&, spi::OperationComplete::UP) override;
    void updateAsync(const spi::Bucket&, spi::Timestamp, spi::DocumentUpdateSP, spi::OperationComplete::UP) override;
    spi::GetResult get(const spi::Bucket&, const document::FieldSet&, const spi::DocumentId&, spi::Context&) const override;

    spi::CreateIteratorResult
    createIterator(const spi::Bucket &bucket, FieldSetSP, const spi::Selection &, spi::IncludedVersions versions,
                   spi::Context &context) override;

    spi::IterateResult iterate(spi::IteratorId, uint64_t maxByteSize) const override;
    spi::Result destroyIterator(spi::IteratorId) override;
    void deleteBucketAsync(const spi::Bucket&, spi::OperationComplete::UP) noexcept override;
    spi::Result split(const spi::Bucket& source, const spi::Bucket& target1, const spi::Bucket& target2) override;
    spi::Result join(const spi::Bucket& source1, const spi::Bucket& source2, const spi::Bucket& target) override;
    spi::Result removeEntry(const spi::Bucket&, spi::Timestamp) override;
    std::unique_ptr<vespalib::IDestructorCallback> register_resource_usage_listener(spi::IResourceUsageListener& listener) override;
    std::unique_ptr<vespalib::IDestructorCallback> register_executor(std::shared_ptr<spi::BucketExecutor>) override;
};

} // storage