### Simple Example: Collection Operations Source: https://github.com/kelindar/column/blob/main/examples/simple/README.md Demonstrates the creation of a collection, loading data, inserting indexes, and performing a query with iteration over the results. This example highlights fundamental data handling and retrieval processes. ```go package main import ( "fmt" "log" "github.com/kelindar/column" ) func main() { // Create a new collection collection, err := column.NewCollection("people") if err != nil { log.Fatalf("failed to create collection: %v", err) } // Define schema scollection.CreateString("name") collection.CreateString("city") collection.CreateInteger("age") // Load data collection.Append(map[string]interface{}{ "name": "human", "city": "old", "age": 20, }) collection.Append(map[string]interface{}{ "name": "mage", "city": "old", "age": 30, }) // Insert index err = collection.CreateIndex("city", column.Ascending) if err != nil { log.Fatalf("failed to create index: %v", err) } // Query data query := collection.Query().Where("city", column.Eq, "old") // Iterate over results for query.Next() { var name, city string var age int query.Get("name", &name) query.Get("city", &city) query.Get("age", &age) fmt.Printf("%s %s %d\n", name, city, age) } } ``` -------------------------------- ### Key/Value Cache Implementation in Go Source: https://github.com/kelindar/column/blob/main/examples/cache/README.md Implements a key-value cache using the column library. The `Cache` struct utilizes a `column.Collection` with a 'key' column for O(1) lookups and a 'val' column for string values. Includes methods for initialization, getting values by key, and setting/updating values. ```go package main import ( "fmt" "github.com/column" ) // Cache represents a key-value store type Cache struct { store *column.Collection } // New creates a new key-value cache func New() *Cache { db := column.NewCollection() db.CreateColumn("key", column.ForKey()) db.CreateColumn("val", column.ForString()) return &Cache{ store: db, } } // Get attempts to retrieve a value for a key func (c *Cache) Get(key string) (value string, found bool) { c.store.QueryKey(key, func(r column.Row) error { value, found = r.String("val") return nil }) return } // Set updates or inserts a new value func (c *Cache) Set(key, value string) { if err := c.store.QueryKey(key, func(r column.Row) error { r.SetString("val", value) return nil }); err != nil { panic(err) } } func main() { cache := New() // Example usage cache.Set("user_11255", "Hi, User 11255") val, found := cache.Get("user_11255") if found { fmt.Println(val, found) } // Performance simulation (as shown in the results) // This part is illustrative and not directly executable without a full column library setup fmt.Println("running insert of 50000 rows...") fmt.Println("-> inserted 10000 rows") fmt.Println("-> inserted 20000 rows") fmt.Println("-> inserted 30000 rows") fmt.Println("-> inserted 40000 rows") fmt.Println("-> inserted 50000 rows") fmt.Println("-> insert took 80.2478ms") fmt.Println("running query of user_11255...") fmt.Println("Hi, User 11255 true") fmt.Println("-> query took 1.271µs") } ``` -------------------------------- ### Snapshot Example Output Source: https://github.com/kelindar/column/blob/main/examples/snapshot/README.md This output shows the sequence of operations performed by the snapshot example, including initialization, restoration from a file, and saving the state. ```text snapshot: created an empty collection (0 rows) snapshot: restoring from '../../fixtures/players.bin' ... snapshot: restored 500 rows snapshot: saving state into 'snapshot.bin' ... ``` -------------------------------- ### Performance Metrics for 10 Million Rows Source: https://github.com/kelindar/column/blob/main/examples/million/README.md This snippet details the performance metrics for inserting 10 million rows, snapshotting, full scans, indexed queries, and updates. It shows the time taken for each operation and the number of rows affected or returned. ```output running insert of 10000000 rows... -> insert took 7.6464726s running snapshot of 10000000 rows... -> snapshot took 1.35868707s running full scan of age >= 30... -> result = 5100000 -> full scan took 27.011615ms running full scan of class == "rogue"... -> result = 3580000 -> full scan took 45.053185ms running indexed query of human mages... -> result = 680000 -> indexed query took 309.74µs running indexed query of human female mages... -> result = 320000 -> indexed query took 385.606µs running update of balance of everyone... -> updated 10000000 rows -> update took 108.09756ms running update of age of mages... -> updated 3020000 rows -> update took 41.731165ms ``` -------------------------------- ### Transaction Commit Example Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates a successful transaction where changes are committed. The `Query` method automatically calls `txn.Commit()` if the provided function returns nil. ```go // Range over all of the players and update (successfully their balance) players.Query(func(txn *column.Txn) error { balance := txn.Float64("balance") txn.Range(func(i uint32) { v.Set(10.0) // Update the "balance" to 10.0 }) // No error, transaction will be committed return nil }) ``` -------------------------------- ### Example Output: Location Updates Source: https://github.com/kelindar/column/blob/main/examples/merge/README.md This JSON output illustrates the sequential updates to the 'location' column, showing how the 'position' is modified over time while the 'velocity' remains constant. Each entry represents a state after a merge operation. ```json 00: {"position":[1,2],"velocity":[1,2]} 01: {"position":[2,4],"velocity":[1,2]} 02: {"position":[3,6],"velocity":[1,2]} 03: {"position":[4,8],"velocity":[1,2]} 04: {"position":[5,10],"velocity":[1,2]} 05: {"position":[6,12],"velocity":[1,2]} 06: {"position":[7,14],"velocity":[1,2]} 07: {"position":[8,16],"velocity":[1,2]} 08: {"position":[9,18],"velocity":[1,2]} 09: {"position":[10,20],"velocity":[1,2]} 10: {"position":[11,22],"velocity":[1,2]} 11: {"position":[12,24],"velocity":[1,2]} 12: {"position":[13,26],"velocity":[1,2]} 13: {"position":[14,28],"velocity":[1,2]} 14: {"position":[15,30],"velocity":[1,2]} 15: {"position":[16,32],"velocity":[1,2]} 16: {"position":[17,34],"velocity":[1,2]} 17: {"position":[18,36],"velocity":[1,2]} 18: {"position":[19,38],"velocity":[1,2]} 19: {"position":[20,40],"velocity":[1,2]} ``` -------------------------------- ### Union Query on Indexes Source: https://github.com/kelindar/column/blob/main/README.md Combines results from multiple indexes using the `Union` operation. This example counts players who are either 'rogue' or 'mage' by merging the 'rogue' and 'mage' indexes. ```go // How many rogues and mages? players.Query(func(txn *column.Txn) error { txn.With("rogue").Union("mage").Count() return nil }) ``` -------------------------------- ### Transaction Rollback Example Source: https://github.com/kelindar/column/blob/main/README.md Illustrates a transaction that is rolled back due to an error. The `Query` method automatically calls `txn.Rollback()` if the provided function returns an error, ensuring no changes are applied. ```go // Range over all of the players and update (successfully their balance) players.Query(func(txn *column.Txn) error { balance := txn.Float64("balance") txn.Range(func(i uint32) { v.Set(10.0) // Update the "balance" to 10.0 }) // Returns an error, transaction will be rolled back return fmt.Errorf("bug") }) ``` -------------------------------- ### Difference Query with Index Source: https://github.com/kelindar/column/blob/main/README.md Excludes results from a specific index using the `Without` operation. This example counts all players except those identified by the 'rogue' index. ```go // How many rogues and mages? players.Query(func(txn *column.Txn) error { txn.Without("rogue").Count() return nil }) ``` -------------------------------- ### Combined Indexed and Value Query Source: https://github.com/kelindar/column/blob/main/README.md Performs a query that combines an index-based filter with a value-based filter. This example counts players who are indexed as 'rogue' and also have an 'age' greater than or equal to 30. ```go // How many rogues that are over 30 years old? players.Query(func(txn *column.Txn) error { txn.With("rogue").WithFloat("age", func(v float64) bool { return v >= 30 }).Count() return nil }) ``` -------------------------------- ### Create a Snapshot Source: https://github.com/kelindar/column/blob/main/README.md Illustrates how to create a snapshot of a collection's data. This involves creating an `io.Writer` destination (e.g., a file) and then calling the `Snapshot()` method on the collection to save its current state. ```go dst, err := os.Create("snapshot.bin") if err != nil { panic(err) } err = players.Snapshot(dst) ``` -------------------------------- ### Concurrency Benchmark Results Source: https://github.com/kelindar/column/blob/main/examples/bench/README.md Presents benchmark results for different workloads (read/write ratios) and processor counts. The data shows transaction rates per second for each configuration, highlighting performance under varying concurrency scenarios. ```text WORK PROCS READ RATE WRITE RATE 100%-0% 1 6,080,402 txn/s 0 txn/s 100%-0% 2 11,280,415 txn/s 0 txn/s 100%-0% 4 23,909,267 txn/s 0 txn/s 100%-0% 8 44,142,401 txn/s 0 txn/s 100%-0% 16 43,839,560 txn/s 0 txn/s 100%-0% 32 45,981,323 txn/s 0 txn/s 100%-0% 64 42,550,034 txn/s 0 txn/s 100%-0% 128 41,748,237 txn/s 0 txn/s 100%-0% 256 42,838,515 txn/s 0 txn/s 100%-0% 512 44,023,907 txn/s 0 txn/s 90%-10% 1 5,275,465 txn/s 582,720 txn/s 90%-10% 2 7,739,053 txn/s 895,427 txn/s 90%-10% 4 9,355,436 txn/s 1,015,179 txn/s 90%-10% 8 8,605,764 txn/s 972,278 txn/s 90%-10% 16 10,254,677 txn/s 1,138,855 txn/s 90%-10% 32 10,231,753 txn/s 1,146,337 txn/s 90%-10% 64 10,708,470 txn/s 1,190,486 txn/s 90%-10% 128 9,863,114 txn/s 1,111,391 txn/s 90%-10% 256 9,149,044 txn/s 1,008,791 txn/s 90%-10% 512 9,131,921 txn/s 1,017,933 txn/s 50%-50% 1 2,308,520 txn/s 2,323,510 txn/s 50%-50% 2 2,387,979 txn/s 2,370,993 txn/s 50%-50% 4 2,381,743 txn/s 2,321,850 txn/s 50%-50% 8 2,250,533 txn/s 2,293,409 txn/s 50%-50% 16 2,272,368 txn/s 2,272,368 txn/s 50%-50% 32 2,181,658 txn/s 2,268,687 txn/s 50%-50% 64 2,245,193 txn/s 2,228,612 txn/s 50%-50% 128 2,172,485 txn/s 2,124,144 txn/s 50%-50% 256 1,871,648 txn/s 1,830,572 txn/s 50%-50% 512 1,489,572 txn/s 1,525,730 txn/s 10%-90% 1 383,770 txn/s 3,350,996 txn/s 10%-90% 2 318,691 txn/s 2,969,129 txn/s 10%-90% 4 316,425 txn/s 2,826,869 txn/s 10%-90% 8 341,467 txn/s 2,751,654 txn/s 10%-90% 16 300,528 txn/s 2,861,470 txn/s 10%-90% 32 349,121 txn/s 2,932,224 txn/s 10%-90% 64 344,824 txn/s 2,869,017 txn/s 10%-90% 128 287,559 txn/s 2,718,741 txn/s 10%-90% 256 253,480 txn/s 2,366,967 txn/s 10%-90% 512 220,717 txn/s 2,102,277 txn/s 0%-100% 1 0 txn/s 3,601,751 txn/s 0%-100% 2 0 txn/s 3,054,833 txn/s 0%-100% 4 0 txn/s 3,171,539 txn/s 0%-100% 8 0 txn/s 2,962,326 txn/s 0%-100% 16 0 txn/s 2,986,498 txn/s 0%-100% 32 0 txn/s 3,068,877 txn/s 0%-100% 64 0 txn/s 2,994,055 txn/s 0%-100% 128 0 txn/s 2,802,362 txn/s 0%-100% 256 0 txn/s 2,444,133 txn/s 0%-100% 512 0 txn/s 2,180,372 txn/s ``` -------------------------------- ### Creating and Querying with Index Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates creating an index named 'rogue' based on the 'class' column with a predicate to identify 'rogue' players. It then queries using this index for significantly faster results compared to a full scan. ```go // Create the index "rogue" in advance out.CreateIndex("rogue", "class", func(v interface{}) bool { return v == "rogue" }) // This returns the same result as the query before, but much faster players.Query(func(txn *column.Txn) error { count := txn.With("rogue").Count() return nil }) ``` -------------------------------- ### Create Collection with Columns Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates how to create a new collection and define its schema by adding columns with specified data types. This is the initial step before inserting data. ```go // Create a new collection with some columns players := column.NewCollection() players.CreateColumn("name", column.ForString()) players.CreateColumn("class", column.ForString()) players.CreateColumn("balance", column.ForFloat64()) players.CreateColumn("age", column.ForInt16()) ``` -------------------------------- ### Restore from a Snapshot Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates how to restore a collection from a previously created snapshot. This requires an `io.Reader` pointing to the snapshot file and calling the `Restore()` method. The collection's schema must be initialized before restoration. ```go src, err := os.Open("snapshot.bin") if err != nil { panic(err) } err = players.Restore(src) ``` -------------------------------- ### Create Collection with Primary Key Source: https://github.com/kelindar/column/blob/main/README.md Shows how to create a new collection and define a primary key column named 'name' using `column.ForKey()`. It also demonstrates adding another string column and inserting a row with a primary key. ```go players := column.NewCollection() players.CreateColumn("name", column.ForKey()) // Create a "name" as a primary-key players.CreateColumn("class", column.ForString()) // .. and some other columns // Insert a player with "merlin" as its primary key players.InsertKey("merlin", func(r column.Row) error { r.SetString("class", "mage") return nil }) ``` -------------------------------- ### Batch Updates and Zero-Allocation Querying Source: https://github.com/kelindar/column/blob/main/README.md Optimized for high-throughput batch operations and minimizes heap allocations during query execution, leading to significant performance gains. ```go package main import ( "fmt" "github.com/kelindar/column" ) func main() { collection := column.NewCollection() ages := collection.Int("age") // Append initial data for i := 0; i < 1000; i++ { ages.Append(i) } // Batch update: Increment all ages by 10 updateQuery := column.All() collection.Batch(func(tx *column.Tx) { tx.Int("age").Update(updateQuery, func(current int) int { return current + 10 }) }) // Querying with zero allocations (example: sum of ages) squery := column.All() ssum := ages.Sum(query) fmt.Printf("Sum of ages after update: %d\n", sum) } ``` -------------------------------- ### Iterate and Print Rogue Names Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates how to query a collection, filter by 'rogue', and iterate over the results to print the 'name' of each rogue using a string column reader. ```go players.Query(func(txn *column.Txn) error { names := txn.String("name") // Create a column reader return txn.With("rogue").Range(func(i uint32) { name, _ := names.Get() println("rogue name", name) }) }) ``` -------------------------------- ### Stream Changes with Commit Channel Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates how to stream transaction commits using a `commit.Channel` implementation of the `commit.Logger` interface. This allows for real-time monitoring of changes by publishing commits to a Go channel, which can then be consumed by a separate goroutine. ```go writer := make(commit.Channel, 1024) players := NewCollection(column.Options{ Writer: writer, }) go func(){ for commit := range writer { fmt.Printf("commit %v\n", commit.ID) } }() ``` -------------------------------- ### Concurrent Snapshotting Source: https://github.com/kelindar/column/blob/main/README.md Allows for the creation of consistent snapshots of the entire collection, enabling reliable data persistence to files. ```go package main import ( "fmt" "os" "github.com/kelindar/column" ) func main() { collection := column.NewCollection() values := collection.Int("value") values.Append(1) values.Append(2) // Create a snapshot file fileName := "column_snapshot.cbor" file, err := os.Create(fileName) if err != nil { panic(err) } defer file.Close() // Save the collection to the snapshot file err = collection.Snapshot(file) if err != nil { panic(err) } fmt.Printf("Snapshot saved to %s\n", fileName) // Restore from snapshot (example) fileToRestore, err := os.Open(fileName) if err != nil { panic(err) } defer fileToRestore.Close() restoredCollection := column.NewCollection() err = restoredCollection.Restore(fileToRestore) if err != nil { panic(err) } restoredValues := restoredCollection.Int("value") fmt.Printf("Restored values: %v\n", restoredValues.All()) // Clean up the snapshot file // os.Remove(fileName) } ``` -------------------------------- ### SIMD-Enabled Aggregate Functions Source: https://github.com/kelindar/column/blob/main/README.md Supports vectorized aggregate functions like sum, average, min, and max, leveraging Single Instruction, Multiple Data (SIMD) for accelerated computations. ```go package main import ( "fmt" "github.com/kelindar/column" ) func main() { collection := column.NewCollection() values := collection.Float("value") // Append sample data for i := 0.0; i < 100.0; i++ { values.Append(i) } // Calculate sum using SIMD sum := values.Sum(column.All()) fmt.Printf("Sum of values: %.2f\n", sum) // Calculate average using SIMD average := values.Avg(column.All()) fmt.Printf("Average of values: %.2f\n", average) // Calculate min using SIMD min := values.Min(column.All()) fmt.Printf("Minimum value: %.2f\n", min) // Calculate max using SIMD max := values.Max(column.All()) fmt.Printf("Maximum value: %.2f\n", max) } ``` -------------------------------- ### Iterate and Print Multiple Columns (Name and Age) Source: https://github.com/kelindar/column/blob/main/README.md Shows how to query a collection, filter by 'rogue', and iterate over the results, accessing both 'name' and 'age' columns using respective column readers. ```go players.Query(func(txn *column.Txn) error { names := txn.String("name") ages := txn.Int64("age") return txn.With("rogue").Range(func(i uint32) { name, _ := names.Get() age, _ := ages.Get() println("rogue name", name) println("rogue age", age) }) }) ``` -------------------------------- ### Create and Use Sorted Index for Ascending Balance Source: https://github.com/kelindar/column/blob/main/README.md Explains how to create a sorted index on the 'balance' column named 'richest' and then use it within a transaction to process records in ascending order of balance, after filtering by 'rogue'. ```go // Create the sorted index "sortedNames" in advance out.CreateSortIndex("richest", "balance") // This filters the transaction with the `rouge` index before // ranging through the remaining balances by ascending order players.Query(func(txn *column.Txn) error { name := txn.String("name") balance := txn.Float64("balance") txn.With("rogue").Ascend("richest", func (i uint32) { // save or do something with sorted record curName, _ := name.Get() balance.Set(newBalance(curName)) }) return nil }) ``` -------------------------------- ### Replicate Changes Between Collections Source: https://github.com/kelindar/column/blob/main/README.md Shows how to synchronize data between two collections using the `Replay()` method. It involves streaming changes from a primary collection to a replica collection via a commit channel, ensuring data consistency across both. ```go writer := make(commit.Channel, 1024) primary := column.NewCollection(column.Options{ Writer: &writer, }) primary.CreateColumnsOf(object) replica := column.NewCollection() replica.CreateColumnsOf(object) go func() { for change := range writer { replica.Replay(change) } }() ``` -------------------------------- ### Define and Store Binary Record Source: https://github.com/kelindar/column/blob/main/README.md Illustrates how to define a custom struct (`Location`) that implements `BinaryMarshaler` and `BinaryUnmarshaler` interfaces for storing complex data as a single column. It shows creating a column for this record type and then inserting and querying data using `SetRecord` and `Record` methods. ```go type Location struct { X float64 `json:"x"` Y float64 `json:"y"` } func (l Location) MarshalBinary() ([]byte, error) { return json.Marshal(l) } func (l *Location) UnmarshalBinary(b []byte) error { return json.Unmarshal(b, l) } players.CreateColumn("location", ForRecord(func() *Location { return new(Location) })) // Insert a new location idx, _ := players.Insert(func(r Row) error { r.SetRecord("location", &Location{X: 1, Y: 2}) return nil }) // Read the location back players.QueryAt(idx, func(r Row) error { location, ok := r.Record("location") return nil }) ``` -------------------------------- ### Calculate Average Age and Filter Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates calculating the average age of 'rogues' and then filtering the collection to find records younger than the average, summing their balances. ```go players.Query(func(txn *column.Txn) error { totalAge := txn.With("rouge").Int64("age").Sum() totalRouges := int64(txn.Count()) avgAge := totalAge / totalRouges txn.WithInt("age", func(v float64) bool { return v < avgAge }) // get total balance for 'all rouges younger than the average rouge' balance := txn.Float64("balance").Sum() return nil }) ``` -------------------------------- ### Go Benchmark Results (100,000 items) Source: https://github.com/kelindar/column/blob/main/README.md Performance metrics for various operations on a collection of 100,000 items with a dozen columns. Metrics include operations per second (ns/op), bytes per operation (B/op), and allocations per operation (allocs/op). ```go cpu: Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz BenchmarkCollection/insert-8 2523 469481 ns/op 24356 B/op 500 allocs/op BenchmarkCollection/select-at-8 22194190 54.23 ns/op 0 B/op 0 allocs/op BenchmarkCollection/scan-8 2068 568953 ns/op 122 B/op 0 allocs/op BenchmarkCollection/count-8 571449 2057 ns/op 0 B/op 0 allocs/op BenchmarkCollection/range-8 28660 41695 ns/op 3 B/op 0 allocs/op BenchmarkCollection/update-at-8 5911978 202.8 ns/op 0 B/op 0 allocs/op BenchmarkCollection/update-all-8 1280 946272 ns/op 3726 B/op 0 allocs/op BenchmarkCollection/delete-at-8 6405852 188.9 ns/op 0 B/op 0 allocs/op BenchmarkCollection/delete-all-8 2073188 562.6 ns/op 0 B/op 0 allocs/op ``` -------------------------------- ### Extending Time-To-Live (TTL) Source: https://github.com/kelindar/column/blob/main/README.md Shows how to query and extend the time-to-live of an existing object in a collection using the Extend() method on the TTL column. ```go players.Query(func(txn *column.Txn) error { ttl := txn.TTL() return txn.Range(func(i uint32) { ttl.Extend(1 * time.Hour) // Add some time }) }) ``` -------------------------------- ### Query by Primary Key Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates how to query a specific row using its primary key ('merlin') without needing to know its internal index. This method involves an overhead due to hash table lookups. ```go // Query merlin's class players.QueryKey("merlin", func(r column.Row) error { class, _ := r.String("class") return nil }) ``` -------------------------------- ### String Concatenation with Merge Source: https://github.com/kelindar/column/blob/main/README.md Illustrates using the Merge() operation for string data types, specifically concatenating strings with a custom merge function. ```go // A merging function that simply concatenates 2 strings together concat := func(value, delta string) string { if len(value) > 0 { value += ", " } return value + delta } // Create a column with a specified merge function db := column.NewCollection() db.CreateColumn("alphabet", column.ForString(column.WithMerge(concat))) // Insert letter "A" db.Insert(func(r column.Row) error { r.SetString("alphabet", "A") // now contains "A" return nil }) // Insert letter "B" db.QueryAt(0, func(r column.Row) error { r.MergeString("alphabet", "B") // now contains "A, B" return nil }) ``` -------------------------------- ### Bulk Insert using Transaction Source: https://github.com/kelindar/column/blob/main/README.md Illustrates how to perform efficient bulk inserts by using a transaction. This method is faster than multiple individual inserts as it reduces transaction overhead. ```go players.Query(func(txn *column.Txn) error { for _, v := range myRawData { txn.Insert(...) } return nil // Commit }) ``` -------------------------------- ### Primary Keys Source: https://github.com/kelindar/column/blob/main/README.md Enables the use of primary keys for data identification and retrieval, particularly useful when row offsets are not suitable. ```go package main import ( "fmt" "github.com/kelindar/column" ) func main() { collection := column.NewCollection() // Define a primary key column (e.g., user ID) ids := collection.String("id").AsPrimaryKey() values := collection.Int("value") // Append data with primary keys ids.Append("user123") values.Append(100) ids.Append("user456") values.Append(200) // Retrieve data using primary key user123Value := values.Lookup(ids.Lookup("user123")) fmt.Printf("Value for user123: %d\n", user123Value) // Update data using primary key collection.Update(func(tx *column.Tx) { tx.Int("value").Update(ids.EqualTo("user123"), func(current int) int { return current + 50 }) }) user123UpdatedValue := values.Lookup(ids.Lookup("user123")) fmt.Printf("Updated value for user123: %d\n", user123UpdatedValue) } ``` -------------------------------- ### Shell Benchmark Results (20 million rows) Source: https://github.com/kelindar/column/blob/main/README.md Performance metrics for operations on a larger dataset of 20 million rows, each with 12 columns and 4 indexes. Includes insert times, snapshot times, full scan performance, indexed query performance, and update times. ```shell running insert of 20000000 rows... -> insert took 20.4538183s running snapshot of 20000000 rows... -> snapshot took 2.57960038s running full scan of age >= 30... -> result = 10200000 -> full scan took 61.611822ms running full scan of class == "rogue"... -> result = 7160000 -> full scan took 81.389954ms running indexed query of human mages... -> result = 1360000 -> indexed query took 608.51µs running indexed query of human female mages... -> result = 640000 -> indexed query took 794.49µs running update of balance of everyone... -> updated 20000000 rows -> update took 214.182216ms running update of age of mages... -> updated 6040000 rows -> update took 81.292378ms ``` -------------------------------- ### Columnar Data Layout and Bitmap Indexing Source: https://github.com/kelindar/column/blob/main/README.md Leverages a cache-friendly columnar data layout (Structures of Arrays) combined with bitmap indexing for efficient data retrieval and filtering. Supports binary operations (AND, OR, XOR) on filters via SIMD. ```go package main import ( "fmt" "github.com/kelindar/column" ) func main() { // Example of creating a collection and adding data collection := column.NewCollection() // Add a column for integers ints := collection.Int("age") // Add a column for strings strings := collection.String("name") // Append data to columns ints.Append(30) strings.Append("Alice") ints.Append(25) strings.Append("Bob") // Querying data (example: select names where age > 28) query := ints.GreaterThan(28) names := strings.Select(query) fmt.Println("Names older than 28:", names) } ``` -------------------------------- ### Setting Time-To-Live (TTL) for Expiration Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates how to set a time-to-live (TTL) duration when inserting an object into a collection, causing it to be automatically evicted after the specified time. ```go players.Insert(func(r column.Row) error { r.SetString("name", "Merlin") r.SetString("class", "mage") r.SetTTL(5 * time.Second) // time-to-live of 5 seconds return nil }) ``` -------------------------------- ### Transaction Management (Commit and Rollback) Source: https://github.com/kelindar/column/blob/main/README.md Provides support for ACID transactions, allowing atomic commits or rollbacks of multiple operations to maintain data consistency. ```go package main import ( "fmt" "github.com/kelindar/column" ) func main() { collection := column.NewCollection() balances := collection.Float("balance") balances.Append(100.0) // Start a transaction tx := collection.Begin() // Perform operations within the transaction tx.Float("balance").Update(column.At(0), func(current float64) float64 { return current - 50.0 // Withdraw 50 }) t// Simulate a condition where rollback might occur // if someCondition { // tx.Rollback() // fmt.Println("Transaction rolled back.") // } else { tx.Commit() fmt.Println("Transaction committed.") // } fmt.Printf("Final balance: %.2f\n", balances.At(0)) } ``` -------------------------------- ### Insert Single Record Source: https://github.com/kelindar/column/blob/main/README.md Shows how to insert a single record into a collection by providing a function that sets the values for each column. Returns the index of the inserted row. ```go index, err := players.Insert(func(r column.Row) error { r.SetString("name", "merlin") r.SetString("class", "mage") r.SetFloat64("balance", 99.95) r.SetInt16("age", 107) return nil }) ``` -------------------------------- ### Atomic Updates in Column Collections Source: https://github.com/kelindar/column/blob/main/README.md Demonstrates how to atomically update values in a column collection using the Set() method within a transaction. Updates are applied when the transaction is committed. ```go players.Query(func(txn *column.Txn) error { balance := txn.Float64("balance") age := txn.Int64("age") return txn.With("rogue").Range(func(i uint32) { balance.Set(10.0) // Update the "balance" to 10.0 age.Set(50) // Update the "age" to 50 }) }) ``` -------------------------------- ### Change Data Stream Source: https://github.com/kelindar/column/blob/main/README.md Provides a mechanism to stream all committed changes (inserts, updates, deletes) from the collection in a consistent manner. ```go package main import ( "fmt" "github.com/kelindar/column" ) func main() { collection := column.NewCollection() data := collection.String("data") // Create a change stream stream := collection.Changes() // Append data, which will trigger a change event data.Append("initial data") // Process changes from the stream go func() { for change := range stream { fmt.Printf("Change detected: %+v\n", change) } }() // Perform another operation to trigger more changes collection.Update(func(tx *column.Tx) { tx.String("data").Update(column.At(0), func(current string) string { return current + " - updated" }) }) // In a real application, you would keep the stream open or handle it appropriately. // For this example, we'll just let it run briefly. ttime.Sleep(100 * time.Millisecond) } ``` -------------------------------- ### Querying with Value Predicate Source: https://github.com/kelindar/column/blob/main/README.md Performs a full scan of a column to filter data based on a provided predicate. It iterates through values in the 'class' column and counts those where the value equals 'rogue'. ```go // This query performs a full scan of "class" column players.Query(func(txn *column.Txn) error { count := txn.WithValue("class", func(v interface{}) bool { return v == "rogue" }).Count() return nil }) ``` -------------------------------- ### Expiration of Rows Source: https://github.com/kelindar/column/blob/main/README.md Supports setting Time-To-Live (TTL) for rows or using an expiration column to automatically remove data after a specified duration. ```go package main import ( "fmt" "time" "github.com/kelindar/column" ) func main() { collection := column.NewCollection() data := collection.String("data") // Add an expiration column (e.g., Unix timestamp) exp := collection.Timestamp("expires_at") // Append data with an expiration time 1 second from now data.Append("temporary data") exp.Append(time.Now().Add(1 * time.Second)) fmt.Println("Data appended with expiration.") // In a real scenario, a background process or periodic check // would remove expired rows. For this example, we'll simulate. ttime.Sleep(2 * time.Second) // Check if data is still present (it should be removed by a cleanup mechanism) // For demonstration, we'll manually check expiration now := time.Now() expiredQuery := exp.LessThan(now.Unix()) if len(data.Select(expiredQuery)) > 0 { fmt.Println("Expired data found (should have been removed).") } else { fmt.Println("Expired data has been cleaned up.") } } ``` -------------------------------- ### Atomic Increment/Decrement with Merge Source: https://github.com/kelindar/column/blob/main/README.md Shows how to atomically increment or decrement numerical values in a column collection using the Merge() operation. Indexes are updated accordingly. ```go players.Query(func(txn *column.Txn) error { balance := txn.Float64("balance") return txn.With("rogue").Range(func(i uint32) { balance.Merge(500.0) // Increment the "balance" by 500 }) }) ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.