class GCSRepository extends BlobStoreRepository {
    // package private for testing
    static final ByteSizeValue MIN_CHUNK_SIZE = new ByteSizeValue(1, ByteSizeUnit.BYTES);

    /**
     * Maximum allowed object size in GCS.
     *
     * @see <a href="https://cloud.google.com/storage/quotas#objects">GCS documentation</a> for details.
     */
    static final ByteSizeValue MAX_CHUNK_SIZE = new ByteSizeValue(5, ByteSizeUnit.TB);

    static final Setting<String> BUCKET_SETTING = simpleString("bucket", Property.NodeScope, Property.Dynamic);

    static final Setting<String> BASE_PATH_SETTING = simpleString("base_path", Property.NodeScope, Property.Dynamic);

    static final Setting<ByteSizeValue> CHUNK_SIZE_SETTING = byteSizeSetting(
        "chunk_size",
        MAX_CHUNK_SIZE,
        MIN_CHUNK_SIZE,
        MAX_CHUNK_SIZE,
        Property.NodeScope,
        Property.Dynamic
    );

    private final GCSService service;
    private final ByteSizeValue chunkSize;
    private final String bucket;


    public GCSRepository(
        final RepositoryMetadata metadata,
        final NamedXContentRegistry namedXContentRegistry,
        final ClusterService clusterService,
        final GCSService service,
        final RecoverySettings recoverySettings) {
        super(metadata, namedXContentRegistry, clusterService, recoverySettings, buildBasePath(metadata));
        this.service = service;
        this.chunkSize = CHUNK_SIZE_SETTING.get(metadata.settings());
        this.bucket = BUCKET_SETTING.get(metadata.settings());
    }

    @Override
    protected GCSBlobStore createBlobStore() {
        return new GCSBlobStore(bucket, service, metadata, bufferSize);
    }

    private static BlobPath buildBasePath(RepositoryMetadata metadata) {<FILL_FUNCTION_BODY>}

    @Override
    protected ByteSizeValue chunkSize() {
        return chunkSize;
    }
}

        String basePath = BASE_PATH_SETTING.get(metadata.settings());
        if (Strings.hasLength(basePath)) {
            BlobPath path = new BlobPath();
            for (String elem : basePath.split("/")) {
                path = path.add(elem);
            }
            return path;
        } else {
            return BlobPath.cleanPath();
        }
    
<methods>public org.elasticsearch.common.blobstore.BlobPath basePath() ,public org.elasticsearch.common.blobstore.BlobStore blobStore() ,public void deleteSnapshots(Collection<org.elasticsearch.snapshots.SnapshotId>, long, org.elasticsearch.Version, ActionListener<org.elasticsearch.repositories.RepositoryData>) ,public void endVerification(java.lang.String) ,public void executeConsistentStateUpdate(Function<org.elasticsearch.repositories.RepositoryData,org.elasticsearch.cluster.ClusterStateUpdateTask>, java.lang.String, Consumer<java.lang.Exception>) ,public void finalizeSnapshot(org.elasticsearch.repositories.ShardGenerations, long, org.elasticsearch.cluster.metadata.Metadata, org.elasticsearch.snapshots.SnapshotInfo, org.elasticsearch.Version, UnaryOperator<org.elasticsearch.cluster.ClusterState>, ActionListener<org.elasticsearch.repositories.RepositoryData>) ,public org.elasticsearch.cluster.metadata.RepositoryMetadata getMetadata() ,public CompletableFuture<org.elasticsearch.repositories.RepositoryData> getRepositoryData() ,public CompletableFuture<org.elasticsearch.index.snapshots.IndexShardSnapshotStatus> getShardSnapshotStatus(org.elasticsearch.snapshots.SnapshotId, org.elasticsearch.repositories.IndexId, org.elasticsearch.index.shard.ShardId) ,public CompletableFuture<org.elasticsearch.cluster.metadata.Metadata> getSnapshotGlobalMetadata(org.elasticsearch.snapshots.SnapshotId) ,public CompletableFuture<org.elasticsearch.cluster.metadata.IndexMetadata> getSnapshotIndexMetadata(org.elasticsearch.repositories.RepositoryData, org.elasticsearch.snapshots.SnapshotId, org.elasticsearch.repositories.IndexId) ,public CompletableFuture<Collection<org.elasticsearch.cluster.metadata.IndexMetadata>> getSnapshotIndexMetadata(org.elasticsearch.repositories.RepositoryData, org.elasticsearch.snapshots.SnapshotId, Collection<org.elasticsearch.repositories.IndexId>) ,public CompletableFuture<org.elasticsearch.snapshots.SnapshotInfo> getSnapshotInfo(org.elasticsearch.snapshots.SnapshotId) ,public boolean isReadOnly() ,public org.elasticsearch.index.snapshots.blobstore.BlobStoreIndexShardSnapshot loadShardSnapshot(org.elasticsearch.common.blobstore.BlobContainer, org.elasticsearch.snapshots.SnapshotId) ,public java.io.InputStream maybeRateLimitRestores(java.io.InputStream) ,public java.io.InputStream maybeRateLimitSnapshots(java.io.InputStream) ,public void restoreShard(org.elasticsearch.index.store.Store, org.elasticsearch.snapshots.SnapshotId, org.elasticsearch.repositories.IndexId, org.elasticsearch.index.shard.ShardId, org.elasticsearch.indices.recovery.RecoveryState, ActionListener<java.lang.Void>) ,public org.elasticsearch.common.blobstore.BlobContainer shardContainer(org.elasticsearch.repositories.IndexId, int) ,public void snapshotShard(org.elasticsearch.index.store.Store, org.elasticsearch.snapshots.SnapshotId, org.elasticsearch.repositories.IndexId, IndexCommit, java.lang.String, org.elasticsearch.index.snapshots.IndexShardSnapshotStatus, org.elasticsearch.Version, ActionListener<java.lang.String>) ,public java.lang.String startVerification() ,public static java.lang.String testBlobPrefix(java.lang.String) ,public org.elasticsearch.threadpool.ThreadPool threadPool() ,public java.lang.String toString() ,public void updateState(org.elasticsearch.cluster.ClusterState) ,public void verify(java.lang.String, org.elasticsearch.cluster.node.DiscoveryNode) <variables>public static final Setting<java.lang.Boolean> COMPRESS_SETTING,public static final ChecksumBlobStoreFormat<org.elasticsearch.cluster.metadata.Metadata> GLOBAL_METADATA_FORMAT,public static final java.lang.String INDEX_FILE_PREFIX,public static final java.lang.String INDEX_LATEST_BLOB,public static final ChecksumBlobStoreFormat<org.elasticsearch.cluster.metadata.IndexMetadata> INDEX_METADATA_FORMAT,public static final ChecksumBlobStoreFormat<org.elasticsearch.index.snapshots.blobstore.BlobStoreIndexShardSnapshots> INDEX_SHARD_SNAPSHOTS_FORMAT,public static final ChecksumBlobStoreFormat<org.elasticsearch.index.snapshots.blobstore.BlobStoreIndexShardSnapshot> INDEX_SHARD_SNAPSHOT_FORMAT,private static final Setting<org.elasticsearch.common.unit.ByteSizeValue> IO_BUFFER_SIZE_SETTING,private static final Logger LOGGER,public static final java.lang.String METADATA_NAME_FORMAT,public static final java.lang.String METADATA_PREFIX,private static final java.lang.String SNAPSHOT_CODEC,public static final ChecksumBlobStoreFormat<org.elasticsearch.snapshots.SnapshotInfo> SNAPSHOT_FORMAT,private static final java.lang.String SNAPSHOT_INDEX_NAME_FORMAT,private static final java.lang.String SNAPSHOT_INDEX_PREFIX,public static final java.lang.String SNAPSHOT_NAME_FORMAT,public static final java.lang.String SNAPSHOT_PREFIX,private static final java.lang.String TESTS_FILE,private static final java.lang.String UPLOADED_DATA_BLOB_PREFIX,private static final java.lang.String VIRTUAL_DATA_BLOB_PREFIX,private final non-sealed org.elasticsearch.common.blobstore.BlobPath basePath,private volatile boolean bestEffortConsistency,private final SetOnce<org.elasticsearch.common.blobstore.BlobContainer> blobContainer,private final SetOnce<org.elasticsearch.common.blobstore.BlobStore> blobStore,protected final non-sealed int bufferSize,private final non-sealed org.elasticsearch.cluster.service.ClusterService clusterService,private final non-sealed boolean compress,private final java.util.concurrent.atomic.AtomicLong latestKnownRepoGen,private final java.lang.Object lock,protected volatile org.elasticsearch.cluster.metadata.RepositoryMetadata metadata,private final non-sealed org.elasticsearch.common.xcontent.NamedXContentRegistry namedXContentRegistry,private final non-sealed boolean readOnly,private final non-sealed org.elasticsearch.indices.recovery.RecoverySettings recoverySettings,private final non-sealed RateLimiter restoreRateLimiter,private final org.elasticsearch.common.metrics.CounterMetric restoreRateLimitingTimeInNanos,private final non-sealed RateLimiter snapshotRateLimiter,private final org.elasticsearch.common.metrics.CounterMetric snapshotRateLimitingTimeInNanos,protected final non-sealed org.elasticsearch.threadpool.ThreadPool threadPool,private boolean uncleanStart