Package org.syncany.database.dao

Source Code of org.syncany.database.dao.MultiChunkSqlDao

/*
* Syncany, www.syncany.org
* Copyright (C) 2011-2014 Philipp C. Heckel <philipp.heckel@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package org.syncany.database.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import org.syncany.chunk.MultiChunk;
import org.syncany.database.ChunkEntry.ChunkChecksum;
import org.syncany.database.DatabaseVersion.DatabaseVersionStatus;
import org.syncany.database.DatabaseVersionHeader;
import org.syncany.database.FileContent.FileChecksum;
import org.syncany.database.MultiChunkEntry;
import org.syncany.database.MultiChunkEntry.MultiChunkId;
import org.syncany.database.VectorClock;

/**
* The multi-chunk data access object (DAO) queries and modifies the <i>multichunk</i> and
* <i>multichunk_chunk</t> table in the SQL database. These tables correspond to the Java
* object {@link MultiChunk}.
*
* @author Philipp C. Heckel <philipp.heckel@gmail.com>
*/
public class MultiChunkSqlDao extends AbstractSqlDao {
  protected static final Logger logger = Logger.getLogger(MultiChunkSqlDao.class.getSimpleName())

  public MultiChunkSqlDao(Connection connection) {
    super(connection);
  }

  public void writeMultiChunks(Connection connection, long databaseVersionId, Collection<MultiChunkEntry> multiChunks) throws SQLException {
    for (MultiChunkEntry multiChunk : multiChunks) {
      PreparedStatement preparedStatement = getStatement(connection, "multichunk.insert.all.writeMultiChunks.sql");

      preparedStatement.setString(1, multiChunk.getId().toString());
      preparedStatement.setLong(2, databaseVersionId);
      preparedStatement.setLong(3, multiChunk.getSize());
     
      preparedStatement.executeUpdate();
      preparedStatement.close();
     
      writeMultiChunkRefs(connection, multiChunk);     
    }
  }

  private void writeMultiChunkRefs(Connection connection, MultiChunkEntry multiChunk) throws SQLException {
    PreparedStatement preparedStatement = getStatement("multichunk.insert.all.writeMultiChunkRefs.sql");
   
    for (ChunkChecksum chunkChecksum : multiChunk.getChunks()) {
      preparedStatement.setString(1, multiChunk.getId().toString());
      preparedStatement.setString(2, chunkChecksum.toString());
     
      preparedStatement.addBatch();     
    }
   
    preparedStatement.executeBatch();
    preparedStatement.close();
 

  public void writeMuddyMultiChunks(Map<DatabaseVersionHeader, Collection<MultiChunkEntry>> muddyMultiChunksPerDatabaseVersion) throws SQLException {
    PreparedStatement preparedStatement = getStatement("multichunk_muddy.insert.muddy.writeMuddyMultiChunks.sql");
   
    for (DatabaseVersionHeader muddyDatabaseVersionHeader : muddyMultiChunksPerDatabaseVersion.keySet()) {
      Collection<MultiChunkEntry> muddyMultiChunks = muddyMultiChunksPerDatabaseVersion.get(muddyDatabaseVersionHeader);
     
      for (MultiChunkEntry muddyMultiChunk : muddyMultiChunks) {
        String multiChunkIdStr = muddyMultiChunk.getId().toString();
        String clientName = muddyDatabaseVersionHeader.getClient();
        Long clientVersion = muddyDatabaseVersionHeader.getVectorClock().getClock(clientName);
       
        preparedStatement.setString(1, multiChunkIdStr);
        preparedStatement.setString(2, clientName);
        preparedStatement.setLong(3, clientVersion);
       
        preparedStatement.addBatch()
      }
    }
   
    preparedStatement.executeBatch();
    preparedStatement.close();
  }

  public void removeUnreferencedMultiChunks() throws SQLException {
    // Note: Chunk references (multichunk_chunk) must be removed first, because
    //       of the foreign key constraints.
   
    removeUnreferencedMultiChunkChunkRefs();
    removeUnreferencedMultiChunksInt();
  }
 
  private void removeUnreferencedMultiChunksInt() throws SQLException {
    PreparedStatement preparedStatement = getStatement("multichunk.delete.all.removeUnreferencedMultiChunks.sql");
    preparedStatement.executeUpdate()
    preparedStatement.close();
  }
 
  private void removeUnreferencedMultiChunkChunkRefs() throws SQLException {
    PreparedStatement preparedStatement = getStatement("multichunk.delete.all.removeUnreferencedMultiChunkChunkRefs.sql");
    preparedStatement.executeUpdate()
    preparedStatement.close();
  }
 
  public void removeNonMuddyMultiChunks() throws SQLException {
    PreparedStatement preparedStatement = getStatement("multichunk_muddy.delete.muddy.removeNonMuddyMultiChunks.sql");
    preparedStatement.executeUpdate()
    preparedStatement.close();
  }
 
  /**
   * Note: This method selects also {@link DatabaseVersionStatus#DIRTY DIRTY}.
   */
  public List<MultiChunkId> getMultiChunkIds(FileChecksum fileChecksum) {
    List<MultiChunkId> multiChunkIds = new ArrayList<MultiChunkId>();

    if (fileChecksum == null) {
      return multiChunkIds;
    }
    else {
      try (PreparedStatement preparedStatement = getStatement("multichunk.select.all.getMultiChunkIdsForFileChecksum.sql")) {
        preparedStatement.setString(1, fileChecksum.toString());
 
        try (ResultSet resultSet = preparedStatement.executeQuery()) {
          while (resultSet.next()) {
            multiChunkIds.add(MultiChunkId.parseMultiChunkId(resultSet.getString("multichunk_id")));
          }
   
          return multiChunkIds;
        }
      }
      catch (SQLException e) {
        throw new RuntimeException(e);
      }
    }
  } 
 
  /**
   * Note: This method selects also {@link DatabaseVersionStatus#DIRTY DIRTY}.
   */
  public Map<MultiChunkId, MultiChunkEntry> getMultiChunks(VectorClock vectorClock) {
    try (PreparedStatement preparedStatement = getStatement("multichunk.select.all.getMultiChunksWithChunksForDatabaseVersion.sql")) {
      preparedStatement.setString(1, vectorClock.toString());

      try (ResultSet resultSet = preparedStatement.executeQuery()) {
        return createMultiChunkEntriesWithChunks(resultSet);
      }
    }
    catch (SQLException e) {
      throw new RuntimeException(e);
    }
  } 

  /**
   * no commit
   */
  public void updateDirtyMultiChunksNewDatabaseId(long newDatabaseVersionId) {
    try (PreparedStatement preparedStatement = getStatement("multichunk.update.dirty.updateDirtyMultiChunksNewDatabaseId.sql")) {
      preparedStatement.setLong(1, newDatabaseVersionId);
      preparedStatement.executeUpdate();
    }
    catch (SQLException e) {
      throw new RuntimeException(e);
    }   
  }
 
  /**
   * Note: This method selects also {@link DatabaseVersionStatus#DIRTY DIRTY}.
   */
  public MultiChunkId getMultiChunkId(ChunkChecksum chunkChecksum) {
    try (PreparedStatement preparedStatement = getStatement("multichunk.select.all.getMultiChunkIdForChunk.sql")) {
      preparedStatement.setString(1, chunkChecksum.toString());
         
      try (ResultSet resultSet = preparedStatement.executeQuery()) {
        if (resultSet.next()) {
          return MultiChunkId.parseMultiChunkId(resultSet.getString("multichunk_id"));
        }
      }

      return null;
    }
    catch (SQLException e) {
      throw new RuntimeException(e);
    }
  }
 
  /**
   * Note: This method selects also {@link DatabaseVersionStatus#DIRTY DIRTY}.
   */
  public Map<ChunkChecksum,MultiChunkId> getMultiChunkIdsByChecksums(List<ChunkChecksum> chunkChecksums) {
    // Gather a unique array of checksum strings (required for query!)
    Set<ChunkChecksum> chunkChecksumSet = new HashSet<ChunkChecksum>(chunkChecksums);
    String[] checksums = new String[chunkChecksumSet.size()];
    int i = 0;
    for (ChunkChecksum checksum : chunkChecksumSet) {
      checksums[i] = checksum.toString();
      i++;
    }
   
    // Execute query
    Map<ChunkChecksum, MultiChunkId> result = new HashMap<ChunkChecksum, MultiChunkId>();
    try (PreparedStatement preparedStatement = getStatement("multichunk.select.all.getMultiChunkIdForChunks.sql")) {
      preparedStatement.setArray(1, connection.createArrayOf("varchar", checksums))
      try (ResultSet resultSet = preparedStatement.executeQuery()) {
        while (resultSet.next()) {
          result.put(ChunkChecksum.parseChunkChecksum(resultSet.getString("chunk_checksum")),
              MultiChunkId.parseMultiChunkId(resultSet.getString("multichunk_id")));
         
        }
      }

      return result;
    }
    catch (SQLException e) {
      throw new RuntimeException(e);
    }
  }
 
  public List<MultiChunkId> getDirtyMultiChunkIds() {
    List<MultiChunkId> dirtyMultiChunkIds = new ArrayList<MultiChunkId>();   
   
    try (PreparedStatement preparedStatement = getStatement("multichunk.select.dirty.getDirtyMultiChunkIds.sql")) {
      try (ResultSet resultSet = preparedStatement.executeQuery()) {
        while (resultSet.next()) {
          dirtyMultiChunkIds.add(MultiChunkId.parseMultiChunkId(resultSet.getString("multichunk_id")));
        }
       
        return dirtyMultiChunkIds;
      }
    }
    catch (SQLException e) {
      throw new RuntimeException(e);
    }
  }
 
  public Map<MultiChunkId, MultiChunkEntry> getUnusedMultiChunks() {
    try (PreparedStatement preparedStatement = getStatement("multichunk.select.all.getUnusedMultiChunks.sql")) {
      try (ResultSet resultSet = preparedStatement.executeQuery()) {
        return createMultiChunkEntriesWithoutChunks(resultSet);
      }
    }
    catch (SQLException e) {
      throw new RuntimeException(e);
    }
  }

  public Map<MultiChunkId, MultiChunkEntry> getMultiChunks() {
    try (PreparedStatement preparedStatement = getStatement("multichunk.select.all.getMultiChunks.sql")) {
      try (ResultSet resultSet = preparedStatement.executeQuery()) {
        return createMultiChunkEntriesWithoutChunks(resultSet);
      }
    }
    catch (SQLException e) {
      throw new RuntimeException(e);
    }
  }
 
  public Map<MultiChunkId, MultiChunkEntry> getMuddyMultiChunks() {
    try (PreparedStatement preparedStatement = getStatement("multichunk.select.muddy.getMuddyMultiChunks.sql")) {
      try (ResultSet resultSet = preparedStatement.executeQuery()) {
        return createMultiChunkEntriesWithoutChunks(resultSet);
      }
    }
    catch (SQLException e) {
      throw new RuntimeException(e);
    }
  }

  private Map<MultiChunkId, MultiChunkEntry> createMultiChunkEntriesWithoutChunks(ResultSet resultSet) throws SQLException {   
    Map<MultiChunkId, MultiChunkEntry> unusedMultiChunkIds = new HashMap<MultiChunkId, MultiChunkEntry>();   
   
    while (resultSet.next()) {
      MultiChunkId multiChunkId = MultiChunkId.parseMultiChunkId(resultSet.getString("id"));
      long multiChunkSize = resultSet.getLong("size");
           
      unusedMultiChunkIds.put(multiChunkId, new MultiChunkEntry(multiChunkId, multiChunkSize));
    }
   
    return unusedMultiChunkIds;
  }
 
  private Map<MultiChunkId, MultiChunkEntry> createMultiChunkEntriesWithChunks(ResultSet resultSet) throws SQLException {
    Map<MultiChunkId, MultiChunkEntry> multiChunkEntries = new HashMap<MultiChunkId, MultiChunkEntry>();   
    MultiChunkId currentMultiChunkId = null;
   
    while (resultSet.next()) {     
      MultiChunkId multiChunkId = MultiChunkId.parseMultiChunkId(resultSet.getString("multichunk_id"));
      long multiChunkSize = resultSet.getLong("size");
     
      MultiChunkEntry multiChunkEntry = null;
     
      if (currentMultiChunkId != null && currentMultiChunkId.equals(multiChunkId)) {
        multiChunkEntry = multiChunkEntries.get(multiChunkId)
      }
      else {
        multiChunkEntry = new MultiChunkEntry(multiChunkId, multiChunkSize);
      }
     
      multiChunkEntry.addChunk(ChunkChecksum.parseChunkChecksum(resultSet.getString("chunk_checksum")));
      multiChunkEntries.put(multiChunkId, multiChunkEntry);
     
      currentMultiChunkId = multiChunkId;
    }
   
    return multiChunkEntries;
  }
}
TOP

Related Classes of org.syncany.database.dao.MultiChunkSqlDao

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.