use of io.cdap.cdap.data2.dataset2.lib.table.Update in project cdap by caskdata.
the class HBaseTableFactory method upgradeCoProcessor.
private void upgradeCoProcessor(TableId tableId, Class<? extends Coprocessor> coprocessor) throws IOException {
try (HBaseDDLExecutor ddlExecutor = ddlExecutorFactory.get()) {
HTableDescriptor tableDescriptor;
try (HBaseAdmin admin = new HBaseAdmin(hConf)) {
// If table doesn't exist, then skip upgrading coprocessor
if (!tableUtil.tableExists(admin, tableId)) {
LOG.debug("TMS Table {} was not found. Skip upgrading coprocessor.", tableId);
return;
}
tableDescriptor = tableUtil.getHTableDescriptor(admin, tableId);
}
// Get cdap version from the table
ProjectInfo.Version version = HBaseTableUtil.getVersion(tableDescriptor);
String hbaseVersion = HBaseTableUtil.getHBaseVersion(tableDescriptor);
if (hbaseVersion != null && hbaseVersion.equals(HBaseVersion.getVersionString()) && version.compareTo(ProjectInfo.getVersion()) >= 0) {
// If cdap has version has not changed or is greater, no need to update. Just enable it, in case
// it has been disabled by the upgrade tool, and return
LOG.info("Table '{}' has not changed and its version '{}' is same or greater than current CDAP version '{}'." + " The underlying HBase version {} has also not changed.", tableId, version, ProjectInfo.getVersion(), hbaseVersion);
enableTable(ddlExecutor, tableId);
return;
}
// create a new descriptor for the table update
HTableDescriptorBuilder newDescriptor = tableUtil.buildHTableDescriptor(tableDescriptor);
// Remove old coprocessor
Map<String, HBaseTableUtil.CoprocessorInfo> coprocessorInfo = HBaseTableUtil.getCoprocessorInfo(tableDescriptor);
for (Map.Entry<String, HBaseTableUtil.CoprocessorInfo> coprocessorEntry : coprocessorInfo.entrySet()) {
newDescriptor.removeCoprocessor(coprocessorEntry.getValue().getClassName());
}
// Add new coprocessor
CoprocessorDescriptor coprocessorDescriptor = coprocessorManager.getCoprocessorDescriptor(coprocessor, Coprocessor.PRIORITY_USER);
Path path = coprocessorDescriptor.getPath() == null ? null : new Path(coprocessorDescriptor.getPath());
newDescriptor.addCoprocessor(coprocessorDescriptor.getClassName(), path, coprocessorDescriptor.getPriority(), coprocessorDescriptor.getProperties());
// Update CDAP version, table prefix
HBaseTableUtil.setVersion(newDescriptor);
HBaseTableUtil.setHBaseVersion(newDescriptor);
HBaseTableUtil.setTablePrefix(newDescriptor, cConf);
// Disable auto-splitting
newDescriptor.setValue(HTableDescriptor.SPLIT_POLICY, cConf.get(Constants.MessagingSystem.TABLE_HBASE_SPLIT_POLICY));
// Disable Table
disableTable(ddlExecutor, tableId);
tableUtil.modifyTable(ddlExecutor, newDescriptor.build());
LOG.debug("Enabling table '{}'...", tableId);
enableTable(ddlExecutor, tableId);
}
LOG.info("Table '{}' update completed.", tableId);
}
use of io.cdap.cdap.data2.dataset2.lib.table.Update in project cdap by caskdata.
the class AppMetadataStore method addWorkflowNodeState.
private void addWorkflowNodeState(ProgramId programId, String pid, Map<String, String> systemArgs, ProgramRunStatus status, @Nullable BasicThrowable failureCause) {
String workflowNodeId = systemArgs.get(ProgramOptionConstants.WORKFLOW_NODE_ID);
String workflowName = systemArgs.get(ProgramOptionConstants.WORKFLOW_NAME);
String workflowRun = systemArgs.get(ProgramOptionConstants.WORKFLOW_RUN_ID);
ApplicationId appId = Ids.namespace(programId.getNamespace()).app(programId.getApplication());
ProgramRunId workflowRunId = appId.workflow(workflowName).run(workflowRun);
// Node states will be stored with following key:
// workflowNodeState.namespace.app.WORKFLOW.workflowName.workflowRun.workflowNodeId
MDSKey key = getProgramKeyBuilder(TYPE_WORKFLOW_NODE_STATE, workflowRunId.getParent()).add(workflowRun).add(workflowNodeId).build();
WorkflowNodeStateDetail nodeStateDetail = new WorkflowNodeStateDetail(workflowNodeId, ProgramRunStatus.toNodeStatus(status), pid, failureCause);
write(key, nodeStateDetail);
// Get the run record of the Workflow which started this program
key = getProgramKeyBuilder(TYPE_RUN_RECORD_STARTED, workflowRunId.getParent()).add(workflowRunId.getRun()).build();
RunRecordMeta record = get(key, RunRecordMeta.class);
if (record != null) {
// Update the parent Workflow run record by adding node id and program run id in the properties
Map<String, String> properties = record.getProperties();
properties.put(workflowNodeId, pid);
write(key, new RunRecordMeta(record, properties));
}
}
use of io.cdap.cdap.data2.dataset2.lib.table.Update in project cdap by caskdata.
the class DatasetTypeManager method addModule.
/**
* Add datasets module in a namespace
*
* @param datasetModuleId the {@link DatasetModuleId} to add
* @param className module class
* @param jarLocation location of the module jar
* @param force if true, an update will be allowed even if there are conflicts with other modules, or if
* removal of a type would break other modules' dependencies.
*/
public void addModule(final DatasetModuleId datasetModuleId, final String className, final Location jarLocation, final boolean force) throws DatasetModuleConflictException {
LOG.debug("adding module: {}, className: {}, jarLocation: {}", datasetModuleId, className, jarLocation == null ? "[local]" : jarLocation);
try {
final DatasetTypeMDS datasetTypeMDS = datasetCache.getDataset(DatasetMetaTableUtil.META_TABLE_NAME);
final DatasetInstanceMDS datasetInstanceMDS = datasetCache.getDataset(DatasetMetaTableUtil.INSTANCE_TABLE_NAME);
txExecutorFactory.createExecutor(datasetCache).execute(new TransactionExecutor.Subroutine() {
@Override
public void apply() throws Exception {
// 1. get existing module with all its types
DatasetModuleMeta existing = datasetTypeMDS.getModule(datasetModuleId);
DependencyTrackingRegistry reg;
// 2. unpack jar and create class loader
File unpackedLocation = Files.createTempDirectory(Files.createDirectories(systemTempPath), datasetModuleId.getEntityName()).toFile();
DirectoryClassLoader cl = null;
try {
// NOTE: if jarLocation is null, we assume that this is a system module, ie. always present in classpath
if (jarLocation != null) {
BundleJarUtil.unJar(jarLocation, unpackedLocation);
cl = new DirectoryClassLoader(unpackedLocation, cConf.get(Constants.AppFabric.PROGRAM_EXTRA_CLASSPATH), FilterClassLoader.create(getClass().getClassLoader()), "lib");
}
reg = new DependencyTrackingRegistry(datasetModuleId, datasetTypeMDS, cl, force);
// 3. register the new module while tracking dependencies.
// this will fail if a type exists in a different module
DatasetDefinitionRegistries.register(className, cl, reg);
} catch (TypeConflictException e) {
// type conflict from the registry, we want to throw that as is
throw e;
} catch (Exception e) {
LOG.error("Could not instantiate instance of dataset module class {} for module {} using jarLocation {}", className, datasetModuleId, jarLocation);
throw Throwables.propagate(e);
} finally {
if (cl != null) {
// Close the ProgramClassLoader
Closeables.closeQuietly(cl);
}
try {
DirUtils.deleteDirectoryContents(unpackedLocation);
} catch (IOException e) {
LOG.warn("Failed to delete directory {}", unpackedLocation, e);
}
}
// 4. determine whether any type were removed from the module, and whether any other modules depend on them
if (existing != null) {
Set<String> removedTypes = new HashSet<>(existing.getTypes());
removedTypes.removeAll(reg.getTypes());
// TODO (CDAP-6294): track dependencies at the type level
if (!force && !removedTypes.isEmpty() && !existing.getUsedByModules().isEmpty()) {
throw new DatasetModuleConflictException(String.format("Cannot update module '%s' to remove types %s: Modules %s may depend on it. Delete them first", datasetModuleId, removedTypes, existing.getUsedByModules()));
}
Collection<DatasetSpecification> instances = datasetInstanceMDS.getByTypes(datasetModuleId.getParent(), removedTypes);
if (!instances.isEmpty()) {
throw new DatasetModuleConflictException(String.format("Attempt to remove dataset types %s from module '%s' that have existing instances: %s. " + "Delete them first.", removedTypes, datasetModuleId, Iterables.toString(Iterables.transform(instances, new Function<DatasetSpecification, String>() {
@Nullable
@Override
public String apply(@Nullable DatasetSpecification input) {
return input.getName() + ":" + input.getType();
}
}))));
}
}
// NOTE: we use set to avoid duplicated dependencies
// NOTE: we use LinkedHashSet to preserve order in which dependencies must be loaded
Set<String> moduleDependencies = new LinkedHashSet<String>();
for (DatasetTypeId usedType : reg.getUsedTypes()) {
DatasetModuleMeta usedModule = datasetTypeMDS.getModuleByType(usedType);
Preconditions.checkState(usedModule != null, String.format("Found a null used module for type %s for while adding module %s", usedType, datasetModuleId));
// adding all used types and the module itself, in this very order to keep the order of loading modules
// for instantiating a type
moduleDependencies.addAll(usedModule.getUsesModules());
boolean added = moduleDependencies.add(usedModule.getName());
if (added) {
// also adding this module as a dependent for all modules it uses
usedModule.addUsedByModule(datasetModuleId.getEntityName());
datasetTypeMDS.writeModule(usedType.getParent(), usedModule);
}
}
URI jarURI = jarLocation == null ? null : jarLocation.toURI();
DatasetModuleMeta moduleMeta = existing == null ? new DatasetModuleMeta(datasetModuleId.getEntityName(), className, jarURI, reg.getTypes(), Lists.newArrayList(moduleDependencies)) : new DatasetModuleMeta(datasetModuleId.getEntityName(), className, jarURI, reg.getTypes(), Lists.newArrayList(moduleDependencies), Lists.newArrayList(existing.getUsedByModules()));
datasetTypeMDS.writeModule(datasetModuleId.getParent(), moduleMeta);
}
});
} catch (TransactionFailureException e) {
Throwable cause = e.getCause();
if (cause != null) {
if (cause instanceof DatasetModuleConflictException) {
throw (DatasetModuleConflictException) cause;
} else if (cause instanceof TypeConflictException) {
throw new DatasetModuleConflictException(cause.getMessage(), cause);
}
}
throw Throwables.propagate(e);
} catch (Exception e) {
LOG.error("Operation failed", e);
throw Throwables.propagate(e);
}
}
use of io.cdap.cdap.data2.dataset2.lib.table.Update in project cdap by caskdata.
the class InMemoryTableServiceTest method testInternalsNotLeaking.
@Test
public void testInternalsNotLeaking() {
// Test that there's no way to break the state of InMemoryTableService by changing parameters of update
// methods (after method invocation) or by changing returned values "in-place"
InMemoryTableService.create("table");
// verify writing thru merge is guarded
NavigableMap<byte[], NavigableMap<byte[], Update>> updates = Maps.newTreeMap(Bytes.BYTES_COMPARATOR);
NavigableMap<byte[], Update> rowUpdate = Maps.newTreeMap(Bytes.BYTES_COMPARATOR);
byte[] rowParam = new byte[] { 1 };
byte[] columnParam = new byte[] { 2 };
byte[] valParam = new byte[] { 3 };
rowUpdate.put(columnParam, new PutValue(valParam));
updates.put(rowParam, rowUpdate);
InMemoryTableService.merge("table", updates, 1L);
verify123();
updates.remove(rowParam);
rowUpdate.remove(columnParam);
rowParam[0]++;
columnParam[0]++;
valParam[0]++;
verify123();
// verify changing returned data from get doesn't affect the stored data
NavigableMap<byte[], NavigableMap<Long, byte[]>> rowFromGet = InMemoryTableService.get("table", new byte[] { 1 }, new Transaction(1L, 2L, new long[0], new long[0], 1L));
Assert.assertEquals(1, rowFromGet.size());
byte[] columnFromGet = rowFromGet.firstEntry().getKey();
Assert.assertArrayEquals(new byte[] { 2 }, columnFromGet);
byte[] valFromGet = rowFromGet.firstEntry().getValue().get(1L);
Assert.assertArrayEquals(new byte[] { 3 }, valFromGet);
rowFromGet.firstEntry().getValue().remove(1L);
rowFromGet.remove(columnFromGet);
columnFromGet[0]++;
valFromGet[0]++;
verify123();
// verify changing returned data doesn't affect the stored data
NavigableMap<byte[], NavigableMap<byte[], NavigableMap<Long, byte[]>>> fromGetRange = InMemoryTableService.getRowRange("table", null, null, new Transaction(1L, 2L, new long[0], new long[0], 1L));
Assert.assertEquals(1, fromGetRange.size());
byte[] keyFromGetRange = fromGetRange.firstEntry().getKey();
Assert.assertArrayEquals(new byte[] { 1 }, keyFromGetRange);
NavigableMap<byte[], NavigableMap<Long, byte[]>> rowFromGetRange = fromGetRange.get(new byte[] { 1 });
Assert.assertEquals(1, rowFromGetRange.size());
byte[] columnFromGetRange = rowFromGetRange.firstEntry().getKey();
Assert.assertArrayEquals(new byte[] { 2 }, columnFromGetRange);
byte[] valFromGetRange = rowFromGetRange.firstEntry().getValue().get(1L);
Assert.assertArrayEquals(new byte[] { 3 }, valFromGetRange);
rowFromGetRange.firstEntry().getValue().remove(1L);
rowFromGetRange.remove(columnFromGetRange);
fromGetRange.remove(keyFromGetRange);
keyFromGetRange[0]++;
columnFromGetRange[0]++;
valFromGet[0]++;
verify123();
}
use of io.cdap.cdap.data2.dataset2.lib.table.Update in project cdap by caskdata.
the class HBaseTable method undo.
@Override
protected void undo(NavigableMap<byte[], NavigableMap<byte[], Update>> persisted) throws Exception {
if (persisted.isEmpty()) {
return;
}
// NOTE: we use Delete with the write pointer as the specific version to delete.
List<Delete> deletes = Lists.newArrayList();
for (Map.Entry<byte[], NavigableMap<byte[], Update>> row : persisted.entrySet()) {
DeleteBuilder delete = tableUtil.buildDelete(row.getKey());
delete.setAttribute(TX_MAX_LIFETIME_MILLIS_KEY, txMaxLifetimeMillis);
for (Map.Entry<byte[], Update> column : row.getValue().entrySet()) {
// we want support tx and non-tx modes
if (tx != null) {
delete.setAttribute(TxConstants.TX_ROLLBACK_ATTRIBUTE_KEY, new byte[0]);
// TODO: hijacking timestamp... bad
delete.deleteColumn(columnFamily, column.getKey(), tx.getWritePointer());
} else {
delete.deleteColumns(columnFamily, column.getKey());
}
}
deletes.add(delete.build());
}
if (!deletes.isEmpty()) {
hbaseDelete(deletes);
}
}
Aggregations