long before = System.currentTimeMillis();
byte[] rowId = recordId.toBytes();
try {
// We need to read the original record in order to put the delete marker in the non-versioned fields.
// Throw RecordNotFoundException if there is no record to be deleted
FieldTypes fieldTypes = typeManager.getFieldTypesSnapshot();
// The existing record is read with authorization disabled, because when deleting a full record we
// must make sure we can delete all the fields in it.
Pair<Record, byte[]> recordAndOcc = readWithOcc(recordId, null, null, fieldTypes, true);
recordAndOcc.getV1().setAttributes(attributes);
Record originalRecord = new UnmodifiableRecord(recordAndOcc.getV1());
// If the record contains any field with scope != non-versioned, do not allow to delete it if
// authorization is active. This is because access to these fields will not be validated by the
// first Put call below, and hence the clearData afterwards might fail, leaving us with a half-deleted
// record.
if (AuthorizationContextHolder.getCurrentContext() != null) {
for (QName field : originalRecord.getFields().keySet()) {
if (fieldTypes.getFieldType(field).getScope() != Scope.NON_VERSIONED) {
throw new RepositoryException("Deleting records with versioned or versioned-mutable fields "
+ "is not supported when authorization is active.");
}
}
}
byte[] oldOcc = recordAndOcc.getV2();
RecordEvent recordEvent = new RecordEvent();
recordEvent.setType(Type.DELETE);
recordEvent.setTableName(getTableName());
if (attributes != null && !attributes.isEmpty()) {
recordEvent.getAttributes().putAll(attributes);
}
for (RecordUpdateHook hook : updateHooks) {
hook.beforeDelete(originalRecord, this, fieldTypes, recordEvent);
}
if (conditions != null) {
Record conditionsRecord = MutationConditionVerifier.checkConditions(originalRecord, conditions, this,
null);
if (conditionsRecord != null) {
return conditionsRecord;
}
}
Put put = new Put(rowId);
// Mark the record as deleted
put.add(RecordCf.DATA.bytes, RecordColumn.DELETED.bytes, 1L, Bytes.toBytes(true));
// Put the delete marker in the non-versioned fields instead of deleting their columns in the clearData call
// This is needed to avoid non-versioned fields to be lost due to the hbase delete thombstone
// See trac ticket http://dev.outerthought.org/trac/outerthought_lilyproject/ticket/297
Map<QName, Object> fields = originalRecord.getFields();
for (Entry<QName, Object> fieldEntry : fields.entrySet()) {
FieldTypeImpl fieldType = (FieldTypeImpl) fieldTypes.getFieldType(fieldEntry.getKey());
if (Scope.NON_VERSIONED == fieldType.getScope()) {
put.add(RecordCf.DATA.bytes, fieldType.getQualifier(), 1L, FieldFlags.getDeleteMarker());
}
}