/** * Copyright (C) 2009-2013 FoundationDB, LLC * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.foundationdb.server.store.format.protobuf; import com.foundationdb.ais.model.Group; import com.foundationdb.ais.model.HasStorage; import com.foundationdb.ais.model.Join; import com.foundationdb.ais.model.Table; import com.foundationdb.ais.model.validation.AISValidationFailure; import com.foundationdb.ais.model.validation.AISValidationOutput; import com.foundationdb.ais.protobuf.CommonProtobuf; import com.foundationdb.ais.protobuf.CommonProtobuf.ProtobufRowFormat; import com.foundationdb.server.error.ProtobufBuildException; import com.foundationdb.server.error.StorageDescriptionInvalidException; import com.foundationdb.ais.protobuf.AISProtobuf.Storage; import com.google.protobuf.DescriptorProtos.FileDescriptorProto; import com.google.protobuf.DescriptorProtos.FileDescriptorSet; import com.google.protobuf.Descriptors.DescriptorValidationException; import com.google.protobuf.Descriptors.FileDescriptor; /** <code><i>Protobuf</i>StorageDescription</code> needs to depend the * store's base class, so this takes care of store independent * handling. */ class ProtobufStorageDescriptionHelper { private ProtobufStorageDescriptionHelper() { } public static final FileDescriptor[] DEPENDENCIES = { CustomOptions.getDescriptor() }; static void writeProtobuf(Storage.Builder storageBuilder, ProtobufRowFormat.Type formatType, FileDescriptorProto fileProto) { ProtobufRowFormat.Builder formatBuilder = ProtobufRowFormat.newBuilder(); formatBuilder.setType(formatType); if (fileProto != null) { formatBuilder.setFileDescriptor(fileProto); } storageBuilder.setExtension(CommonProtobuf.protobufRow, formatBuilder.build()); } static FileDescriptorProto validateAndGenerate(HasStorage object, ProtobufRowFormat.Type formatType, FileDescriptorProto fileProto, AISValidationOutput output) { if (!(object instanceof Group)) { output.reportFailure(new AISValidationFailure(new StorageDescriptionInvalidException(object, "is not a Group and cannot use Protocol Buffers"))); return null; } Group group = (Group)object; if (formatType == ProtobufRowFormat.Type.SINGLE_TABLE) { if (!group.getRoot().getChildJoins().isEmpty()) { output.reportFailure(new AISValidationFailure(new StorageDescriptionInvalidException(object, "has more than one table"))); return null; } } int currentVersion = sumTableVersions(group.getRoot()); if (fileProto != null) { int storedVersion = fileProto.getOptions() .getExtension(CustomOptions.GroupOptions.fdbsql).getVersion(); if (storedVersion == currentVersion) { return fileProto; } } FileDescriptorSet set = null; if (fileProto != null) { FileDescriptorSet.Builder builder = FileDescriptorSet.newBuilder(); builder.addFile(fileProto); set = builder.build(); } AISToProtobuf ais2p = new AISToProtobuf(formatType, set); ais2p.addGroup(group); set = ais2p.build(); fileProto = set.getFile(0); // Only added one group. // Make sure it will build before committing to this format. try { FileDescriptor.buildFrom(fileProto, DEPENDENCIES); } catch (DescriptorValidationException ex) { output.reportFailure(new AISValidationFailure(new ProtobufBuildException(ex))); } return fileProto; } private static int sumTableVersions(Table table) { int sum = table.getVersion() + 1; for (Join join : table.getChildJoins()) { sum += sumTableVersions(join.getChild()); } return sum; } static ProtobufRowDataConverter buildRowDataConverter(HasStorage object, FileDescriptorProto fileProto) { Group group = (Group)object; FileDescriptor fileDescriptor; try { fileDescriptor = FileDescriptor.buildFrom(fileProto, DEPENDENCIES); } catch (DescriptorValidationException ex) { throw new ProtobufBuildException(ex); } return ProtobufRowDataConverter.forGroup(group, fileDescriptor); } static ProtobufRowConverter buildRowConverter(HasStorage object, FileDescriptorProto fileProto) { Group group = (Group) object; FileDescriptor fileDescriptor; try { fileDescriptor = FileDescriptor.buildFrom(fileProto, DEPENDENCIES); } catch (DescriptorValidationException ex) { throw new ProtobufBuildException(ex); } return ProtobufRowConverter.forGroup(group, fileDescriptor); } }