1// Copyright 2013-2020 Aerospike, Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package aerospike
16
17import (
18	"fmt"
19
20	. "github.com/aerospike/aerospike-client-go/logger"
21	. "github.com/aerospike/aerospike-client-go/types"
22	Buffer "github.com/aerospike/aerospike-client-go/utils/buffer"
23)
24
25// guarantee touchCommand implements command interface
26var _ command = &touchCommand{}
27
28type touchCommand struct {
29	singleCommand
30
31	policy *WritePolicy
32}
33
34func newTouchCommand(cluster *Cluster, policy *WritePolicy, key *Key) (touchCommand, error) {
35	partition, err := PartitionForWrite(cluster, &policy.BasePolicy, key)
36	if err != nil {
37		return touchCommand{}, err
38	}
39
40	newTouchCmd := touchCommand{
41		singleCommand: newSingleCommand(cluster, key, partition),
42		policy:        policy,
43	}
44
45	return newTouchCmd, nil
46}
47
48func (cmd *touchCommand) getPolicy(ifc command) Policy {
49	return cmd.policy
50}
51
52func (cmd *touchCommand) writeBuffer(ifc command) error {
53	return cmd.setTouch(cmd.policy, cmd.key)
54}
55
56func (cmd *touchCommand) getNode(ifc command) (*Node, error) {
57	return cmd.partition.GetNodeWrite(cmd.cluster)
58}
59
60func (cmd *touchCommand) prepareRetry(ifc command, isTimeout bool) bool {
61	cmd.partition.PrepareRetryWrite(isTimeout)
62	return true
63}
64
65func (cmd *touchCommand) parseResult(ifc command, conn *Connection) error {
66	// Read header.
67	_, err := conn.Read(cmd.dataBuffer, 8)
68	if err != nil {
69		return err
70	}
71
72	if compressedSize := cmd.compressedSize(); compressedSize > 0 {
73		// Read compressed size
74		_, err = conn.Read(cmd.dataBuffer, compressedSize)
75		if err != nil {
76			Logger.Debug("Connection error reading data for TouchCommand: %s", err.Error())
77			return err
78		}
79
80		// Read compressed size
81		_, err = conn.Read(cmd.dataBuffer, 8)
82		if err != nil {
83			Logger.Debug("Connection error reading data for TouchCommand: %s", err.Error())
84			return err
85		}
86
87		if err := cmd.conn.initInflater(true, compressedSize); err != nil {
88			return NewAerospikeError(PARSE_ERROR, fmt.Sprintf("Error setting up zlib inflater for size `%d`: %s", compressedSize, err.Error()))
89		}
90
91		// Read header.
92		_, err = conn.Read(cmd.dataBuffer, int(_MSG_TOTAL_HEADER_SIZE))
93		if err != nil {
94			Logger.Debug("Connection error reading data for TouchCommand: %s", err.Error())
95			return err
96		}
97	} else {
98		// Read header.
99		_, err = conn.Read(cmd.dataBuffer[8:], int(_MSG_TOTAL_HEADER_SIZE)-8)
100		if err != nil {
101			Logger.Debug("Connection error reading data for TouchCommand: %s", err.Error())
102			return err
103		}
104	}
105
106	// Read header.
107	header := Buffer.BytesToInt64(cmd.dataBuffer, 0)
108
109	// Validate header to make sure we are at the beginning of a message
110	if err := cmd.validateHeader(header); err != nil {
111		return err
112	}
113
114	resultCode := cmd.dataBuffer[13] & 0xFF
115
116	if resultCode != 0 {
117		if resultCode == byte(KEY_NOT_FOUND_ERROR) {
118			return ErrKeyNotFound
119		} else if ResultCode(resultCode) == FILTERED_OUT {
120			return ErrFilteredOut
121		}
122
123		return NewAerospikeError(ResultCode(resultCode))
124	}
125	if err := cmd.emptySocket(conn); err != nil {
126		return err
127	}
128	return nil
129}
130
131func (cmd *touchCommand) Execute() error {
132	return cmd.execute(cmd, false)
133}
134