-
Notifications
You must be signed in to change notification settings - Fork 58
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Fixed buffer resize on writes larger than default 64K * Added flow control handling * Fixed re-putting a deleted object issue * Added Object Store documentation
- Loading branch information
Showing
17 changed files
with
291 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
# Object Store | ||
|
||
[The Object Store](https://docs.nats.io/nats-concepts/jetstream/obj_store) is very similar to the Key Value Store in that you put and get data using a key. | ||
The difference being that Object store allows for the storage of objects that can be of any size. | ||
|
||
Under the covers Object Store is a client side construct that allows you to store and retrieve chunks of data | ||
by a key using JetStream as the stream persistence engine. It's a simple, yet powerful way to store | ||
and retrieve large data like files. | ||
|
||
To be able to use Object Store you need to enable JetStream by running the server with `-js` flag e.g. `nats-server -js`. | ||
|
||
## Object Store Quick Start | ||
|
||
[Download the latest](https://nats.io/download/) `nats-server` for your platform and run it with JetStream enabled: | ||
|
||
```shell | ||
$ nats-server -js | ||
``` | ||
|
||
Install `NATS.Client.ObjectStore` preview from Nuget. | ||
|
||
Before we can do anything, we need an Object Store context: | ||
|
||
```csharp | ||
await using var nats = new NatsConnection(); | ||
var js = new NatsJSContext(nats); | ||
var obj = new NatsObjContext(js); | ||
``` | ||
|
||
Let's create our store first. In Object Store, a bucket is simply a storage for key/object pairs: | ||
|
||
```csharp | ||
var store = await obj.CreateObjectStore("test-bucket"); | ||
``` | ||
|
||
Now that we have a KV bucket in our stream, let's see its status using the [NATS command | ||
line client](https://github.com/nats-io/natscli): | ||
|
||
```shell | ||
$ nats object ls | ||
╭──────────────────────────────────────────────────────────────────────╮ | ||
│ Object Store Buckets │ | ||
├─────────────┬─────────────┬─────────────────────┬──────┬─────────────┤ | ||
│ Bucket │ Description │ Created │ Size │ Last Update │ | ||
├─────────────┼─────────────┼─────────────────────┼──────┼─────────────┤ | ||
│ test-bucket │ │ 2023-10-18 14:10:27 │ 0 B │ never │ | ||
╰─────────────┴─────────────┴─────────────────────┴──────┴─────────────╯ | ||
``` | ||
|
||
We can save objects in a bucket by putting them using a key, which is `my/random/data.bin` in our case. We can also retrieve the | ||
saved value by its key: | ||
|
||
```csharp | ||
await store.PutAsync("my/random/data.bin", File.OpenRead("data.bin")); | ||
|
||
await store.GetAsync("my/random/data.bin", File.OpenWrite("data_copy.bin")); | ||
``` | ||
|
||
We can also confirm that our value is persisted by using the NATS command line: | ||
|
||
```shell | ||
$ nats object info test-bucket my/random/data.bin | ||
Object information for test-bucket > my/random/data.bin | ||
|
||
Size: 10 MiB | ||
Modification Time: 18 Oct 23 14:54 +0000 | ||
Chunks: 80 | ||
Digest: SHA-256 d34334673e4e2b2300c09550faa5e2b6d0f04245a1d0b664454bb922da56 | ||
``` | ||
|
||
## Other Operations | ||
|
||
### Get Info | ||
|
||
We can get information about a key in a bucket: | ||
|
||
```csharp | ||
var metadata = await store.GetInfoAsync("my/random/data.bin"); | ||
|
||
Console.WriteLine("Metadata:"); | ||
Console.WriteLine($" Bucket: {metadata.Bucket}"); | ||
Console.WriteLine($" Name: {metadata.Name}"); | ||
Console.WriteLine($" Size: {metadata.Size}"); | ||
Console.WriteLine($" Time: {metadata.MTime}"); | ||
Console.WriteLine($" Chunks: {metadata.Chunks}"); | ||
|
||
// Outputs: | ||
// Metadata: | ||
// Bucket: test-bucket | ||
// Name: my/random/data.bin | ||
// Size: 10485760 | ||
// Time: 18/10/2023 15:13:22 +00:00 | ||
// Chunks: 80 | ||
``` | ||
|
||
### Delete | ||
|
||
We can delete a key from a bucket: | ||
|
||
```csharp | ||
await store.DeleteAsync("my/random/data.bin"); | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
data* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,48 @@ | ||
using System.Text; | ||
using System.Security.Cryptography; | ||
using Microsoft.Extensions.Logging; | ||
using NATS.Client.Core; | ||
using NATS.Client.JetStream; | ||
using NATS.Client.ObjectStore; | ||
using NATS.Client.ObjectStore.Models; | ||
|
||
var nats = new NatsConnection(); | ||
var opts = NatsOpts.Default with { LoggerFactory = new MinimumConsoleLoggerFactory(LogLevel.Error) }; | ||
|
||
var nats = new NatsConnection(opts); | ||
var js = new NatsJSContext(nats); | ||
var ob = new NatsObjContext(js); | ||
var obj = new NatsObjContext(js); | ||
|
||
var store = await ob.CreateObjectStore(new NatsObjConfig("o1")); | ||
Log("Create object store..."); | ||
var store = await obj.CreateObjectStore("test-bucket"); | ||
|
||
var meta = new ObjectMetadata { Name = "k1", Options = new Options { MaxChunkSize = 10 }, }; | ||
var data = new byte[1024 * 1024 * 10]; | ||
Random.Shared.NextBytes(data); | ||
|
||
var stringBuilder = new StringBuilder(); | ||
for (var i = 0; i < 9; i++) | ||
{ | ||
stringBuilder.Append($"{i:D2}-4567890"); | ||
} | ||
File.WriteAllBytes("data.bin", data); | ||
|
||
var buffer90 = stringBuilder.ToString(); | ||
{ | ||
var buffer = Encoding.ASCII.GetBytes(buffer90); | ||
var stream = new MemoryStream(buffer); | ||
Log("Put file..."); | ||
await store.PutAsync("my/random/data.bin", File.OpenRead("data.bin")); | ||
|
||
await store.PutAsync(meta, stream); | ||
Log("Get file..."); | ||
await store.GetAsync("my/random/data.bin", File.OpenWrite("data1.bin")); | ||
|
||
var data = await store.GetInfoAsync("k1"); | ||
var hash = Convert.ToBase64String(SHA256.HashData(File.ReadAllBytes("data.bin"))); | ||
var hash1 = Convert.ToBase64String(SHA256.HashData(File.ReadAllBytes("data1.bin"))); | ||
|
||
Console.WriteLine($"DATA: {data}"); | ||
} | ||
Log($"Check SHA-256: {hash == hash1}"); | ||
|
||
{ | ||
var memoryStream = new MemoryStream(); | ||
await store.GetAsync("k1", memoryStream); | ||
await memoryStream.FlushAsync(); | ||
var buffer = memoryStream.ToArray(); | ||
Console.WriteLine($"buffer:{Encoding.ASCII.GetString(buffer)}"); | ||
} | ||
var metadata = await store.GetInfoAsync("my/random/data.bin"); | ||
|
||
Console.WriteLine("Metadata:"); | ||
Console.WriteLine($" Bucket: {metadata.Bucket}"); | ||
Console.WriteLine($" Name: {metadata.Name}"); | ||
Console.WriteLine($" Size: {metadata.Size}"); | ||
Console.WriteLine($" Time: {metadata.MTime}"); | ||
Console.WriteLine($" Chunks: {metadata.Chunks}"); | ||
|
||
await store.DeleteAsync("my/random/data.bin"); | ||
|
||
Console.WriteLine("Bye"); | ||
|
||
void Log(string message) | ||
{ | ||
Console.WriteLine($"{DateTime.Now:HH:mm:ss.fff} {message}"); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.