Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert presence change from string to binary #1069

Merged
merged 3 commits into from
Nov 20, 2024
Merged

Conversation

chacha912
Copy link
Contributor

@chacha912 chacha912 commented Nov 14, 2024

What this PR does / why we need it:

This PR implements the storage format change for presence changes from string to byte array to maintain consistency with other data types.

  • Register custom encoder to store presence change as binary format
  • Update related tests
  • Add migration script for converting existing string presence changes to binary format

Which issue(s) this PR fixes:

Fixes #1067

Special notes for your reviewer:

Test migration
After building with make build, run the migration:

bin/yorkie migration --from v0.5.6 --to v0.5.6 --mongo-connection-uri mongodb://localhost:27017 --database-name yorkie-meta

Does this PR introduce a user-facing change?:


Additional documentation:


Checklist:

  • Added relevant tests or not required
  • Didn't break anything

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced migration version v0.5.6 for improved database handling.
    • Added functionality to migrate presence changes from string to byte array format.
  • Improvements

    • Enhanced handling of PresenceChange objects, simplifying encoding and decoding processes.
    • Streamlined the creation of change information by removing unnecessary encoding steps.
    • Updated the ToPBChangePack method to simplify conversion processes by eliminating dependency on the innerpresence package.
  • Bug Fixes

    • Updated tests to ensure proper serialization and deserialization of PresenceChange objects.
  • Chores

    • Cleaned up unused imports to improve code clarity.

@chacha912 chacha912 requested a review from hackerwins November 14, 2024 08:33
Copy link

coderabbitai bot commented Nov 14, 2024

Walkthrough

The pull request introduces several changes primarily focused on the handling of presence changes within the codebase. Key modifications include the addition of a new migration version (v0.5.6) and the introduction of functions for encoding and decoding presence changes. The test cases for the converter functionality have been updated to simplify the creation of presence change objects. Additionally, the representation of presence changes in various structures has been altered, transitioning from string types to more complex objects, enhancing data handling consistency across the application.

Changes

File Path Change Summary
api/converter/converter_test.go Updated test cases to simplify change object creation by using innerpresence.PresenceChange directly instead of JSON parsing.
cmd/yorkie/migration.go Added migration version v0.5.6 to migrationMap, linking it to the RunMigration function from the v056 package.
migrations/v0.5.6/main.go Introduced RunMigration function for migration v0.5.6, which calls MigratePresenceChange and handles migration completion logging.
migrations/v0.5.6/migrate-presence-change.go Added functions for migrating presence changes, including validatePresenceChangeMigration, processMigrationBatchPresence, and MigratePresenceChange, which processes and validates the migration of presence changes in MongoDB.
pkg/document/innerpresence/presence.go Removed NewChangeFromJSON function; added functions for encoding and decoding PresenceChange objects.
server/backend/database/change_info.go Changed PresenceChange field type from string to pointer of innerpresence.PresenceChange in ChangeInfo struct; removed EncodePresenceChange function.
server/backend/database/memory/database.go Modified CreateChangeInfos method to directly assign PresenceChange from cn without encoding.
server/backend/database/mongo/client.go Updated CreateChangeInfos method to directly assign presence_change from cn instead of using database.EncodePresenceChange.
server/backend/database/mongo/registry.go Added support for encoding/decoding innerpresence.PresenceChange with new encoder and decoder functions.
server/backend/database/mongo/registry_test.go Added a test case to validate the serialization and deserialization of a PresenceChange object.
server/packs/serverpacks.go Removed import of innerpresence and updated ToPBChangePack method to directly use info.PresenceChange.

Assessment against linked issues

Objective Addressed Explanation
Unify data storage format for presence changes (#1067)

Possibly related PRs

Suggested labels

enhancement 🌟


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

codecov bot commented Nov 14, 2024

Codecov Report

Attention: Patch coverage is 30.88235% with 47 lines in your changes missing coverage. Please review.

Project coverage is 46.79%. Comparing base (f8ebba2) to head (379b46a).
Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
server/backend/database/mongo/registry.go 39.13% 20 Missing and 8 partials ⚠️
server/backend/database/change_info.go 5.26% 18 Missing ⚠️
server/packs/serverpacks.go 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1069      +/-   ##
==========================================
- Coverage   46.82%   46.79%   -0.03%     
==========================================
  Files          84       84              
  Lines       12180    12219      +39     
==========================================
+ Hits         5703     5718      +15     
- Misses       5909     5928      +19     
- Partials      568      573       +5     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.


🚨 Try these New Features:

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Outside diff range and nitpick comments (11)
migrations/v0.5.6/main.go (2)

17-18: Enhance package documentation with migration details

The package documentation could be more descriptive about what this migration does. Consider adding details about the presence change format conversion from string to byte array.

-// Package v056 provides migration for v0.5.6
+// Package v056 provides migration for v0.5.6 to convert the storage format
+// of presence changes from string to byte array, ensuring consistency with
+// other data types in the system.
 package v056

27-28: Enhance function documentation

The function documentation should include:

  • Parameter descriptions
  • Expected behavior
  • Batch size requirements
-// RunMigration runs migrations for v0.5.6
+// RunMigration executes the v0.5.6 migration to convert presence changes from string
+// to byte array format. It processes records in batches to manage memory usage.
+//
+// Parameters:
+//   - ctx: Context for cancellation and timeout
+//   - db: MongoDB client connection
+//   - databaseName: Name of the database to migrate
+//   - batchSize: Number of records to process in each batch (must be positive)
+//
+// Returns an error if the migration fails.
server/backend/database/mongo/registry_test.go (1)

69-88: Consider enhancing test coverage

While the basic functionality is tested, consider adding the following test cases for more comprehensive coverage:

  1. Test presence changes with multiple properties and nested objects
  2. Test error cases (e.g., invalid presence data)
  3. Add explicit assertions for individual fields after unmarshaling

Example enhancement:

 t.Run("presenceChange test", func(t *testing.T) {
+    tests := []struct {
+        name string
+        presence *innerpresence.Presence
+        changeType innerpresence.ChangeType
+        wantErr bool
+    }{
+        {
+            name: "basic presence",
+            presence: func() *innerpresence.Presence {
+                p := innerpresence.NewPresence()
+                p.Set("color", "orange")
+                return p
+            }(),
+            changeType: innerpresence.Put,
+            wantErr: false,
+        },
+        {
+            name: "complex presence",
+            presence: func() *innerpresence.Presence {
+                p := innerpresence.NewPresence()
+                p.Set("color", "blue")
+                p.Set("position", map[string]interface{}{
+                    "x": 100,
+                    "y": 200,
+                })
+                return p
+            }(),
+            changeType: innerpresence.Put,
+            wantErr: false,
+        },
+    }
+
+    for _, tt := range tests {
+        t.Run(tt.name, func(t *testing.T) {
             presenceChange := &innerpresence.PresenceChange{
-                ChangeType: innerpresence.Put,
-                Presence:   presence,
+                ChangeType: tt.changeType,
+                Presence:   tt.presence,
             }
             // ... rest of the test
+            // Additional assertions
+            assert.Equal(t, tt.presence.Get("color"), info.PresenceChange.Presence.Get("color"))
         })
+    }
 })
pkg/document/innerpresence/presence.go (2)

107-119: Enhance documentation to specify the encoding format.

The function implementation is correct, but the documentation should explicitly mention that JSON encoding is used. This helps maintainers understand the storage format and potential size implications.

Apply this diff to improve the documentation:

-// EncodeToBytes encodes the given presence change into bytes array.
+// EncodeToBytes encodes the given presence change into a JSON byte array.
+// Returns nil, nil if the input is nil.

Line range hint 121-132: Fix indentation and enhance input validation.

The function has inconsistent indentation and could benefit from additional validation.

Apply these changes:

  1. Fix indentation:
 func PresenceChangeFromBytes(bytes []byte) (*PresenceChange, error) {
     if bytes == nil {
-		return nil, nil
-	}
+        return nil, nil
+    }
 
-	p := &PresenceChange{}
-	if err := json.Unmarshal(bytes, p); err != nil {
-		return nil, fmt.Errorf("unmarshal presence change: %w", err)
-	}
+    p := &PresenceChange{}
+    if err := json.Unmarshal(bytes, p); err != nil {
+        return nil, fmt.Errorf("unmarshal presence change: %w", err)
+    }
  1. Add validation:
     if err := json.Unmarshal(bytes, p); err != nil {
         return nil, fmt.Errorf("unmarshal presence change: %w", err)
     }
 
+    // Validate required fields
+    if p.ChangeType == "" {
+        return nil, fmt.Errorf("invalid presence change: missing change type")
+    }
+
     return p, nil

Also, improve the documentation:

-// PresenceChangeFromBytes unmarshals the given bytes array into PresenceChange.
+// PresenceChangeFromBytes unmarshals a JSON byte array into a PresenceChange object.
+// Returns nil, nil if the input is nil. Returns an error if the JSON is invalid
+// or required fields are missing.
server/backend/database/mongo/registry.go (2)

141-165: Consider standardizing error wrapping patterns.

While the error handling is functional, consider standardizing the error wrapping pattern. The function uses both direct fmt.Errorf("encode error: %w", err) and returning errors from EncodeToBytes with additional wrapping.

Consider applying this consistent pattern:

 func presenceChangeEncoder(_ bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
     if !val.IsValid() || val.Type() != tPresenceChange {
         return bsoncodec.ValueEncoderError{
             Name: "presenceChangeEncoder", Types: []reflect.Type{tPresenceChange}, Received: val}
     }

     presenceChange := val.Interface().(*innerpresence.PresenceChange)
     if presenceChange == nil {
         if err := vw.WriteNull(); err != nil {
-            return fmt.Errorf("encode error: %w", err)
+            return fmt.Errorf("presenceChangeEncoder: failed to write null: %w", err)
         }
         return nil
     }

     bytes, err := innerpresence.EncodeToBytes(presenceChange)
     if err != nil {
-        return fmt.Errorf("encode error: %w", err)
+        return fmt.Errorf("presenceChangeEncoder: failed to encode presence change: %w", err)
     }

     if err := vw.WriteBinary(bytes); err != nil {
-        return fmt.Errorf("encode error: %w", err)
+        return fmt.Errorf("presenceChangeEncoder: failed to write binary: %w", err)
     }

     return nil
 }

167-195: Consider standardizing error handling patterns.

Similar to the encoder, consider standardizing error messages for better debugging. Also, the default case in the switch statement could be more specific about the received type.

Consider applying these improvements:

 func presenceChangeDecoder(_ bsoncodec.DecodeContext, vr bsonrw.ValueReader, val reflect.Value) error {
     if val.Type() != tPresenceChange {
         return bsoncodec.ValueDecoderError{
             Name: "presenceChangeDecoder", Types: []reflect.Type{tPresenceChange}, Received: val}
     }

     switch vrType := vr.Type(); vrType {
     case bson.TypeNull:
         if err := vr.ReadNull(); err != nil {
-            return fmt.Errorf("decode error: %w", err)
+            return fmt.Errorf("presenceChangeDecoder: failed to read null: %w", err)
         }
         val.Set(reflect.Zero(tPresenceChange))
         return nil
     case bson.TypeBinary:
         data, _, err := vr.ReadBinary()
         if err != nil {
-            return fmt.Errorf("decode error: %w", err)
+            return fmt.Errorf("presenceChangeDecoder: failed to read binary: %w", err)
         }

         presenceChange, err := innerpresence.PresenceChangeFromBytes(data)
         if err != nil {
-            return fmt.Errorf("decode error: %w", err)
+            return fmt.Errorf("presenceChangeDecoder: failed to decode presence change: %w", err)
         }
         val.Set(reflect.ValueOf(presenceChange))
         return nil
     default:
-        return fmt.Errorf("unsupported type: %v", vr.Type())
+        return fmt.Errorf("presenceChangeDecoder: unsupported BSON type %v for presence change", vrType)
     }
 }
api/converter/converter_test.go (1)

264-267: LGTM! Consider adding more test cases.

The change aligns well with the PR objectives by moving away from string-based representation to direct struct instantiation. This simplifies the test setup and makes it more maintainable.

Consider adding more test cases to verify:

  • Presence changes with non-empty presence data
  • Different change types (Put, Delete)
  • Edge cases with nil or invalid presence data

Example test case:

change := &innerpresence.PresenceChange{
    ChangeType: innerpresence.Put,
    Presence: func() *innerpresence.Presence {
        p := innerpresence.NewPresence()
        p.SetData(map[string]interface{}{"cursor": 10})
        return p
    }(),
}
migrations/v0.5.6/migrate-presence-change.go (3)

31-51: Simplify validation by using CountDocuments instead of iterating over the cursor

Currently, the validatePresenceChangeMigration function fetches all documents and iterates over them to check if any presence_change fields are still stored as strings. This can be simplified by using CountDocuments with the same filter to check if any documents remain. If the count is greater than zero, it indicates that there are still documents to be migrated.

Apply this diff to simplify the function:

 func validatePresenceChangeMigration(ctx context.Context, db *mongo.Client, databaseName string) error {
     collection := db.Database(databaseName).Collection("changes")
-    cursor, err := collection.Find(ctx, bson.M{
+    count, err := collection.CountDocuments(ctx, bson.M{
         "presence_change": bson.M{
             "$type": "string",
         },
     })
     if err != nil {
         return fmt.Errorf("count documents: %w", err)
     }
-
-    if count > 0 {
-        return fmt.Errorf("found presence change still stored as string")
-    }
-
-    return nil
-
-    for cursor.Next(ctx) {
-        var doc bson.M
-        if err := cursor.Decode(&doc); err != nil {
-            return fmt.Errorf("decode document: %w", err)
-        }
-
-        if presenceChange, ok := doc["presence_change"]; ok {
-            if _, isString := presenceChange.(string); isString {
-                return fmt.Errorf("found presence change still stored as string")
-            }
-        }
-    }
-
+    if count > 0 {
+        return fmt.Errorf("found %d presence changes still stored as string", count)
+    }
     return nil
 }

37-38: Ensure consistent error wrapping for better context

In some places, errors are returned directly (e.g., return err), while in others, errors are wrapped with additional context using fmt.Errorf. For consistency and improved error tracing, consider wrapping all returned errors with contextual messages.

For example, modify these instances:

 if err != nil {
-    return err
+    return fmt.Errorf("failed to find documents: %w", err)
 }

 ...

 if err != nil {
-    return err
+    return fmt.Errorf("failed to count documents: %w", err)
 }

 ...

 if err != nil {
-    return err
+    return fmt.Errorf("collection.Find failed: %w", err)
 }

Also applies to: 113-114, 124-125


116-117: Use structured logging instead of fmt.Printf for better log management

Using fmt.Printf and fmt.Println for logging may not be suitable for larger applications or for environments where log management is critical. Consider using a structured logging library like log to provide better control over log output and to standardize logging practices.

Apply this diff to use the log package:

-import (
-    "context"
-    "fmt"
+import (
+    "context"
+    "fmt"
+    "log"
 )

 ...

 if totalCount == 0 {
-    fmt.Println("No data found to migrate")
+    log.Println("No data found to migrate")
     return nil
 }

 ...

-    fmt.Printf("%s.changes presence change migration completed: %d converted \n", databaseName, totalCount)
+    log.Printf("%s.changes presence change migration completed: %d converted\n", databaseName, totalCount)

Ensure to import the log package at the beginning of the file.

Also applies to: 164-164

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f8ebba2 and b9b1c0c.

📒 Files selected for processing (11)
  • api/converter/converter_test.go (1 hunks)
  • cmd/yorkie/migration.go (2 hunks)
  • migrations/v0.5.6/main.go (1 hunks)
  • migrations/v0.5.6/migrate-presence-change.go (1 hunks)
  • pkg/document/innerpresence/presence.go (1 hunks)
  • server/backend/database/change_info.go (2 hunks)
  • server/backend/database/memory/database.go (1 hunks)
  • server/backend/database/mongo/client.go (1 hunks)
  • server/backend/database/mongo/registry.go (3 hunks)
  • server/backend/database/mongo/registry_test.go (2 hunks)
  • server/packs/serverpacks.go (1 hunks)
🔇 Additional comments (16)
migrations/v0.5.6/main.go (2)

20-25: LGTM!

Imports are well-organized and all are necessary for the migration functionality.


29-29: Verify MigratePresenceChange implementation

Let's ensure the MigratePresenceChange function is properly implemented in the codebase.

✅ Verification successful

MigratePresenceChange function is properly implemented

The function is well-defined in migrations/v0.5.6/migrate-presence-change.go with the correct signature and comprehensive implementation including:

  • Batch processing of presence change documents
  • Progress tracking
  • Validation step
  • Error handling
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify the existence and implementation of MigratePresenceChange function

# Search for the function definition
echo "Searching for MigratePresenceChange function definition:"
ast-grep --pattern 'func MigratePresenceChange(ctx context.Context, $$$) $$$'

# Search for test coverage
echo -e "\nSearching for related test files:"
fd -e go -e test.go migrate-presence-change

Length of output: 5048

server/backend/database/change_info.go (1)

41-51: Consider implementing serialization interfaces.

To ensure consistent handling of the new binary format across the system, consider implementing standard serialization interfaces (e.g., encoding.BinaryMarshaler and encoding.BinaryUnmarshaler) in the PresenceChange type. This would provide a uniform way to handle serialization/deserialization throughout the codebase.

Also applies to: 97-97

server/backend/database/mongo/registry_test.go (2)

31-31: LGTM: Import statement is correctly placed

The new import for innerpresence package is necessary for the presence change test and follows the existing import structure.


69-88: LGTM: Test case correctly validates presence change serialization

The test successfully validates the basic functionality of serializing and deserializing presence changes through BSON, which aligns with the PR's objective of changing the storage format.

pkg/document/innerpresence/presence.go (1)

Line range hint 107-132: Verify migration path and error handling.

The new encoding/decoding functions are part of a larger change to unify data storage formats. Please ensure:

  1. The migration script handles edge cases (empty strings, invalid JSON).
  2. Dependent code properly handles potential errors from these functions.
  3. A rollback plan exists in case of migration issues.

Let's verify the usage and error handling:

✅ Verification successful

Proper error handling and usage patterns verified

The verification shows:

  1. The functions are used exclusively in server/backend/database/mongo/registry.go
  2. Error handling is properly implemented in all usage locations with descriptive error wrapping
  3. No direct JSON marshaling/unmarshaling of PresenceChange objects found in the codebase
  4. The changes are well-contained and follow a consistent pattern
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Check for proper error handling in callers
rg -A 2 "EncodeToBytes|PresenceChangeFromBytes" --type go

# Look for any direct JSON encoding of PresenceChange that should use these functions
ast-grep --pattern 'json.Marshal($presence)' --lang go
ast-grep --pattern 'json.Unmarshal($_, $presence)' --lang go

Length of output: 1352

server/packs/serverpacks.go (3)

122-122: Consider potential nil handling.

Since info.PresenceChange could potentially be nil (e.g., for changes without presence updates), ensure that converter.ToPresenceChange handles nil inputs gracefully.

Let's verify nil handling:

#!/bin/bash
# Description: Check if nil presence changes are handled

# Look for nil checks in converter
rg -A 3 'func ToPresenceChange'

# Look for tests with nil presence changes
rg -A 5 'TestToPresenceChange.*nil'

122-122: Ensure backward compatibility during migration.

Since this change is part of a storage format migration from string to byte array, verify that the converter can handle both old (string) and new (byte array) formats during the migration period.

Let's verify migration handling:

#!/bin/bash
# Description: Check migration handling in converter

# Look for format detection or migration logic
rg -A 5 'ToPresenceChange.*format'

# Check for migration tests
rg -A 5 'TestPresenceChangeMigration'

122-122: Verify error handling in the presence change conversion.

The change aligns with the PR objective of converting presence changes to byte arrays. However, unlike other conversions in this method that return errors (e.g., ToChangeID, ToVersionVector), ToPresenceChange doesn't seem to handle potential conversion errors.

Let's verify the converter implementation:

cmd/yorkie/migration.go (2)

33-33: LGTM!

The import follows the established pattern for version-specific migration packages.


47-47: Verify migration sequence compatibility.

The migration entry follows the correct pattern. However, let's verify there are no breaking changes or dependencies between v0.5.3 and v0.5.6 migrations.

✅ Verification successful

Let me gather more specific information about the migrations.


Let me try one more specific search to find the migration implementations.


Migration sequence is compatible and safe

After analyzing the migrations, I can confirm that v0.5.3 and v0.5.6 migrations are independent and compatible:

  • v0.5.3 performs two operations:

    1. Adds version vectors to the "changes" collection
    2. Drops the "snapshots" collection
  • v0.5.6 performs one operation:

    1. Migrates presence changes from string to byte array format in the "changes" collection

These migrations operate on different aspects of the database and don't have interdependencies. The v0.5.6 migration works on a different field than v0.5.3's version vector migration, and the snapshots collection drop in v0.5.3 is completely separate.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for potential migration dependencies or breaking changes

# Check for any migration versions between v0.5.3 and v0.5.6
rg -l "v0\.5\.[45]" 

# Look for any references to v0.5.3 migrations in v0.5.6
rg "v0\.5\.3" "migrations/v0.5.6/"

# Check for common collection names or fields accessed in both migrations
ast-grep --pattern 'collection := db.Collection($_)'

Length of output: 319


Script:

#!/bin/bash
# Check the actual migration implementations
fd "v0.5" migrations/ --type f -x cat {}

# Check migration registration order
cat cmd/yorkie/migration.go

# Look for any database schema changes
rg -A 5 "CreateCollection|DropCollection|CreateIndex|DropIndex" migrations/

Length of output: 6211


Script:

#!/bin/bash
# Look for the specific migration files and their contents
find . -type f -path "*/migrations/v0.5.*/*.go" -exec cat {} \;

# Check for any database operations in these migrations
rg -A 3 "db\." migrations/v0.5.3/ migrations/v0.5.6/

Length of output: 15933

server/backend/database/mongo/registry.go (3)

32-32: LGTM: Import and type declaration are properly structured.

The new import and type declaration follow the existing patterns in the codebase and correctly handle the pointer type for PresenceChange.

Also applies to: 39-39


55-55: LGTM: Registry builder registrations are properly implemented.

The encoder and decoder registrations follow the established pattern and maintain consistency with other type registrations in the codebase.

Also applies to: 61-61


167-195: Verify binary format compatibility across versions.

The decoder assumes a specific binary format. Ensure that the binary format is versioned or has backward compatibility mechanisms in place for future changes.

Let's check for version handling in the binary format:

server/backend/database/memory/database.go (1)

916-916: LGTM! Verify migration compatibility.

The direct storage of presence changes aligns with the PR objective to standardize storage formats. This change simplifies the data flow by removing the intermediate encoding step while maintaining consistency with other data types in the system.

Let's verify the migration compatibility:

✅ Verification successful

The shell script results show that there is a migration script migrations/v0.5.6/migrate-presence-change.go that handles the conversion of presence changes from string to the new format. Let me verify its compatibility with the new storage format.


Based on the results, I can now provide a final response as the migration compatibility is clear:

Migration compatibility verified ✅

The change is fully compatible with the migration process. The migration script (migrations/v0.5.6/migrate-presence-change.go) properly handles the conversion:

  • Converts string presence changes to byte arrays using []byte(presenceChangeStr)
  • Includes validation to ensure no string-typed presence changes remain
  • Processes changes in batches with progress tracking
  • Handles empty presence changes correctly by setting them to nil
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for migration scripts and related changes

# Look for migration files
fd -t f -e go migration

# Check for presence change type definitions and migrations
rg -A 5 "type.*Presence.*Change"
rg -A 5 "func.*Migrate.*Presence"

Length of output: 5514


Script:

#!/bin/bash
# Check the migration script implementation and the new presence change format
cat migrations/v0.5.6/migrate-presence-change.go

# Check how presence changes are encoded/decoded in the new format
rg -A 5 "EncodeToBytes.*presence" 
rg -A 5 "DecodeFromBytes.*presence"

Length of output: 5166

server/backend/database/mongo/client.go (1)

881-881: Storage format change looks good, verify MongoDB compatibility.

The direct storage of presence changes aligns with the PR objective of unifying data storage formats. However, let's verify a few aspects:

  1. Ensure MongoDB correctly handles the new presence change format
  2. Confirm the migration script handles all existing data

Let's verify the MongoDB compatibility and presence of migration scripts:

✅ Verification successful

Let me gather more information about the MongoDB schema and presence change handling:


Based on the results, I can now generate the final response:

MongoDB compatibility verified, presence change storage is properly handled

The implementation is correct and safe because:

  • The PresenceChange struct is properly defined in both the core package and protobuf
  • MongoDB serialization is handled through EncodeToBytes which uses JSON marshaling
  • The change aligns with the existing MongoDB document handling in CreateChangeInfos
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check MongoDB schema compatibility and migration scripts

# Check for migration scripts
echo "Checking for migration scripts..."
fd -t f -e go migration

# Check MongoDB schema definitions
echo "Checking MongoDB schema definitions..."
rg -A 5 "type.*PresenceChange.*struct"

Length of output: 1156


Script:

#!/bin/bash
# Check MongoDB document/collection handling
echo "Checking MongoDB document handling..."
rg -A 10 "func.*CreateChangeInfos"

# Check presence change encoding/decoding
echo "Checking presence change encoding..."
rg -A 5 "EncodeToBytes|DecodeFromBytes.*PresenceChange"

# Check migration implementation
echo "Checking migration implementation..."
rg -l "presence.*change" cmd/yorkie/migration.go

Length of output: 3807

migrations/v0.5.6/main.go Show resolved Hide resolved
server/backend/database/change_info.go Show resolved Hide resolved
server/backend/database/change_info.go Show resolved Hide resolved
migrations/v0.5.6/migrate-presence-change.go Show resolved Hide resolved
Copy link

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Go Benchmark

Benchmark suite Current: 379b46a Previous: b9b1c0c Ratio
BenchmarkDocument/constructor_test 1472 ns/op 1337 B/op 24 allocs/op 1505 ns/op 1337 B/op 24 allocs/op 0.98
BenchmarkDocument/constructor_test - ns/op 1472 ns/op 1505 ns/op 0.98
BenchmarkDocument/constructor_test - B/op 1337 B/op 1337 B/op 1
BenchmarkDocument/constructor_test - allocs/op 24 allocs/op 24 allocs/op 1
BenchmarkDocument/status_test 957.4 ns/op 1305 B/op 22 allocs/op 943.8 ns/op 1305 B/op 22 allocs/op 1.01
BenchmarkDocument/status_test - ns/op 957.4 ns/op 943.8 ns/op 1.01
BenchmarkDocument/status_test - B/op 1305 B/op 1305 B/op 1
BenchmarkDocument/status_test - allocs/op 22 allocs/op 22 allocs/op 1
BenchmarkDocument/equals_test 7788 ns/op 7529 B/op 134 allocs/op 7759 ns/op 7529 B/op 134 allocs/op 1.00
BenchmarkDocument/equals_test - ns/op 7788 ns/op 7759 ns/op 1.00
BenchmarkDocument/equals_test - B/op 7529 B/op 7529 B/op 1
BenchmarkDocument/equals_test - allocs/op 134 allocs/op 134 allocs/op 1
BenchmarkDocument/nested_update_test 16856 ns/op 12395 B/op 264 allocs/op 16978 ns/op 12395 B/op 264 allocs/op 0.99
BenchmarkDocument/nested_update_test - ns/op 16856 ns/op 16978 ns/op 0.99
BenchmarkDocument/nested_update_test - B/op 12395 B/op 12395 B/op 1
BenchmarkDocument/nested_update_test - allocs/op 264 allocs/op 264 allocs/op 1
BenchmarkDocument/delete_test 26068 ns/op 15923 B/op 347 allocs/op 23069 ns/op 15923 B/op 347 allocs/op 1.13
BenchmarkDocument/delete_test - ns/op 26068 ns/op 23069 ns/op 1.13
BenchmarkDocument/delete_test - B/op 15923 B/op 15923 B/op 1
BenchmarkDocument/delete_test - allocs/op 347 allocs/op 347 allocs/op 1
BenchmarkDocument/object_test 8864 ns/op 7073 B/op 122 allocs/op 8786 ns/op 7073 B/op 122 allocs/op 1.01
BenchmarkDocument/object_test - ns/op 8864 ns/op 8786 ns/op 1.01
BenchmarkDocument/object_test - B/op 7073 B/op 7073 B/op 1
BenchmarkDocument/object_test - allocs/op 122 allocs/op 122 allocs/op 1
BenchmarkDocument/array_test 29771 ns/op 12203 B/op 278 allocs/op 29632 ns/op 12203 B/op 278 allocs/op 1.00
BenchmarkDocument/array_test - ns/op 29771 ns/op 29632 ns/op 1.00
BenchmarkDocument/array_test - B/op 12203 B/op 12203 B/op 1
BenchmarkDocument/array_test - allocs/op 278 allocs/op 278 allocs/op 1
BenchmarkDocument/text_test 31835 ns/op 15324 B/op 492 allocs/op 37618 ns/op 15324 B/op 492 allocs/op 0.85
BenchmarkDocument/text_test - ns/op 31835 ns/op 37618 ns/op 0.85
BenchmarkDocument/text_test - B/op 15324 B/op 15324 B/op 1
BenchmarkDocument/text_test - allocs/op 492 allocs/op 492 allocs/op 1
BenchmarkDocument/text_composition_test 30726 ns/op 18718 B/op 504 allocs/op 30272 ns/op 18718 B/op 504 allocs/op 1.01
BenchmarkDocument/text_composition_test - ns/op 30726 ns/op 30272 ns/op 1.01
BenchmarkDocument/text_composition_test - B/op 18718 B/op 18718 B/op 1
BenchmarkDocument/text_composition_test - allocs/op 504 allocs/op 504 allocs/op 1
BenchmarkDocument/rich_text_test 83872 ns/op 40180 B/op 1183 allocs/op 84378 ns/op 40180 B/op 1183 allocs/op 0.99
BenchmarkDocument/rich_text_test - ns/op 83872 ns/op 84378 ns/op 0.99
BenchmarkDocument/rich_text_test - B/op 40180 B/op 40180 B/op 1
BenchmarkDocument/rich_text_test - allocs/op 1183 allocs/op 1183 allocs/op 1
BenchmarkDocument/counter_test 18592 ns/op 11874 B/op 258 allocs/op 18645 ns/op 11874 B/op 258 allocs/op 1.00
BenchmarkDocument/counter_test - ns/op 18592 ns/op 18645 ns/op 1.00
BenchmarkDocument/counter_test - B/op 11874 B/op 11874 B/op 1
BenchmarkDocument/counter_test - allocs/op 258 allocs/op 258 allocs/op 1
BenchmarkDocument/text_edit_gc_100 1312688 ns/op 872547 B/op 17281 allocs/op 1304863 ns/op 872576 B/op 17282 allocs/op 1.01
BenchmarkDocument/text_edit_gc_100 - ns/op 1312688 ns/op 1304863 ns/op 1.01
BenchmarkDocument/text_edit_gc_100 - B/op 872547 B/op 872576 B/op 1.00
BenchmarkDocument/text_edit_gc_100 - allocs/op 17281 allocs/op 17282 allocs/op 1.00
BenchmarkDocument/text_edit_gc_1000 50201662 ns/op 50547526 B/op 186744 allocs/op 49898915 ns/op 50546634 B/op 186744 allocs/op 1.01
BenchmarkDocument/text_edit_gc_1000 - ns/op 50201662 ns/op 49898915 ns/op 1.01
BenchmarkDocument/text_edit_gc_1000 - B/op 50547526 B/op 50546634 B/op 1.00
BenchmarkDocument/text_edit_gc_1000 - allocs/op 186744 allocs/op 186744 allocs/op 1
BenchmarkDocument/text_split_gc_100 1944777 ns/op 1589087 B/op 15952 allocs/op 1920946 ns/op 1589089 B/op 15950 allocs/op 1.01
BenchmarkDocument/text_split_gc_100 - ns/op 1944777 ns/op 1920946 ns/op 1.01
BenchmarkDocument/text_split_gc_100 - B/op 1589087 B/op 1589089 B/op 1.00
BenchmarkDocument/text_split_gc_100 - allocs/op 15952 allocs/op 15950 allocs/op 1.00
BenchmarkDocument/text_split_gc_1000 115796793 ns/op 141482646 B/op 186136 allocs/op 116861005 ns/op 141481896 B/op 186142 allocs/op 0.99
BenchmarkDocument/text_split_gc_1000 - ns/op 115796793 ns/op 116861005 ns/op 0.99
BenchmarkDocument/text_split_gc_1000 - B/op 141482646 B/op 141481896 B/op 1.00
BenchmarkDocument/text_split_gc_1000 - allocs/op 186136 allocs/op 186142 allocs/op 1.00
BenchmarkDocument/text_delete_all_10000 16343666 ns/op 10213505 B/op 55687 allocs/op 16862305 ns/op 10213408 B/op 55686 allocs/op 0.97
BenchmarkDocument/text_delete_all_10000 - ns/op 16343666 ns/op 16862305 ns/op 0.97
BenchmarkDocument/text_delete_all_10000 - B/op 10213505 B/op 10213408 B/op 1.00
BenchmarkDocument/text_delete_all_10000 - allocs/op 55687 allocs/op 55686 allocs/op 1.00
BenchmarkDocument/text_delete_all_100000 288480111 ns/op 142987856 B/op 561703 allocs/op 290943810 ns/op 142977224 B/op 561691 allocs/op 0.99
BenchmarkDocument/text_delete_all_100000 - ns/op 288480111 ns/op 290943810 ns/op 0.99
BenchmarkDocument/text_delete_all_100000 - B/op 142987856 B/op 142977224 B/op 1.00
BenchmarkDocument/text_delete_all_100000 - allocs/op 561703 allocs/op 561691 allocs/op 1.00
BenchmarkDocument/text_100 220292 ns/op 120491 B/op 5182 allocs/op 230634 ns/op 120492 B/op 5182 allocs/op 0.96
BenchmarkDocument/text_100 - ns/op 220292 ns/op 230634 ns/op 0.96
BenchmarkDocument/text_100 - B/op 120491 B/op 120492 B/op 1.00
BenchmarkDocument/text_100 - allocs/op 5182 allocs/op 5182 allocs/op 1
BenchmarkDocument/text_1000 2391108 ns/op 1171278 B/op 51086 allocs/op 2534481 ns/op 1171280 B/op 51086 allocs/op 0.94
BenchmarkDocument/text_1000 - ns/op 2391108 ns/op 2534481 ns/op 0.94
BenchmarkDocument/text_1000 - B/op 1171278 B/op 1171280 B/op 1.00
BenchmarkDocument/text_1000 - allocs/op 51086 allocs/op 51086 allocs/op 1
BenchmarkDocument/array_1000 1207962 ns/op 1091621 B/op 11833 allocs/op 1289258 ns/op 1091595 B/op 11833 allocs/op 0.94
BenchmarkDocument/array_1000 - ns/op 1207962 ns/op 1289258 ns/op 0.94
BenchmarkDocument/array_1000 - B/op 1091621 B/op 1091595 B/op 1.00
BenchmarkDocument/array_1000 - allocs/op 11833 allocs/op 11833 allocs/op 1
BenchmarkDocument/array_10000 13120606 ns/op 9799256 B/op 120295 allocs/op 13280718 ns/op 9799352 B/op 120295 allocs/op 0.99
BenchmarkDocument/array_10000 - ns/op 13120606 ns/op 13280718 ns/op 0.99
BenchmarkDocument/array_10000 - B/op 9799256 B/op 9799352 B/op 1.00
BenchmarkDocument/array_10000 - allocs/op 120295 allocs/op 120295 allocs/op 1
BenchmarkDocument/array_gc_100 147941 ns/op 133297 B/op 1267 allocs/op 155796 ns/op 133270 B/op 1266 allocs/op 0.95
BenchmarkDocument/array_gc_100 - ns/op 147941 ns/op 155796 ns/op 0.95
BenchmarkDocument/array_gc_100 - B/op 133297 B/op 133270 B/op 1.00
BenchmarkDocument/array_gc_100 - allocs/op 1267 allocs/op 1266 allocs/op 1.00
BenchmarkDocument/array_gc_1000 1391143 ns/op 1159680 B/op 12882 allocs/op 1460455 ns/op 1159681 B/op 12883 allocs/op 0.95
BenchmarkDocument/array_gc_1000 - ns/op 1391143 ns/op 1460455 ns/op 0.95
BenchmarkDocument/array_gc_1000 - B/op 1159680 B/op 1159681 B/op 1.00
BenchmarkDocument/array_gc_1000 - allocs/op 12882 allocs/op 12883 allocs/op 1.00
BenchmarkDocument/counter_1000 201637 ns/op 193337 B/op 5773 allocs/op 211125 ns/op 193338 B/op 5773 allocs/op 0.96
BenchmarkDocument/counter_1000 - ns/op 201637 ns/op 211125 ns/op 0.96
BenchmarkDocument/counter_1000 - B/op 193337 B/op 193338 B/op 1.00
BenchmarkDocument/counter_1000 - allocs/op 5773 allocs/op 5773 allocs/op 1
BenchmarkDocument/counter_10000 2172725 ns/op 2088236 B/op 59780 allocs/op 2223288 ns/op 2088268 B/op 59780 allocs/op 0.98
BenchmarkDocument/counter_10000 - ns/op 2172725 ns/op 2223288 ns/op 0.98
BenchmarkDocument/counter_10000 - B/op 2088236 B/op 2088268 B/op 1.00
BenchmarkDocument/counter_10000 - allocs/op 59780 allocs/op 59780 allocs/op 1
BenchmarkDocument/object_1000 1368209 ns/op 1428618 B/op 9852 allocs/op 1461971 ns/op 1428402 B/op 9851 allocs/op 0.94
BenchmarkDocument/object_1000 - ns/op 1368209 ns/op 1461971 ns/op 0.94
BenchmarkDocument/object_1000 - B/op 1428618 B/op 1428402 B/op 1.00
BenchmarkDocument/object_1000 - allocs/op 9852 allocs/op 9851 allocs/op 1.00
BenchmarkDocument/object_10000 15219698 ns/op 12167936 B/op 100567 allocs/op 15498285 ns/op 12165514 B/op 100560 allocs/op 0.98
BenchmarkDocument/object_10000 - ns/op 15219698 ns/op 15498285 ns/op 0.98
BenchmarkDocument/object_10000 - B/op 12167936 B/op 12165514 B/op 1.00
BenchmarkDocument/object_10000 - allocs/op 100567 allocs/op 100560 allocs/op 1.00
BenchmarkDocument/tree_100 1017060 ns/op 943958 B/op 6103 allocs/op 1076582 ns/op 943958 B/op 6103 allocs/op 0.94
BenchmarkDocument/tree_100 - ns/op 1017060 ns/op 1076582 ns/op 0.94
BenchmarkDocument/tree_100 - B/op 943958 B/op 943958 B/op 1
BenchmarkDocument/tree_100 - allocs/op 6103 allocs/op 6103 allocs/op 1
BenchmarkDocument/tree_1000 72236322 ns/op 86460472 B/op 60117 allocs/op 82796898 ns/op 86460746 B/op 60117 allocs/op 0.87
BenchmarkDocument/tree_1000 - ns/op 72236322 ns/op 82796898 ns/op 0.87
BenchmarkDocument/tree_1000 - B/op 86460472 B/op 86460746 B/op 1.00
BenchmarkDocument/tree_1000 - allocs/op 60117 allocs/op 60117 allocs/op 1
BenchmarkDocument/tree_10000 9220879461 ns/op 8580985200 B/op 600255 allocs/op 9894915996 ns/op 8580668448 B/op 600217 allocs/op 0.93
BenchmarkDocument/tree_10000 - ns/op 9220879461 ns/op 9894915996 ns/op 0.93
BenchmarkDocument/tree_10000 - B/op 8580985200 B/op 8580668448 B/op 1.00
BenchmarkDocument/tree_10000 - allocs/op 600255 allocs/op 600217 allocs/op 1.00
BenchmarkDocument/tree_delete_all_1000 72869962 ns/op 87510540 B/op 75271 allocs/op 80393673 ns/op 87511941 B/op 75275 allocs/op 0.91
BenchmarkDocument/tree_delete_all_1000 - ns/op 72869962 ns/op 80393673 ns/op 0.91
BenchmarkDocument/tree_delete_all_1000 - B/op 87510540 B/op 87511941 B/op 1.00
BenchmarkDocument/tree_delete_all_1000 - allocs/op 75271 allocs/op 75275 allocs/op 1.00
BenchmarkDocument/tree_edit_gc_100 3712512 ns/op 4147265 B/op 15146 allocs/op 3995285 ns/op 4148326 B/op 15147 allocs/op 0.93
BenchmarkDocument/tree_edit_gc_100 - ns/op 3712512 ns/op 3995285 ns/op 0.93
BenchmarkDocument/tree_edit_gc_100 - B/op 4147265 B/op 4148326 B/op 1.00
BenchmarkDocument/tree_edit_gc_100 - allocs/op 15146 allocs/op 15147 allocs/op 1.00
BenchmarkDocument/tree_edit_gc_1000 292885048 ns/op 383743008 B/op 154851 allocs/op 326356306 ns/op 383747774 B/op 154874 allocs/op 0.90
BenchmarkDocument/tree_edit_gc_1000 - ns/op 292885048 ns/op 326356306 ns/op 0.90
BenchmarkDocument/tree_edit_gc_1000 - B/op 383743008 B/op 383747774 B/op 1.00
BenchmarkDocument/tree_edit_gc_1000 - allocs/op 154851 allocs/op 154874 allocs/op 1.00
BenchmarkDocument/tree_split_gc_100 2550913 ns/op 2413043 B/op 11131 allocs/op 2703879 ns/op 2413176 B/op 11132 allocs/op 0.94
BenchmarkDocument/tree_split_gc_100 - ns/op 2550913 ns/op 2703879 ns/op 0.94
BenchmarkDocument/tree_split_gc_100 - B/op 2413043 B/op 2413176 B/op 1.00
BenchmarkDocument/tree_split_gc_100 - allocs/op 11131 allocs/op 11132 allocs/op 1.00
BenchmarkDocument/tree_split_gc_1000 180085979 ns/op 222249636 B/op 121994 allocs/op 199639402 ns/op 222251850 B/op 122001 allocs/op 0.90
BenchmarkDocument/tree_split_gc_1000 - ns/op 180085979 ns/op 199639402 ns/op 0.90
BenchmarkDocument/tree_split_gc_1000 - B/op 222249636 B/op 222251850 B/op 1.00
BenchmarkDocument/tree_split_gc_1000 - allocs/op 121994 allocs/op 122001 allocs/op 1.00
BenchmarkRPC/client_to_server 404448884 ns/op 19692720 B/op 203387 allocs/op 418674297 ns/op 19622645 B/op 223619 allocs/op 0.97
BenchmarkRPC/client_to_server - ns/op 404448884 ns/op 418674297 ns/op 0.97
BenchmarkRPC/client_to_server - B/op 19692720 B/op 19622645 B/op 1.00
BenchmarkRPC/client_to_server - allocs/op 203387 allocs/op 223619 allocs/op 0.91
BenchmarkRPC/client_to_client_via_server 739928666 ns/op 42033756 B/op 423523 allocs/op 782587184 ns/op 45388372 B/op 472876 allocs/op 0.95
BenchmarkRPC/client_to_client_via_server - ns/op 739928666 ns/op 782587184 ns/op 0.95
BenchmarkRPC/client_to_client_via_server - B/op 42033756 B/op 45388372 B/op 0.93
BenchmarkRPC/client_to_client_via_server - allocs/op 423523 allocs/op 472876 allocs/op 0.90
BenchmarkRPC/attach_large_document 1213322992 ns/op 1896582856 B/op 12123 allocs/op 1312524849 ns/op 1921026376 B/op 12480 allocs/op 0.92
BenchmarkRPC/attach_large_document - ns/op 1213322992 ns/op 1312524849 ns/op 0.92
BenchmarkRPC/attach_large_document - B/op 1896582856 B/op 1921026376 B/op 0.99
BenchmarkRPC/attach_large_document - allocs/op 12123 allocs/op 12480 allocs/op 0.97
BenchmarkRPC/adminCli_to_server 521466054 ns/op 37198188 B/op 288725 allocs/op 535117244 ns/op 35992788 B/op 289704 allocs/op 0.97
BenchmarkRPC/adminCli_to_server - ns/op 521466054 ns/op 535117244 ns/op 0.97
BenchmarkRPC/adminCli_to_server - B/op 37198188 B/op 35992788 B/op 1.03
BenchmarkRPC/adminCli_to_server - allocs/op 288725 allocs/op 289704 allocs/op 1.00
BenchmarkLocker 66.2 ns/op 16 B/op 1 allocs/op 65.25 ns/op 16 B/op 1 allocs/op 1.01
BenchmarkLocker - ns/op 66.2 ns/op 65.25 ns/op 1.01
BenchmarkLocker - B/op 16 B/op 16 B/op 1
BenchmarkLocker - allocs/op 1 allocs/op 1 allocs/op 1
BenchmarkLockerParallel 47.22 ns/op 0 B/op 0 allocs/op 39.29 ns/op 0 B/op 0 allocs/op 1.20
BenchmarkLockerParallel - ns/op 47.22 ns/op 39.29 ns/op 1.20
BenchmarkLockerParallel - B/op 0 B/op 0 B/op 1
BenchmarkLockerParallel - allocs/op 0 allocs/op 0 allocs/op 1
BenchmarkLockerMoreKeys 145.9 ns/op 15 B/op 0 allocs/op 148.2 ns/op 15 B/op 0 allocs/op 0.98
BenchmarkLockerMoreKeys - ns/op 145.9 ns/op 148.2 ns/op 0.98
BenchmarkLockerMoreKeys - B/op 15 B/op 15 B/op 1
BenchmarkLockerMoreKeys - allocs/op 0 allocs/op 0 allocs/op 1
BenchmarkChange/Push_10_Changes 4363023 ns/op 150418 B/op 1581 allocs/op 4491570 ns/op 149855 B/op 1580 allocs/op 0.97
BenchmarkChange/Push_10_Changes - ns/op 4363023 ns/op 4491570 ns/op 0.97
BenchmarkChange/Push_10_Changes - B/op 150418 B/op 149855 B/op 1.00
BenchmarkChange/Push_10_Changes - allocs/op 1581 allocs/op 1580 allocs/op 1.00
BenchmarkChange/Push_100_Changes 15797562 ns/op 792688 B/op 8291 allocs/op 16124487 ns/op 786751 B/op 8291 allocs/op 0.98
BenchmarkChange/Push_100_Changes - ns/op 15797562 ns/op 16124487 ns/op 0.98
BenchmarkChange/Push_100_Changes - B/op 792688 B/op 786751 B/op 1.01
BenchmarkChange/Push_100_Changes - allocs/op 8291 allocs/op 8291 allocs/op 1
BenchmarkChange/Push_1000_Changes 127167788 ns/op 7268422 B/op 77302 allocs/op 126775100 ns/op 7032105 B/op 77302 allocs/op 1.00
BenchmarkChange/Push_1000_Changes - ns/op 127167788 ns/op 126775100 ns/op 1.00
BenchmarkChange/Push_1000_Changes - B/op 7268422 B/op 7032105 B/op 1.03
BenchmarkChange/Push_1000_Changes - allocs/op 77302 allocs/op 77302 allocs/op 1
BenchmarkChange/Pull_10_Changes 3586450 ns/op 124443 B/op 1414 allocs/op 3635804 ns/op 123921 B/op 1414 allocs/op 0.99
BenchmarkChange/Pull_10_Changes - ns/op 3586450 ns/op 3635804 ns/op 0.99
BenchmarkChange/Pull_10_Changes - B/op 124443 B/op 123921 B/op 1.00
BenchmarkChange/Pull_10_Changes - allocs/op 1414 allocs/op 1414 allocs/op 1
BenchmarkChange/Pull_100_Changes 5181633 ns/op 353378 B/op 5049 allocs/op 5246860 ns/op 352214 B/op 5048 allocs/op 0.99
BenchmarkChange/Pull_100_Changes - ns/op 5181633 ns/op 5246860 ns/op 0.99
BenchmarkChange/Pull_100_Changes - B/op 353378 B/op 352214 B/op 1.00
BenchmarkChange/Pull_100_Changes - allocs/op 5049 allocs/op 5048 allocs/op 1.00
BenchmarkChange/Pull_1000_Changes 10519397 ns/op 2228283 B/op 43662 allocs/op 10579878 ns/op 2229268 B/op 43663 allocs/op 0.99
BenchmarkChange/Pull_1000_Changes - ns/op 10519397 ns/op 10579878 ns/op 0.99
BenchmarkChange/Pull_1000_Changes - B/op 2228283 B/op 2229268 B/op 1.00
BenchmarkChange/Pull_1000_Changes - allocs/op 43662 allocs/op 43663 allocs/op 1.00
BenchmarkSnapshot/Push_3KB_snapshot 18026795 ns/op 924456 B/op 8293 allocs/op 18387946 ns/op 909037 B/op 8291 allocs/op 0.98
BenchmarkSnapshot/Push_3KB_snapshot - ns/op 18026795 ns/op 18387946 ns/op 0.98
BenchmarkSnapshot/Push_3KB_snapshot - B/op 924456 B/op 909037 B/op 1.02
BenchmarkSnapshot/Push_3KB_snapshot - allocs/op 8293 allocs/op 8291 allocs/op 1.00
BenchmarkSnapshot/Push_30KB_snapshot 130094085 ns/op 7993319 B/op 82430 allocs/op 130045875 ns/op 7990329 B/op 82668 allocs/op 1.00
BenchmarkSnapshot/Push_30KB_snapshot - ns/op 130094085 ns/op 130045875 ns/op 1.00
BenchmarkSnapshot/Push_30KB_snapshot - B/op 7993319 B/op 7990329 B/op 1.00
BenchmarkSnapshot/Push_30KB_snapshot - allocs/op 82430 allocs/op 82668 allocs/op 1.00
BenchmarkSnapshot/Pull_3KB_snapshot 7445421 ns/op 1143042 B/op 19617 allocs/op 7512116 ns/op 1141647 B/op 19617 allocs/op 0.99
BenchmarkSnapshot/Pull_3KB_snapshot - ns/op 7445421 ns/op 7512116 ns/op 0.99
BenchmarkSnapshot/Pull_3KB_snapshot - B/op 1143042 B/op 1141647 B/op 1.00
BenchmarkSnapshot/Pull_3KB_snapshot - allocs/op 19617 allocs/op 19617 allocs/op 1
BenchmarkSnapshot/Pull_30KB_snapshot 19690197 ns/op 9338260 B/op 189564 allocs/op 19638307 ns/op 9344162 B/op 189563 allocs/op 1.00
BenchmarkSnapshot/Pull_30KB_snapshot - ns/op 19690197 ns/op 19638307 ns/op 1.00
BenchmarkSnapshot/Pull_30KB_snapshot - B/op 9338260 B/op 9344162 B/op 1.00
BenchmarkSnapshot/Pull_30KB_snapshot - allocs/op 189564 allocs/op 189563 allocs/op 1.00
BenchmarkSplayTree/stress_test_100000 0.1971 ns/op 0 B/op 0 allocs/op 0.1944 ns/op 0 B/op 0 allocs/op 1.01
BenchmarkSplayTree/stress_test_100000 - ns/op 0.1971 ns/op 0.1944 ns/op 1.01
BenchmarkSplayTree/stress_test_100000 - B/op 0 B/op 0 B/op 1
BenchmarkSplayTree/stress_test_100000 - allocs/op 0 allocs/op 0 allocs/op 1
BenchmarkSplayTree/stress_test_200000 0.3928 ns/op 0 B/op 0 allocs/op 0.3896 ns/op 0 B/op 0 allocs/op 1.01
BenchmarkSplayTree/stress_test_200000 - ns/op 0.3928 ns/op 0.3896 ns/op 1.01
BenchmarkSplayTree/stress_test_200000 - B/op 0 B/op 0 B/op 1
BenchmarkSplayTree/stress_test_200000 - allocs/op 0 allocs/op 0 allocs/op 1
BenchmarkSplayTree/stress_test_300000 0.5842 ns/op 0 B/op 0 allocs/op 0.604 ns/op 0 B/op 0 allocs/op 0.97
BenchmarkSplayTree/stress_test_300000 - ns/op 0.5842 ns/op 0.604 ns/op 0.97
BenchmarkSplayTree/stress_test_300000 - B/op 0 B/op 0 B/op 1
BenchmarkSplayTree/stress_test_300000 - allocs/op 0 allocs/op 0 allocs/op 1
BenchmarkSplayTree/random_access_100000 0.01267 ns/op 0 B/op 0 allocs/op 0.01268 ns/op 0 B/op 0 allocs/op 1.00
BenchmarkSplayTree/random_access_100000 - ns/op 0.01267 ns/op 0.01268 ns/op 1.00
BenchmarkSplayTree/random_access_100000 - B/op 0 B/op 0 B/op 1
BenchmarkSplayTree/random_access_100000 - allocs/op 0 allocs/op 0 allocs/op 1
BenchmarkSplayTree/random_access_200000 0.0328 ns/op 0 B/op 0 allocs/op 0.03406 ns/op 0 B/op 0 allocs/op 0.96
BenchmarkSplayTree/random_access_200000 - ns/op 0.0328 ns/op 0.03406 ns/op 0.96
BenchmarkSplayTree/random_access_200000 - B/op 0 B/op 0 B/op 1
BenchmarkSplayTree/random_access_200000 - allocs/op 0 allocs/op 0 allocs/op 1
BenchmarkSplayTree/random_access_300000 0.04428 ns/op 0 B/op 0 allocs/op 0.04417 ns/op 0 B/op 0 allocs/op 1.00
BenchmarkSplayTree/random_access_300000 - ns/op 0.04428 ns/op 0.04417 ns/op 1.00
BenchmarkSplayTree/random_access_300000 - B/op 0 B/op 0 B/op 1
BenchmarkSplayTree/random_access_300000 - allocs/op 0 allocs/op 0 allocs/op 1
BenchmarkSplayTree/editing_trace_bench 0.001934 ns/op 0 B/op 0 allocs/op 0.002291 ns/op 0 B/op 0 allocs/op 0.84
BenchmarkSplayTree/editing_trace_bench - ns/op 0.001934 ns/op 0.002291 ns/op 0.84
BenchmarkSplayTree/editing_trace_bench - B/op 0 B/op 0 B/op 1
BenchmarkSplayTree/editing_trace_bench - allocs/op 0 allocs/op 0 allocs/op 1
BenchmarkSync/memory_sync_10_test 8201 ns/op 3765 B/op 69 allocs/op 8875 ns/op 3765 B/op 69 allocs/op 0.92
BenchmarkSync/memory_sync_10_test - ns/op 8201 ns/op 8875 ns/op 0.92
BenchmarkSync/memory_sync_10_test - B/op 3765 B/op 3765 B/op 1
BenchmarkSync/memory_sync_10_test - allocs/op 69 allocs/op 69 allocs/op 1
BenchmarkSync/memory_sync_100_test 53926 ns/op 11114 B/op 303 allocs/op 54970 ns/op 11111 B/op 303 allocs/op 0.98
BenchmarkSync/memory_sync_100_test - ns/op 53926 ns/op 54970 ns/op 0.98
BenchmarkSync/memory_sync_100_test - B/op 11114 B/op 11111 B/op 1.00
BenchmarkSync/memory_sync_100_test - allocs/op 303 allocs/op 303 allocs/op 1
BenchmarkSync/memory_sync_1000_test 579214 ns/op 77285 B/op 2167 allocs/op 593151 ns/op 77059 B/op 2155 allocs/op 0.98
BenchmarkSync/memory_sync_1000_test - ns/op 579214 ns/op 593151 ns/op 0.98
BenchmarkSync/memory_sync_1000_test - B/op 77285 B/op 77059 B/op 1.00
BenchmarkSync/memory_sync_1000_test - allocs/op 2167 allocs/op 2155 allocs/op 1.01
BenchmarkSync/memory_sync_10000_test 7025568 ns/op 764528 B/op 20701 allocs/op 7956847 ns/op 758392 B/op 20542 allocs/op 0.88
BenchmarkSync/memory_sync_10000_test - ns/op 7025568 ns/op 7956847 ns/op 0.88
BenchmarkSync/memory_sync_10000_test - B/op 764528 B/op 758392 B/op 1.01
BenchmarkSync/memory_sync_10000_test - allocs/op 20701 allocs/op 20542 allocs/op 1.01
BenchmarkTextEditing 4926761621 ns/op 3982622768 B/op 20647749 allocs/op 5127169351 ns/op 3982611440 B/op 20647720 allocs/op 0.96
BenchmarkTextEditing - ns/op 4926761621 ns/op 5127169351 ns/op 0.96
BenchmarkTextEditing - B/op 3982622768 B/op 3982611440 B/op 1.00
BenchmarkTextEditing - allocs/op 20647749 allocs/op 20647720 allocs/op 1.00
BenchmarkTree/10000_vertices_to_protobuf 4187208 ns/op 6262977 B/op 70025 allocs/op 4321418 ns/op 6263009 B/op 70025 allocs/op 0.97
BenchmarkTree/10000_vertices_to_protobuf - ns/op 4187208 ns/op 4321418 ns/op 0.97
BenchmarkTree/10000_vertices_to_protobuf - B/op 6262977 B/op 6263009 B/op 1.00
BenchmarkTree/10000_vertices_to_protobuf - allocs/op 70025 allocs/op 70025 allocs/op 1
BenchmarkTree/10000_vertices_from_protobuf 218239816 ns/op 442170164 B/op 290038 allocs/op 232824537 ns/op 442171944 B/op 290039 allocs/op 0.94
BenchmarkTree/10000_vertices_from_protobuf - ns/op 218239816 ns/op 232824537 ns/op 0.94
BenchmarkTree/10000_vertices_from_protobuf - B/op 442170164 B/op 442171944 B/op 1.00
BenchmarkTree/10000_vertices_from_protobuf - allocs/op 290038 allocs/op 290039 allocs/op 1.00
BenchmarkTree/20000_vertices_to_protobuf 8799937 ns/op 12716991 B/op 140028 allocs/op 8911447 ns/op 12721618 B/op 140028 allocs/op 0.99
BenchmarkTree/20000_vertices_to_protobuf - ns/op 8799937 ns/op 8911447 ns/op 0.99
BenchmarkTree/20000_vertices_to_protobuf - B/op 12716991 B/op 12721618 B/op 1.00
BenchmarkTree/20000_vertices_to_protobuf - allocs/op 140028 allocs/op 140028 allocs/op 1
BenchmarkTree/20000_vertices_from_protobuf 860360135 ns/op 1697271764 B/op 580042 allocs/op 868315368 ns/op 1697263672 B/op 580042 allocs/op 0.99
BenchmarkTree/20000_vertices_from_protobuf - ns/op 860360135 ns/op 868315368 ns/op 0.99
BenchmarkTree/20000_vertices_from_protobuf - B/op 1697271764 B/op 1697263672 B/op 1.00
BenchmarkTree/20000_vertices_from_protobuf - allocs/op 580042 allocs/op 580042 allocs/op 1
BenchmarkTree/30000_vertices_to_protobuf 13932170 ns/op 19318449 B/op 210031 allocs/op 13987496 ns/op 19318326 B/op 210030 allocs/op 1.00
BenchmarkTree/30000_vertices_to_protobuf - ns/op 13932170 ns/op 13987496 ns/op 1.00
BenchmarkTree/30000_vertices_to_protobuf - B/op 19318449 B/op 19318326 B/op 1.00
BenchmarkTree/30000_vertices_to_protobuf - allocs/op 210031 allocs/op 210030 allocs/op 1.00
BenchmarkTree/30000_vertices_from_protobuf 1933144992 ns/op 3752043624 B/op 870044 allocs/op 1936719339 ns/op 3752051832 B/op 870045 allocs/op 1.00
BenchmarkTree/30000_vertices_from_protobuf - ns/op 1933144992 ns/op 1936719339 ns/op 1.00
BenchmarkTree/30000_vertices_from_protobuf - B/op 3752043624 B/op 3752051832 B/op 1.00
BenchmarkTree/30000_vertices_from_protobuf - allocs/op 870044 allocs/op 870045 allocs/op 1.00

This comment was automatically generated by workflow using github-action-benchmark.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (5)
pkg/document/innerpresence/presence.go (1)

130-130: Unnecessary blank line addition.

The added blank line doesn't affect functionality and appears to be an unintentional change.

server/backend/database/change_info.go (2)

42-52: LGTM! Consider documenting the migration path.

The change from string to *innerpresence.PresenceChange aligns well with the PR objectives for unified storage format. The pointer type appropriately handles optional presence changes.

Consider documenting the migration path in README.md or UPGRADE.md to help users:

  1. Understand the storage format change
  2. Execute necessary migration steps
  3. Handle potential rollback scenarios

116-128: LGTM! Consider adding format documentation.

The implementation correctly handles nil values and provides good error context. Consider adding documentation about the binary format structure for future maintainability.

Add a comment describing the binary format:

+// PresenceChangeToBytes encodes the given presence change into a protobuf-encoded
+// byte array. The binary format follows the structure defined in the protobuf
+// schema at api/yorkie/v1/presence.proto.
 func PresenceChangeToBytes(p *innerpresence.PresenceChange) ([]byte, error) {
server/backend/database/mongo/registry.go (2)

142-166: Add documentation for the encoding format.

The encoder implementation is solid, but would benefit from a comment explaining the binary format used for storing presence changes. This documentation would help with future maintenance and debugging.

Add a comment like:

+// presenceChangeEncoder encodes PresenceChange into a binary format using protocol buffers.
+// The encoded format includes [describe the structure of the binary data].
 func presenceChangeEncoder(_ bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {

168-196: Consider adding binary data validation.

The decoder implementation is robust but could benefit from validating the binary data length before attempting to decode it. This would help catch corrupted or invalid data early.

Consider adding a validation check:

 		data, _, err := vr.ReadBinary()
 		if err != nil {
 			return fmt.Errorf("decode error: %w", err)
 		}
+		// Validate binary data length
+		if len(data) < MinPresenceChangeBytes {
+			return fmt.Errorf("invalid binary data length for presence change: %d", len(data))
+		}
 
 		presenceChange, err := database.PresenceChangeFromBytes(data)
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between b9b1c0c and 70a0e99.

📒 Files selected for processing (3)
  • pkg/document/innerpresence/presence.go (1 hunks)
  • server/backend/database/change_info.go (3 hunks)
  • server/backend/database/mongo/registry.go (3 hunks)
🔇 Additional comments (6)
pkg/document/innerpresence/presence.go (1)

Line range hint 1-139: Implementation doesn't align with PR objectives.

The PR aims to convert presence change storage from string to byte array format, but the current implementation still uses string-based storage (map[string]string). This appears inconsistent with the stated objectives.

Consider:

  1. Converting the Presence type to use byte arrays
  2. Adding serialization/deserialization methods for byte array conversion
  3. Updating the PresenceChange struct to handle binary data

Let's verify the complete changes and their context:

Here's a suggested approach for the byte array conversion:

  1. Update the Presence type:
// Presence represents custom presence that can be defined by the client.
type Presence struct {
    data map[string][]byte
}
  1. Add encoding/decoding methods:
func (p *Presence) Marshal() ([]byte, error)
func UnmarshalPresence(data []byte) (*Presence, error)

Would you like me to provide a complete implementation for these changes?

server/backend/database/change_info.go (2)

98-98: Skip comment - nil check concern already raised.

A previous review comment already highlighted the need for nil checks before using i.PresenceChange.


116-142: Verify bidirectional conversion integrity.

Let's ensure that the conversion between PresenceChange and bytes is lossless in both directions.

server/backend/database/mongo/registry.go (3)

32-32: LGTM! Import and type registration are well-structured.

The new import and type registration for PresenceChange follow the established patterns in the codebase.

Also applies to: 40-40


56-56: LGTM! Registry builder updates are consistent.

The registration of encoder and decoder for PresenceChange follows the established pattern and maintains symmetry with other custom type registrations.

Also applies to: 62-62


156-159: Verify data migration for existing presence changes.

The implementation correctly handles the new binary format, but we should verify that existing string-based presence changes will be properly migrated.

Also applies to: 187-190

✅ Verification successful

Let me check the content of these files to better understand the presence change implementation and migration strategy.


Let me check the migration script and the actual encoding implementation to ensure proper handling of the format change.


Migration strategy for presence changes is properly implemented

The implementation includes a comprehensive migration strategy:

  • A dedicated migration script (migrate-presence-change.go) handles the conversion from string to byte array format
  • The migration process includes batch processing, progress tracking, and validation
  • The new PresenceChangeToBytes function correctly uses protocol buffers for binary encoding
  • The migration script includes validation to ensure no string-based presence changes remain
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any remaining string-based presence changes in the database
# and verify the migration script handles the conversion correctly.

# Search for string type usage in presence change related code
rg -l "type.*PresenceChange.*string" 

# Search for any remaining JSON encoding/decoding of presence changes
rg -l "json.*PresenceChange|PresenceChange.*json"

Length of output: 198


Script:

#!/bin/bash
# Check the content of presence.go to understand the type definition and usage
rg -A 5 "type.*PresenceChange" pkg/document/innerpresence/presence.go

# Check for any migration related code
rg -l "migrate.*presence|presence.*migrate"

# Look for protobuf definitions related to presence
fd "presence.*proto"

# Check the actual implementation of PresenceChangeToBytes
ast-grep --pattern 'func PresenceChangeToBytes($$$) {
  $$$
}'

Length of output: 572


Script:

#!/bin/bash
# Check the migration script content
cat migrations/v0.5.6/migrate-presence-change.go

# Check the actual encoding implementation
rg -A 10 "func.*PresenceChangeToBytes" server/backend/database/

# Check for any tests related to presence change encoding
rg -l "Test.*PresenceChange.*" 

Length of output: 5082

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (2)
pkg/document/innerpresence/presence.go (1)

Line range hint 1-138: Consider implementing binary encoding for presence changes

To align with the PR objectives of using byte arrays for storage, consider:

  1. Adding binary encoding/decoding methods to PresenceChange
  2. Implementing a custom binary format for Presence map
  3. Updating the storage layer to use the binary format

Here's a suggested approach:

// Add these methods to handle binary encoding

func (p Presence) MarshalBinary() ([]byte, error) {
    // Implement binary encoding for the map
}

func (p *Presence) UnmarshalBinary(data []byte) error {
    // Implement binary decoding for the map
}

func (pc *PresenceChange) MarshalBinary() ([]byte, error) {
    // Implement binary encoding for PresenceChange
}

func (pc *PresenceChange) UnmarshalBinary(data []byte) error {
    // Implement binary decoding for PresenceChange
}

Would you like me to:

  1. Generate a complete implementation of the binary encoding/decoding methods?
  2. Create a GitHub issue to track this implementation task?
server/backend/database/change_info.go (1)

130-142: Add validation for empty non-nil bytes.

While the nil check is good, consider adding validation for empty non-nil bytes to prevent potential issues with malformed data.

 func PresenceChangeFromBytes(bytes []byte) (*innerpresence.PresenceChange, error) {
 	if bytes == nil {
 		return nil, nil
 	}
+
+	if len(bytes) == 0 {
+		return nil, fmt.Errorf("empty presence change bytes")
+	}

 	pbChange := &api.PresenceChange{}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between 70a0e99 and f35ebb0.

📒 Files selected for processing (3)
  • pkg/document/innerpresence/presence.go (1 hunks)
  • server/backend/database/change_info.go (3 hunks)
  • server/backend/database/mongo/registry.go (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • server/backend/database/mongo/registry.go
🔇 Additional comments (6)
pkg/document/innerpresence/presence.go (2)

130-130: LGTM: Minor formatting change

The addition of a blank line improves code readability.


Line range hint 1-129: Implementation doesn't align with PR objectives

The PR objectives state converting presence changes from string to byte array format, but the current implementation still uses string-based storage:

  • Presence is still defined as map[string]string
  • No byte array types have been introduced
  • The removal of NewChangeFromJSON suggests moving away from string-based storage, but the corresponding byte array implementation is missing

Let's verify if the byte array implementation exists in other files:

server/backend/database/change_info.go (4)

98-98: Add nil check for PresenceChange before usage.

Referring to the previous review comment about adding nil checks for i.PresenceChange to prevent potential issues with null values from the database.


116-128: LGTM! Well-implemented encoding function.

The implementation includes proper nil handling, uses protocol buffers for serialization, and has good error handling with context.


Line range hint 42-142: Verify migration path for existing data.

The code changes look good, but we need to ensure there's a proper migration path for existing string-based presence changes in the database.

✅ Verification successful

Let me gather more information about the presence change migration implementation.


Migration path for presence changes is properly implemented

The migration path from string-based to byte array presence changes is well implemented in migrations/v0.5.6/migrate-presence-change.go. The implementation includes:

  • Batch processing of records to handle large datasets efficiently
  • Proper conversion from string to byte array format
  • Empty string handling (converted to nil)
  • Progress tracking and logging
  • Post-migration validation to ensure no string-based presence changes remain
  • Error handling and rollback capabilities
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for migration scripts and their implementation

# Search for migration files
fd -e go migration

# Check migration version handling
rg -A 5 "v0.5.6.*migration"

# Look for presence change conversion logic in migrations
rg -A 10 "presence.*change.*migration"

Length of output: 2195


Script:

#!/bin/bash
# Check the full implementation of presence change migration
cat migrations/v0.5.6/migrate-presence-change.go

# Look for any test files related to presence change migration
fd -e go test.*presence

Length of output: 4297


42-52: LGTM! Verify MongoDB schema compatibility.

The change from string to *innerpresence.PresenceChange aligns with the PR objectives. The pointer type is appropriate for optional presence changes.

✅ Verification successful

MongoDB schema change is properly handled with migration

The migration file migrations/v0.5.6/migrate-presence-change.go confirms that:

  • A migration is in place to convert existing string presence changes to byte array format
  • The migration includes validation to ensure no string-type presence changes remain
  • Empty string presence changes are properly converted to nil
  • The change is handled in batches with proper error handling
  • Tests in registry_test.go verify the new format works correctly with MongoDB BSON encoding/decoding
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify MongoDB schema and existing data compatibility
# Check for any direct string-type presence_change fields in MongoDB

# Search for MongoDB schema definitions and indexes
fd -e go | xargs rg -A 3 'presence_change.*string'

# Search for MongoDB queries or aggregations using presence_change
fd -e go | xargs rg -A 3 'presence_change.*\$'

Length of output: 101


Script:

#!/bin/bash
# Let's try a different approach to verify MongoDB schema compatibility

# 1. Search for any MongoDB migration files or schema changes
fd -e go | xargs rg -l "presence_change"

# 2. Look for any MongoDB-related code handling presence_change
ast-grep --pattern 'func $_($_, $_) {
  $$$
  presence_change
  $$$
}'

# 3. Check for any MongoDB indexes or schema definitions
fd -e go | xargs rg -B 3 'Index.*presence_change'

# 4. Look for any MongoDB query operations with presence_change
ast-grep --pattern '$_ = $_.Find(bson.M{
  $$$
  "presence_change"
  $$$
})'

Length of output: 445


Script:

#!/bin/bash
# Let's examine the migration file and related code

# 1. Check the migration file content
cat migrations/v0.5.6/migrate-presence-change.go

# 2. Look for any MongoDB operations in the client file
rg -A 5 "presence_change" server/backend/database/mongo/client.go

# 3. Check for any test cases handling presence change
cat server/backend/database/mongo/registry_test.go

Length of output: 8519

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (4)
pkg/document/innerpresence/presence.go (1)

101-102: Consider adding byte array encoding/decoding methods

While we're removing JSON serialization, I don't see the implementation for byte array encoding/decoding that was mentioned in the PR objectives. Consider adding:

  1. EncodeToBinary() ([]byte, error)
  2. DecodeFromBinary(data []byte) error

This would complete the transition from string to byte array storage format.

server/backend/database/change_info.go (1)

130-142: Consider adding validation for decoded presence change.

While the implementation is solid, consider adding validation for the decoded presence change to ensure data integrity.

 func PresenceChangeFromBytes(bytes []byte) (*innerpresence.PresenceChange, error) {
     if bytes == nil {
         return nil, nil
     }
 
     pbChange := &api.PresenceChange{}
     if err := proto.Unmarshal(bytes, pbChange); err != nil {
         return nil, fmt.Errorf("decode presence change: %w", err)
     }
 
+    // Validate decoded presence change
+    if err := validatePresenceChange(pbChange); err != nil {
+        return nil, fmt.Errorf("invalid presence change: %w", err)
+    }
+
     return converter.FromPresenceChange(pbChange), nil
 }
+
+func validatePresenceChange(p *api.PresenceChange) error {
+    if p == nil {
+        return errors.New("presence change is nil")
+    }
+    // Add more validation as needed
+    return nil
+}
server/backend/database/mongo/registry.go (2)

142-166: Consider adding presence change validation.

While the encoder implementation is solid, consider adding validation of the presence change content before encoding. This could prevent storing invalid presence changes in the database.

 func presenceChangeEncoder(_ bsoncodec.EncodeContext, vw bsonrw.ValueWriter, val reflect.Value) error {
 	if !val.IsValid() || val.Type() != tPresenceChange {
 		return bsoncodec.ValueEncoderError{
 			Name: "presenceChangeEncoder", Types: []reflect.Type{tPresenceChange}, Received: val}
 	}

 	presenceChange := val.Interface().(*innerpresence.PresenceChange)
 	if presenceChange == nil {
 		if err := vw.WriteNull(); err != nil {
 			return fmt.Errorf("encode error: %w", err)
 		}
 		return nil
 	}

+	// Validate presence change content
+	if err := presenceChange.Validate(); err != nil {
+		return fmt.Errorf("invalid presence change: %w", err)
+	}
+
 	bytes, err := database.EncodePresenceChange(presenceChange)
 	if err != nil {
 		return fmt.Errorf("encode error: %w", err)
 	}

 	if err := vw.WriteBinary(bytes); err != nil {
 		return fmt.Errorf("encode error: %w", err)
 	}

 	return nil
 }

168-196: Improve error handling in the default case.

The decoder implementation is robust, but the error message in the default case could be more descriptive to aid in debugging.

 	default:
-		return fmt.Errorf("unsupported type: %v", vr.Type())
+		return fmt.Errorf("presenceChangeDecoder: unsupported BSON type %v, expected %v or %v", 
+			vr.Type(), bson.TypeNull, bson.TypeBinary)
 	}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

📥 Commits

Reviewing files that changed from the base of the PR and between f35ebb0 and 379b46a.

📒 Files selected for processing (3)
  • pkg/document/innerpresence/presence.go (2 hunks)
  • server/backend/database/change_info.go (3 hunks)
  • server/backend/database/mongo/registry.go (3 hunks)
🔇 Additional comments (9)
pkg/document/innerpresence/presence.go (3)

128-128: LGTM: Improved code organization

The added blank line improves readability by clearly separating the nil check from the implementation logic.


101-102: Verify complete removal of JSON serialization

The removal of JSON tags aligns with the transition to byte array storage. However, we should ensure all JSON-related code has been properly updated.

✅ Verification successful

JSON serialization removal verified

The verification shows that all JSON-related code has been properly removed from the presence.go file:

  • No JSON struct tags remain
  • No JSON Marshal/Unmarshal implementations exist
  • No encoding/json imports present
  • No other JSON-related operations found

The removal of JSON tags from the PresenceChange struct is consistent with the complete removal of JSON serialization functionality.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Search for any remaining JSON-related code for PresenceChange
rg -A 5 "json\.(Marshal|Unmarshal).*PresenceChange" 

# Search for any remaining JSON tag references
rg -A 5 'PresenceChange.*`json:"'

Length of output: 89


Script:

#!/bin/bash
# Let's broaden our search to find any JSON-related code in the presence.go file
rg -A 5 "json\." pkg/document/innerpresence/presence.go

# Search for any JSON struct tags in the file
rg -A 5 '`json:' pkg/document/innerpresence/presence.go

# Look for any Marshal/Unmarshal implementations
ast-grep --pattern 'func $_($_ *PresenceChange) MarshalJSON() ([]byte, error) { $$$ }'
ast-grep --pattern 'func $_($_ *PresenceChange) UnmarshalJSON([]byte) error { $$$ }'

# Check for any imports of encoding/json
rg '"encoding/json"' pkg/document/innerpresence/presence.go

Length of output: 353


119-120: ⚠️ Potential issue

Breaking Change: Clear method now uses pointer receiver

The change from value to pointer receiver is correct for modifying the map, but this is a breaking change. Callers passing value receivers will no longer work correctly.

server/backend/database/change_info.go (3)

98-98: Past review comment is still applicable.


116-128: LGTM! Well-structured encoding implementation.

The implementation includes proper nil handling, uses protobuf for serialization, and follows good error handling practices.


42-52: LGTM! Verify data migration path.

The change from string to *innerpresence.PresenceChange aligns with the PR objectives. The pointer type is appropriate for optional presence changes.

Let's verify the migration path for existing data:

✅ Verification successful

Migration path is properly handled

The migration path for changing presence change from string to byte array format is well-implemented:

  1. A dedicated migration script migrate-presence-change.go handles the data conversion:

    • Migrates existing string presence changes to byte array format
    • Processes changes in batches for efficiency
    • Handles empty presence changes by setting them to nil
    • Includes validation to ensure no string presence changes remain
    • Provides progress reporting during migration
  2. The database schema change is properly tested:

    • registry_test.go verifies BSON encoding/decoding of the new format
    • The mongo client correctly handles the new format when writing changes

The implementation ensures zero-downtime migration and data consistency, making this change safe to proceed with.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for migration scripts and database schema updates

# Look for migration files
fd -e go -e sql migration v0.5.6

# Check for presence change handling in migrations
rg -A 5 "presence.*change" -g "migrations/*"

Length of output: 324


Script:

#!/bin/bash
# Let's try a different approach to find migration-related files and presence change handling

# Look for migration files in the repository
fd migration

# Search for presence change handling in the entire codebase
rg -A 5 "presence.*change" 

# Check for database schema or upgrade related files
fd -e go upgrade
fd -e go schema

Length of output: 128339


Script:

#!/bin/bash
# Let's check for presence change migration code and database schema changes

# Look for presence change migration files
rg -l "presence.*change.*migration" 

# Check for database schema changes related to presence
rg -A 5 "presence.*change.*bson" 

# Look for any test files related to presence change migration
rg -l "presence.*change.*test"

Length of output: 932


Script:

#!/bin/bash
# Let's examine the migration code in detail

# Check the content of the migration file
cat migrations/v0.5.6/migrate-presence-change.go

# Look for any database-related tests that verify presence change migration
rg -A 10 "presence.*change" server/backend/database/mongo/

Length of output: 6223

server/backend/database/mongo/registry.go (3)

32-32: LGTM: Import and type registration for presence changes.

The addition of the innerpresence package import and the registration of tPresenceChange type are well-aligned with the PR's objective of transitioning presence changes to binary format.

Also applies to: 40-40


56-56: LGTM: Symmetric registration of presence change encoder and decoder.

The registration of both encoder and decoder follows the established pattern in the codebase, maintaining consistency with other type registrations.

Also applies to: 62-62


141-196: Verify handling of existing string-format data during migration.

The implementation looks solid for the new binary format. However, we should verify the migration path for existing data.

✅ Verification successful

Let me check the migration code to ensure proper handling of the string format data.


Let me check one more aspect to verify the database encoding/decoding implementation for both formats.


Based on the review of the migration code and implementation, I can now provide the final response:

Migration path for string-format data is properly handled

The implementation includes a comprehensive migration strategy:

  • Dedicated migration module (migrations/v0.5.6/migrate-presence-change.go) handles conversion from string to byte array format
  • Migration process includes:
    • Batch processing with progress tracking
    • Validation step to ensure no string-format data remains
    • Proper handling of empty strings (converted to nil)
    • Atomic updates using MongoDB bulk operations
🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Check for any direct string-to-presence-change conversions in the codebase
# that might need updating for the migration.

# Look for string-based presence change handling
rg -l "PresenceChange.*string|string.*PresenceChange"

# Look for any migration-related code
rg -l "migration.*presence|presence.*migration"

# Look for potential JSON unmarshaling of presence changes
ast-grep --pattern 'json.Unmarshal($_, $_)'

Length of output: 866


Script:

#!/bin/bash
# Check the migration implementation
cat migrations/v0.5.6/migrate-presence-change.go

# Check the presence change implementation
cat pkg/document/innerpresence/presence.go

# Check if there are any tests for migration
rg -l "TestMigrate.*Presence|test.*presence.*migration" 

Length of output: 7869


Script:

#!/bin/bash
# Check the database encoding implementation
cat pkg/document/change/change.go

# Look for any test cases related to presence change encoding/decoding
rg -A 10 "func.*Test.*PresenceChange.*Encoding|func.*Test.*PresenceChange.*Migration" 

Length of output: 3554

Copy link
Member

@hackerwins hackerwins left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your contribution.

@hackerwins hackerwins changed the title Convert Presence Change Storage Format from String to Byte Array Convert presence change from string to binary Nov 20, 2024
@hackerwins hackerwins merged commit 6eef109 into main Nov 20, 2024
5 checks passed
@hackerwins hackerwins deleted the db-presence-change branch November 20, 2024 07:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Unify Data Storage Format for Presence Changes
2 participants