summaryrefslogtreecommitdiffstats
path: root/storage/src/tests/common/teststorageapp.h
blob: e567206c37185f7cf5778d8d4ac32facc289e063 (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
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
/**
 * \class storage::TestServiceLayerApp
 * \ingroup common
 *
 * \brief Helper class for tests involving service layer.
 *
 * Some components need some dependencies injected in order to work correctly.
 * This test class simplifies the process of creating these dependencies.
 *
 * Note that the interface between this class and the test class should be as
 * clean as possible, such that we can change as little as possible when
 * refactoring later. Also, advanced functionality should not be generated in
 * here, but rather fixed by tests themselves. Functionality here should be
 * needed by many tests, and we should avoid instantiating complex instances
 * here that several tests
 */
#pragma once

#include "testnodestateupdater.h"
#include <vespa/storage/bucketdb/storbucketdb.h>
#include <vespa/storage/common/doneinitializehandler.h>
#include <vespa/storage/common/nodestateupdater.h>
#include <vespa/storage/storageserver/framework.h>
#include <vespa/storage/frameworkimpl/component/distributorcomponentregisterimpl.h>
#include <vespa/storage/frameworkimpl/component/servicelayercomponentregisterimpl.h>
#include <vespa/storageframework/defaultimplementation/clock/realclock.h>
#include <vespa/storageframework/defaultimplementation/component/testcomponentregister.h>
#include <vespa/persistence/spi/persistenceprovider.h>
#include <vespa/document/bucket/fixed_bucket_spaces.h>
#include <vespa/document/base/testdocman.h>
#include <atomic>

namespace storage {

class StorageBucketDBInitializer;

DEFINE_PRIMITIVE_WRAPPER(uint16_t, DiskCount);
DEFINE_PRIMITIVE_WRAPPER(uint16_t, NodeIndex);
DEFINE_PRIMITIVE_WRAPPER(uint16_t, NodeCount);
DEFINE_PRIMITIVE_WRAPPER(uint16_t, Redundancy);

class TestStorageApp
        : public framework::defaultimplementation::TestComponentRegister,
          private DoneInitializeHandler
{
    StorageComponentRegisterImpl& _compReg;

protected:
    document::TestDocMan _docMan;
    TestNodeStateUpdater _nodeStateUpdater;
    vespalib::string _configId;
    std::atomic<bool> _initialized;

public:
    /**
     * Set up a storage application. If node index is not set, it will be
     * fetched from config if config id is given, otherwise it is set to 0.
     * If configId is given, some critical values are taken from config.
     * (node count, redundancy, node index etc). If configId set not set these
     * will just have some default values. A non-default node index will
     * override config, but be careful with this, as components may fetch index
     * from config themselves.
     */
    TestStorageApp(StorageComponentRegisterImpl::UP compReg,
                   const lib::NodeType&, NodeIndex = NodeIndex(0xffff),
                   vespalib::stringref configId = "");
    ~TestStorageApp();

    // Set functions, to be able to modify content while running.
    void setDistribution(Redundancy, NodeCount);
    void setTypeRepo(std::shared_ptr<const document::DocumentTypeRepo> repo);
    void setClusterState(const lib::ClusterState&);

    // Utility functions for getting a hold of currently used bits. Practical
    // to avoid adding extra components in the tests.
    StorageComponentRegisterImpl& getComponentRegister() { return _compReg; }
    document::TestDocMan& getTestDocMan() { return _docMan; }
    std::shared_ptr<const document::DocumentTypeRepo> getTypeRepo()
        { return _compReg.getTypeRepo(); }
    const document::BucketIdFactory& getBucketIdFactory()
        { return _compReg.getBucketIdFactory(); }
    TestNodeStateUpdater& getStateUpdater() { return _nodeStateUpdater; }
    documentapi::LoadTypeSet::SP getLoadTypes()
        { return _compReg.getLoadTypes(); }
    lib::Distribution::SP getDistribution()
        { return _compReg.getDistribution(); }
    TestNodeStateUpdater& getNodeStateUpdater() { return _nodeStateUpdater; }
    uint16_t getIndex() const { return _compReg.getIndex(); }

    // The storage app also implements the done initializer interface, so it can
    // be sent to components needing this.
    DoneInitializeHandler& getDoneInitializeHandler() { return *this; }
    void notifyDoneInitializing() override { _initialized = true; }
    bool isInitialized() const { return _initialized; }
    void waitUntilInitialized(
            StorageBucketDBInitializer* initializer = 0,
            framework::SecondTime timeout = framework::SecondTime(30));

private:
    // Storage server interface implementation (until we can remove it)
    virtual api::Timestamp getUniqueTimestamp() { assert(0); throw; }
    virtual StorBucketDatabase& getStorageBucketDatabase() { assert(0); throw; }
    virtual BucketDatabase& getBucketDatabase() { assert(0); throw; }
    virtual uint16_t getDiskCount() const { assert(0); throw; }
};

class TestServiceLayerApp : public TestStorageApp
{
    ServiceLayerComponentRegisterImpl& _compReg;
    spi::PersistenceProvider::UP _persistenceProvider;
    spi::PartitionStateList _partitions;

public:
    TestServiceLayerApp(vespalib::stringref configId = "");
    TestServiceLayerApp(DiskCount diskCount, NodeIndex = NodeIndex(0xffff),
                        vespalib::stringref configId = "");
    ~TestServiceLayerApp();

    void setupDummyPersistence();
    void setPersistenceProvider(spi::PersistenceProvider::UP);

    ServiceLayerComponentRegisterImpl& getComponentRegister() { return _compReg; }

    spi::PersistenceProvider& getPersistenceProvider();
    spi::PartitionStateList& getPartitions();
    uint16_t getPartition(const document::BucketId&);

    StorBucketDatabase& getStorageBucketDatabase() override {
        return _compReg.getBucketSpaceRepo().get(document::FixedBucketSpaces::default_space()).bucketDatabase();
    }

private:
    // For storage server interface implementation we'll get rid of soon.
    // Use getPartitions().size() instead.
    uint16_t getDiskCount() const override { return _compReg.getDiskCount(); }
};

class TestDistributorApp : public TestStorageApp,
                           public UniqueTimeCalculator
{
    DistributorComponentRegisterImpl& _compReg;
    vespalib::Lock _accessLock;
    uint64_t _lastUniqueTimestampRequested;
    uint32_t _uniqueTimestampCounter;

    void configure(vespalib::stringref configId);

public:
    TestDistributorApp(vespalib::stringref configId = "");
    TestDistributorApp(NodeIndex index, vespalib::stringref configId = "");
    ~TestDistributorApp();

    DistributorComponentRegisterImpl& getComponentRegister() {
        return _compReg;
    }

    api::Timestamp getUniqueTimestamp() override;
};

} // storageo