All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.arcadedb.server.ha.message.DatabaseAlignRequest Maven / Gradle / Ivy

The newest version!
/*
 * Copyright © 2021-present Arcade Data Ltd ([email protected])
 *
 * 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.
 *
 * SPDX-FileCopyrightText: 2021-present Arcade Data Ltd ([email protected])
 * SPDX-License-Identifier: Apache-2.0
 */
package com.arcadedb.server.ha.message;

import com.arcadedb.database.Binary;
import com.arcadedb.database.DatabaseInternal;
import com.arcadedb.engine.ComponentFile;
import com.arcadedb.log.LogManager;
import com.arcadedb.server.ArcadeDBServer;
import com.arcadedb.server.ha.HAServer;

import java.util.*;
import java.util.logging.*;

public class DatabaseAlignRequest extends HAAbstractCommand {
  private String             databaseName;
  private String             schemaJson;
  private Map fileChecksums;
  private Map fileSizes;

  public DatabaseAlignRequest() {
  }

  public DatabaseAlignRequest(final String databaseName, final String schemaJson, final Map fileChecksums,
      final Map fileSizes) {
    this.databaseName = databaseName;
    this.schemaJson = schemaJson;
    this.fileChecksums = fileChecksums;
    this.fileSizes = fileSizes;
  }

  @Override
  public void toStream(final Binary stream) {
    stream.putString(databaseName);
    stream.putString(schemaJson);

    stream.putUnsignedNumber(fileChecksums.size());
    for (final Map.Entry file : fileChecksums.entrySet()) {
      stream.putInt(file.getKey());
      stream.putLong(file.getValue());
    }

    stream.putUnsignedNumber(fileSizes.size());
    for (final Map.Entry file : fileSizes.entrySet()) {
      stream.putInt(file.getKey());
      stream.putLong(file.getValue());
    }
  }

  @Override
  public void fromStream(final ArcadeDBServer server, final Binary stream) {
    databaseName = stream.getString();
    schemaJson = stream.getString();

    fileChecksums = new HashMap<>();
    int fileCount = (int) stream.getUnsignedNumber();
    for (int i = 0; i < fileCount; ++i) {
      final int fileId = stream.getInt();
      fileChecksums.put(fileId, stream.getLong());
    }

    fileSizes = new HashMap<>();
    fileCount = (int) stream.getUnsignedNumber();
    for (int i = 0; i < fileCount; ++i) {
      final int fileId = stream.getInt();
      fileSizes.put(fileId, stream.getLong());
    }
  }

  @Override
  public HACommand execute(final HAServer server, final String remoteServerName, final long messageNumber) {
    final DatabaseInternal database = server.getServer().getDatabase(databaseName);

    final List pagesToAlign = new ArrayList<>();

    // ACQUIRE A READ LOCK. TRANSACTION CAN STILL RUN, BUT CREATION OF NEW FILES (BUCKETS, TYPES, INDEXES) WILL BE PUT ON PAUSE UNTIL THIS LOCK IS RELEASED
    database.executeInReadLock(() -> {
      // AVOID FLUSHING OF DATA PAGES TO DISK
      database.getPageManager().suspendFlushAndExecute(database, () -> {

        for (final Map.Entry entry : fileSizes.entrySet()) {
          final Integer fileId = entry.getKey();
          final ComponentFile file = database.getFileManager().getFile(fileId);

          final Long leaderFileSize = entry.getValue();
          if (file.getSize() < leaderFileSize) {
            // ALIGN THE ENTIRE FILE
            pagesToAlign.add(new int[] { fileId, 0, -1 });

            LogManager.instance()
                .log(this, Level.INFO, "File %d size %s <> leader %s: requesting the entire file from the leader", null,//
                    fileId, file.getSize(), leaderFileSize);
            continue;
          }

          final Long leaderFileChecksum = fileChecksums.get(fileId);
          if (leaderFileChecksum == null)
            continue;

          final long localFileChecksum = file.calculateChecksum();
          if (localFileChecksum != leaderFileChecksum) {
            // ALIGN THE ENTIRE FILE
            pagesToAlign.add(new int[] { fileId, 0, -1 });

            LogManager.instance()
                .log(this, Level.INFO, "File %d checksum %s <> leader %s: requesting the entire file from the leader", null,//
                    fileId, localFileChecksum, leaderFileChecksum);
            continue;
          }
        }

        // ASK FOR FILES
        final Binary buffer = new Binary();
        for (final int[] entry : pagesToAlign) {
          final FileContentRequest fileAlign = new FileContentRequest(databaseName, entry[0], entry[1], entry[2]);
          server.getLeader().sendCommandToLeader(buffer, fileAlign, -1);
        }
      });
      return null;
    });

    return new DatabaseAlignResponse(pagesToAlign);
  }

  @Override
  public String toString() {
    return "DatabaseAlignRequest{" + databaseName + " fileChecksum=" + fileChecksums + " fileSizes=" + fileSizes + "}";
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy