You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
* Transaction docs
Signed-off-by: Adam Fowler <[email protected]>
* Update Sources/Valkey/Documentation.docc/Pipelining.md
Co-authored-by: Joseph Heck <[email protected]>
Signed-off-by: Adam Fowler <[email protected]>
* Update Sources/Valkey/Documentation.docc/Pipelining.md
Co-authored-by: Joseph Heck <[email protected]>
Signed-off-by: Adam Fowler <[email protected]>
* Update Sources/Valkey/Documentation.docc/Transactions.md
Co-authored-by: Joseph Heck <[email protected]>
Signed-off-by: Adam Fowler <[email protected]>
* Update Sources/Valkey/Documentation.docc/Transactions.md
Co-authored-by: Joseph Heck <[email protected]>
Signed-off-by: Adam Fowler <[email protected]>
* Edit check and set text
Signed-off-by: Adam Fowler <[email protected]>
* Transactions are only available on connections
Signed-off-by: Adam Fowler <[email protected]>
---------
Signed-off-by: Adam Fowler <[email protected]>
Co-authored-by: Joseph Heck <[email protected]>
Copy file name to clipboardExpand all lines: Sources/Valkey/Documentation.docc/Pipelining.md
+12-9Lines changed: 12 additions & 9 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
-
# Pipelining Commands
1
+
# Pipelining
2
2
3
-
Sending multiple commands at once without waiting for the response of each command
3
+
Send multiple commands at once without waiting for the response of each command.
4
4
5
5
Valkey pipelining is a technique for improving performance by issuing multiple commands at once without waiting for the response to each individual command. Pipelining not only reduces the latency cost of waiting for the result of each command it also reduces the cost to the server as it reduces I/O costs. Multiple commands can be read with a single syscall, and multiple results are delivered with a single syscall.
6
6
@@ -10,9 +10,9 @@ In valkey-swift each command has its own type conforming to the protocol ``Valke
10
10
11
11
```swift
12
12
let (_,_, getResult) =await valkeyClient.pipeline(
13
-
SET(key: "foo", value: "100"),
14
-
INCR(key: "foo")
15
-
GET(key: "foo")
13
+
SET("foo", value: "100"),
14
+
INCR("foo")
15
+
GET("foo")
16
16
)
17
17
// get returns an optional ByteBuffer
18
18
iflet result =try getResult.get().map({ String(buffer: $0) }) {
@@ -28,10 +28,10 @@ Being able to have multiple requests in transit on a single connection means we
28
28
tryawait client.withConnection { connection in
29
29
tryawaitwithThrowingTaskGroup(of: Void.self) { group in
Be careful when using a single connection across multiple Tasks though. The result of a command will only become available when the result of any previous command queued has been made available. So a command that either blocks the connection or takes a long time could affect the response time of commands that follow it.
49
+
Be careful when using a single connection across multiple Tasks though. The result of a command only becomes available when the server makes available the result of the command previously queued. Because of this, a command that either blocks the connection or takes a long time can affect the response time of commands that follow it.
50
+
51
+
You can find out more about pipelining of commands in the [Valkey documentation](https://valkey.io/topics/pipelining/).
Transactions allow you to group multiple commands into an atomic operation. A request sent by another client isn't processed in the middle of the execution of a transaction. Valkey uses the commands `MULTI` and `EXEC` to setup and execute a transaction. After initiating a transaction with `MULTI`, commands return a simple string `QUEUED` to indicate the server queued the commands. When the client sends the `EXEC` command, the server executes all the queued commands and returns an array with their results.
6
+
7
+
Because of this custom behaviour valkey-swift provides extra support for executing transactions. The API is very similar to the pipelining function which accepts a parameter pack of commands, detailed in <doc:Pipelining>.
8
+
9
+
```swift
10
+
tryawait valkeyClient.withConnection { connection in
11
+
let results =tryawait connection.transaction(
12
+
SET("foo", value: "100"),
13
+
LPUSH("queue", elements: ["foo"])
14
+
)
15
+
let lpushResponse =try results.1.get()
16
+
}
17
+
```
18
+
19
+
### Rollbacks
20
+
21
+
Valkey does not support rollbacks of transactions for simplicity and performance reasons.
22
+
23
+
### Check and set
24
+
25
+
The transaction command `WATCH` is used to add a check-and-set behaviour to Valkey transactions. This sets up a list of keys to WATCH, and if any changes to them are detected before the next transaction is executed on the same connection, then that transaction will fail.
26
+
27
+
For instance, imagine we wanted to atomically increment a counter (assuming we don't have the INCR command). A simple implementation might look like this:
28
+
29
+
```swift
30
+
// get value, otherwise default to 0
31
+
let value =tryawait connection.get("counter").map { Int(String(buffer: $0)) } ??0
Unfortunately this isn't a reliable solution as another client could attempt to increment the key "counter" in between the GET and SET commands, then the increment would be applied to the wrong value. By using WATCH and executing the SET inside a transaction we can avoid this. If the key is edited between the WATCH and SET, the transaction fails and throws a `ValkeyClientError(.transactionAborted)` error. When this occurs we know the key was edited between these two commands and we need to update the "counter" value before trying to call SET again, so we run the operation again.
36
+
37
+
```swift
38
+
whiletrue {
39
+
tryawait connection.watch(keys: ["counter"])
40
+
let value =tryawait connection.get("counter").map { Int(String(buffer: $0)) } ??0
41
+
do {
42
+
let result =tryawait connection.transaction(
43
+
SET("counter", String(value +1))
44
+
)
45
+
// set was succesful break out of the while loop
46
+
break
47
+
} catchlet error as ValkeyClientError where error.errorCode== .transactionAborted {
48
+
// Cancelled SET because "counter" was edited after WATCH, try again
49
+
}
50
+
}
51
+
```
52
+
53
+
More can be found out about Valkey transactions in the [Valkey documentation](https://valkey.io/topics/transactions/).
0 commit comments