Exemplo n.º 1
0
func (self *metadataInstance) opPut(operation *operations.Put,
	state *minos.OperationState) (bucketReturn ares.Return) {

	key, status := extractMetadataKey(operation.Key)
	if !status.IsOk() {
		return &bucket.ReturnGeneric{status}
	}

	status = assertNotConst(key)
	if !status.IsOk() {
		return &bucket.ReturnGeneric{status}
	}

	var valueToSet []byte
	var existingValue []byte
	var optimisticLocking bool

	numberOfValueElements := len(operation.Value)
	switch numberOfValueElements {
	case 0:
		optimisticLocking = false
		valueToSet = nil
	case 1:
		optimisticLocking = false
		valueToSet = operation.Value[0]
	case 2:
		optimisticLocking = true
		valueToSet = operation.Value[0]
		existingValue = operation.Value[1]
	default:
		status = retcode.NewStatusFmt(retcode.ErrorClient, "Expecting 0 value elements (remove), one "+
			"value element (the new value to set) or two value elements (the value to set and the existing "+
			"Value for optimistic locking. You've supplied %v value elements.",
			numberOfValueElements)
		return &bucket.ReturnGeneric{status}
	}

	singleValueGetterSetter := metadata.SingleValueGetterSetter{
		Key:   key,
		Value: valueToSet,
	}

	systemKey := isSystemKey(key)
	var validationError error
	if systemKey {
		// System validate
		validationError = validateSystemChange(singleValueGetterSetter)
	} else {
		// Let the bucket type validate the change
		bucketType := state.BucketType(state.BucketId.TypeId())
		if bucketType == nil {
			validationError = errors.New(fmt.Sprintf("The bucket type %v is not "+
				"known to the system. Cannot perform metadata change.", state.BucketId.TypeId()))
		}
		validationError = bucketType.ValidateMetadata(singleValueGetterSetter)
	}

	// Ok to perform the change?
	if validationError != nil {
		status = retcode.NewStatusFmt(retcode.ErrorClient,
			"The requested change of key %v was rejected, reason: %v", key, validationError)
		return &bucket.ReturnGeneric{status}
	}

	// Lock while performing change
	metadataId, err := state.BucketId.ConvertToMetadataId()
	if err != nil {
		status = retcode.NewStatusFmt(retcode.ErrorServer,
			"Unable to convert bucket ID to metadata ID: %v", err)
		return &bucket.ReturnGeneric{status}
	}
	state.Locker.BucketIdWriteLock(metadataId)
	defer state.Locker.BucketIdWriteUnlock(metadataId)

	// Check current value if optimistic locking is enabled
	if optimisticLocking {
		currentValue, err := state.MetadataGetterSetter.Get(key)
		if err != nil {
			status = retcode.NewStatusFmt(retcode.ErrorServer,
				"Error getting current metadata value for optimistic locking: %v", err)
			return &bucket.ReturnGeneric{status}
		}
		if bytes.Compare(currentValue, existingValue) != 0 {
			status = retcode.NewStatusFmt(retcode.ErrorOptimisticLocking,
				"Optimistic locking failure: The supplied 'existing' value is no longer "+
					"the current value. Refusing to perform the change.")
			return &bucket.ReturnGeneric{status}
		}
	}

	// Everything is OK, now perform the change
	err = state.MetadataGetterSetter.Set(key, valueToSet)
	if err != nil {
		status = retcode.NewStatusFmt(retcode.ErrorServer,
			"Could not write metadata: %v", err)
		return &bucket.ReturnGeneric{status}
	}

	return &operations.PutReturn{
		Status: retcode.NewStatusOk(),
	}
}
Exemplo n.º 2
0
func (self *dispatcherimpl) perform_BucketOperation(context *ares.Context,
	operation ares.Operation,
	targetBucketId bucket.Id) (
	ret ares.Return) {

	bucketId := targetBucketId

	if bucketId == nil || len(bucketId) == 0 {
		return &operations.GenericReturn{retcode.NewStatusError(retcode.ErrorClient,
			errors.New("Bucket ID is missing or invalid"))}
	}

	bucketType := self.typesRegistry.BucketType(bucketId.TypeId())
	if bucketType == nil {
		return &operations.GenericReturn{retcode.NewStatusError(retcode.ErrorClient,
			errors.New(fmt.Sprintf("BucketType %v not found", bucketId.TypeId())))}
	}

	var err error

	// Special case for metadata
	if bucketId.IsMetadata() {
		// Extract and supply the original bucket ID to the metadata
		bucketId = bucketId.ExtractOriginalId()
	}

	metadataReader, err := self.metadata.TypedGetterSetter(bucketId)
	if err != nil {
		return &operations.GenericReturn{
			retcode.NewStatusError(retcode.ErrorBucketIdNotFound, err)}
	}

	state := new(minos.OperationState)
	state.Operation = operation
	state.BucketId = bucketId

	putfowarderVar := new(putfowarder)
	putfowarderVar.metadataReader = metadataReader
	putfowarderVar.putReceiversIds, err = metadataReader.PutReceivers()
	putfowarderVar.context = *context
	putfowarderVar.forwardFunction = self.Perform

	state.PutForwarder = putfowarderVar
	state.MetadataGetterSetter = metadataReader
	state.NotificationReceiver = self.receiveNotification
	state.Context = context
	state.Dispatcher = self
	state.Locker = self.lock
	state.Files = self.files
	state.BucketType = self.typesRegistry.BucketType

	bucketReturn := bucketType.Perform(state)
	putfowarderVar.maybeDoPutForward(bucketReturn)
	return bucketReturn
}