| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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. |
| */ |
| package org.apache.ignite.internal.processors.cache.binary; |
| |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileOutputStream; |
| import java.util.concurrent.ConcurrentMap; |
| import org.apache.ignite.IgniteCheckedException; |
| import org.apache.ignite.IgniteLogger; |
| import org.apache.ignite.internal.GridKernalContext; |
| import org.apache.ignite.internal.binary.BinaryMetadata; |
| import org.apache.ignite.internal.binary.BinaryUtils; |
| import org.apache.ignite.internal.util.typedef.internal.CU; |
| import org.apache.ignite.internal.util.typedef.internal.U; |
| import org.jetbrains.annotations.Nullable; |
| |
| /** |
| * Class handles saving/restoring binary metadata to/from disk. |
| * |
| * Current implementation needs to be rewritten as it issues IO operations from discovery thread |
| * which may lead to segmentation of nodes from cluster. |
| */ |
| class BinaryMetadataFileStore { |
| /** Link to resolved binary metadata directory. Null for non persistent mode */ |
| private File workDir; |
| |
| /** */ |
| private final ConcurrentMap<Integer, BinaryMetadataHolder> metadataLocCache; |
| |
| /** */ |
| private final GridKernalContext ctx; |
| |
| /** */ |
| private final IgniteLogger log; |
| |
| /** |
| * @param metadataLocCache Metadata locale cache. |
| * @param ctx Context. |
| * @param log Logger. |
| * @param binaryMetadataFileStoreDir Path to binary metadata store configured by user, should include binary_meta and consistentId |
| */ |
| BinaryMetadataFileStore( |
| final ConcurrentMap<Integer, BinaryMetadataHolder> metadataLocCache, |
| final GridKernalContext ctx, |
| final IgniteLogger log, |
| @Nullable final File binaryMetadataFileStoreDir |
| ) throws IgniteCheckedException { |
| this.metadataLocCache = metadataLocCache; |
| this.ctx = ctx; |
| this.log = log; |
| |
| if (!CU.isPersistenceEnabled(ctx.config())) |
| return; |
| |
| if (binaryMetadataFileStoreDir != null) |
| workDir = binaryMetadataFileStoreDir; |
| else { |
| final String subFolder = ctx.pdsFolderResolver().resolveFolders().folderName(); |
| |
| workDir = new File(U.resolveWorkDirectory( |
| ctx.config().getWorkDirectory(), |
| "binary_meta", |
| false |
| ), |
| subFolder); |
| } |
| |
| U.ensureDirectory(workDir, "directory for serialized binary metadata", log); |
| } |
| |
| /** |
| * @param binMeta Binary metadata to be written to disk. |
| */ |
| void writeMetadata(BinaryMetadata binMeta) { |
| if (!CU.isPersistenceEnabled(ctx.config())) |
| return; |
| |
| try { |
| File file = new File(workDir, Integer.toString(binMeta.typeId()) + ".bin"); |
| |
| try(FileOutputStream out = new FileOutputStream(file, false)) { |
| byte[] marshalled = U.marshal(ctx, binMeta); |
| |
| out.write(marshalled); |
| } |
| } |
| catch (Exception e) { |
| U.warn(log, "Failed to save metadata for typeId: " + binMeta.typeId() + |
| "; exception was thrown: " + e.getMessage()); |
| } |
| } |
| |
| /** |
| * Restores metadata on startup of {@link CacheObjectBinaryProcessorImpl} but before starting discovery. |
| */ |
| void restoreMetadata() { |
| if (!CU.isPersistenceEnabled(ctx.config())) |
| return; |
| |
| for (File file : workDir.listFiles()) { |
| try (FileInputStream in = new FileInputStream(file)) { |
| BinaryMetadata meta = U.unmarshal(ctx.config().getMarshaller(), in, U.resolveClassLoader(ctx.config())); |
| |
| metadataLocCache.put(meta.typeId(), new BinaryMetadataHolder(meta, 0, 0)); |
| } |
| catch (Exception e) { |
| U.warn(log, "Failed to restore metadata from file: " + file.getName() + |
| "; exception was thrown: " + e.getMessage()); |
| } |
| } |
| } |
| |
| /** |
| * Checks if binary metadata for the same typeId is already presented on disk. |
| * If so merges it with new metadata and stores the result. |
| * Otherwise just writes new metadata. |
| * |
| * @param binMeta new binary metadata to write to disk. |
| */ |
| void mergeAndWriteMetadata(BinaryMetadata binMeta) { |
| BinaryMetadata existingMeta = readMetadata(binMeta.typeId()); |
| |
| if (existingMeta != null) { |
| BinaryMetadata mergedMeta = BinaryUtils.mergeMetadata(existingMeta, binMeta); |
| |
| writeMetadata(mergedMeta); |
| } else |
| writeMetadata(binMeta); |
| } |
| |
| /** |
| * Reads binary metadata for given typeId. |
| * |
| * @param typeId typeId of BinaryMetadata to be read. |
| */ |
| private BinaryMetadata readMetadata(int typeId) { |
| File file = new File(workDir, Integer.toString(typeId) + ".bin"); |
| |
| if (!file.exists()) |
| return null; |
| |
| try (FileInputStream in = new FileInputStream(file)) { |
| return U.unmarshal(ctx.config().getMarshaller(), in, U.resolveClassLoader(ctx.config())); |
| } |
| catch (Exception e) { |
| U.warn(log, "Failed to restore metadata from file: " + file.getName() + |
| "; exception was thrown: " + e.getMessage()); |
| } |
| |
| return null; |
| } |
| } |