Skip to content

Conversation

@nixel2007
Copy link
Member

@nixel2007 nixel2007 commented Jan 4, 2026

Описание

Связанные задачи

Closes

Чеклист

Общие

  • Ветка PR обновлена из develop
  • Отладочные, закомментированные и прочие, не имеющие смысла участки кода удалены
  • Изменения покрыты тестами
  • Обязательные действия перед коммитом выполнены (запускал команду gradlew precommit)

Для диагностик

  • Описание диагностики заполнено для обоих языков (присутствуют файлы для обоих языков, для русского заполнено все подробно, перевод на английский можно опустить)

Дополнительно

Summary by CodeRabbit

  • Bug Fixes

    • Resolved race conditions during concurrent edits; serialized per-document writes to prevent corruption.
    • Fixed missing-state issues with clearer logging and safer handling of absent document context.
  • Improvements

    • Per-document locking for more reliable open/change/close flows and consistent diagnostics on open.
    • More robust document reloads from filesystem, improving editor features (hover, diagnostics, change responses).
  • Tests

    • Added integration scaffolding to validate locking and change-application behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

Аспект отправки событий тригерился на оба rebuild, и внешний и внутренний.
Добавлены блокировки на уровне URI вместо общего лока на уровне сервера. Это должно решить проблему отдачи недоинициализированного контекта во время работы редактора + дать возможность параллельной работы LSP операций и заполнении контекста
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 4, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

This PR introduces per-document ReadWriteLocks and context-safe execution wrappers. BSLTextDocumentService now uses per-URI locking and withFreshDocumentContext(...) helpers; DocumentChangeExecutor and DocumentContext are updated to acquire per-document locks and rebuild from filesystem respectively; ServerContext manages per-document locks.

Changes

Cohort / File(s) Summary
Per-URI Locking Infrastructure
src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
Replace global contextLock with a Map<URI, ReadWriteLock>; add getDocumentLock(URI); use per-URI locks in populateContext, getDocument, addDocument, removeDocument, clear; rebuildDocument calls rebuildFromFileSystem().
Document Lifecycle & Concurrency
src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutor.java
flushPendingChanges() now acquires/releases the per-document write lock around applying accumulated changes to serialize writes.
Document State & Rebuild
src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentContext.java
rebuild() renamed to rebuildFromFileSystem(); implementation reads file content from filesystem (URI), handles IOException, and calls existing rebuild(content, 0).
LSP Request Handling & Context-Safe Execution
src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
Add withFreshDocumentContextNullable(...), withFreshDocumentContext(...), and internal helper; didOpen uses Absolute.uri(...), acquires per-document write lock, creates/associates DocumentChangeExecutor, optionally runs diagnostics under lock; didChange acquires read lock and submits changes; multiple handlers route through new wrappers; added logging for missing contexts/executors.
Test Coordination Setup
src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
Add TEST_URI, ServerContext mock, per-document lock mocking via ReentrantReadWriteLock, wire DocumentContext to return URI and server context; ensure executor shutdown/termination in setup.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant BSLTextDocumentService
    participant ServerContext
    participant DocumentContext
    participant DocumentChangeExecutor

    rect rgb(220,240,255)
    Note over Client,BSLTextDocumentService: didOpen flow (write lock)
    end

    Client->>BSLTextDocumentService: didOpen(uri, content)
    BSLTextDocumentService->>ServerContext: getDocumentLock(uri)
    ServerContext-->>BSLTextDocumentService: ReadWriteLock
    BSLTextDocumentService->>ServerContext: addDocument(uri)
    ServerContext-->>BSLTextDocumentService: DocumentContext
    BSLTextDocumentService->>DocumentChangeExecutor: create executor(ctx)
    BSLTextDocumentService->>DocumentContext: open(document content)
    BSLTextDocumentService->>BSLTextDocumentService: runDiagnostics() (under write lock)
    BSLTextDocumentService-->>Client: open acknowledgment

    rect rgb(220,240,255)
    Note over Client,BSLTextDocumentService: didChange flow (read lock + executor)
    end

    Client->>BSLTextDocumentService: didChange(uri, changes)
    BSLTextDocumentService->>ServerContext: getDocumentLock(uri)
    ServerContext-->>BSLTextDocumentService: ReadWriteLock
    BSLTextDocumentService->>ServerContext: getDocument(uri)
    ServerContext-->>BSLTextDocumentService: DocumentContext
    BSLTextDocumentService->>DocumentChangeExecutor: submitChanges(changes)
    DocumentChangeExecutor->>DocumentChangeExecutor: queue changes
    DocumentChangeExecutor->>DocumentChangeExecutor: flushPendingChanges() (acquire write lock)
    DocumentChangeExecutor->>DocumentContext: applyChanges()
    DocumentContext-->>DocumentChangeExecutor: applied
    DocumentChangeExecutor-->>BSLTextDocumentService: CompletableFuture result
    BSLTextDocumentService-->>Client: change acknowledgment
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • #3617: Modifies BSLTextDocumentService, DocumentChangeExecutor, DocumentContext for per-document executors/locking.
  • #3724: Touches didClose executor termination and lock handling related to per-document executors.
  • #3510: Integrates semanticTokensFull execution into the new withFreshDocumentContext(...) flow.

Suggested labels

hacktoberfest-accepted

Suggested reviewers

  • theshadowco

Poem

🐰 I hopped through locks and danced with threads,
Per-URI keys beneath my beds.
I guard each doc with gentle care,
No global waits — just ordered flair.
🥕 Hop, sync, repeat — concurrency shared.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: fixing race conditions in context population and LSP operations, which aligns with the substantial concurrency and locking changes throughout the codebase.
✨ Finishing touches
  • 📝 Generate docstrings

📜 Recent review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de0ee24 and 9f79828.

📒 Files selected for processing (2)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
🧰 Additional context used
📓 Path-based instructions (3)
src/test/java/**/*Test.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Maintain or improve test coverage and use appropriate test frameworks (JUnit, AssertJ, Mockito)

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
src/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Java 17 for language and follow Java naming conventions

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
src/main/java/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/main/java/**/*.java: Follow the Style Guide for code formatting and conventions
Use Lombok annotations to reduce boilerplate code and enable annotation processing in IDE
Write JavaDoc for public APIs and include comments for complex logic
Use meaningful, descriptive names for classes and methods following Java naming conventions
Optimize imports before committing; DO NOT optimize imports across the entire project unless specifically working on that task

Files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
🧠 Learnings (1)
📚 Learning: 2025-02-10T17:12:56.150Z
Learnt from: nixel2007
Repo: 1c-syntax/bsl-language-server PR: 3408
File: src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/ProtectedModuleDiagnostic.java:63-66
Timestamp: 2025-02-10T17:12:56.150Z
Learning: In BSL Language Server, `documentContext.getServerContext().getConfiguration()` is guaranteed to return a non-null value, making null checks unnecessary.

Applied to files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Benchmark
  • GitHub Check: build
  • GitHub Check: build (17, ubuntu-latest)
  • GitHub Check: build (25, macOS-latest)
  • GitHub Check: build (25, ubuntu-latest)
  • GitHub Check: build (21, macOS-latest)
  • GitHub Check: build (17, macOS-latest)
  • GitHub Check: build (25, windows-latest)
  • GitHub Check: build (17, windows-latest)
  • GitHub Check: build (21, windows-latest)
  • GitHub Check: build (21, ubuntu-latest)
  • GitHub Check: Analyse
🔇 Additional comments (5)
src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java (2)

29-47: LGTM!

The imports and constant declaration properly support the per-URI locking test infrastructure.


97-99: LGTM!

The pre-cleanup properly shuts down the executor from setUp before creating a new one, preventing resource leaks and test interference.

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java (3)

87-87: LGTM!

The per-URI lock map using ConcurrentHashMap is appropriate for thread-safe management of document locks.


167-174: LGTM!

The read lock acquisition properly protects document access in the new per-URI locking model.


312-319: LGTM!

The method call correctly uses rebuildFromFileSystem() to reflect the filesystem-based rebuild operation.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@nixel2007 nixel2007 marked this pull request as ready for review January 4, 2026 07:45
Copilot AI review requested due to automatic review settings January 4, 2026 07:45
@github-actions
Copy link
Contributor

github-actions bot commented Jan 4, 2026

Test Results

 2 808 files  ±0   2 808 suites  ±0   52m 1s ⏱️ + 2m 31s
 1 156 tests ±0   1 156 ✅ ±0  0 💤 ±0  0 ❌ ±0 
10 404 runs  ±0  10 404 ✅ ±0  0 💤 ±0  0 ❌ ±0 

Results for commit de0ee24. ± Comparison against base commit 9c1f478.

This pull request removes 8 and adds 4 tests. Note that renamed tests count towards both.
#, count=1
, count=0
, count=1
A, count=1
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [2] content=
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [6] content=
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [7] content=#
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [8] content=
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [2] content=
, count=0
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [6] content=
A, count=1
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [7] content=#
, count=1
com.github._1c_syntax.bsl.languageserver.diagnostics.MetadataObjectNameLengthDiagnosticTest ‑ [8] content=
#, count=1

♻️ This comment has been updated with latest results.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses race conditions in document handling by introducing per-document locking mechanisms. The changes replace a global context lock with fine-grained ReadWriteLock instances for each document URI, improving concurrency and preventing race conditions during parallel document operations.

Key Changes

  • Introduced per-document ReadWriteLock instances stored in a ConcurrentHashMap to replace the global context lock
  • Updated document lifecycle operations (open, change, close) to acquire appropriate locks before modifying document state
  • Added lock acquisition in DocumentChangeExecutor.flushPendingChanges() to protect document rebuild operations

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
ServerContext.java Replaced global contextLock with per-document documentLocks map; refactored populateContext, getDocument, and addDocument to use document-specific locks; added getDocumentLock() method
DocumentContext.java Renamed rebuild() to rebuildFromFileSystem() for clarity
DocumentChangeExecutor.java Added write lock acquisition in flushPendingChanges() before applying document changes
BSLTextDocumentService.java Added lock acquisition in didOpen() and didChange(); refactored withFreshDocumentContext to acquire read locks; split into nullable and non-nullable variants
DocumentChangeExecutorTest.java Updated test setup to mock ServerContext and provide ReentrantReadWriteLock instances; added executor cleanup before creating new instances

Copy link
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentContext.java (1)

326-333: Silent failure on IOException may leave document in inconsistent state.

If FileUtils.readFileToString throws an IOException, the error is logged but rebuild is never called. This could leave the document with stale or null content, potentially causing NullPointerException when getContent() is later called (since it uses requireNonNull(content)).

Consider either propagating the exception or setting the document to a known empty/error state.

🔎 Suggested improvement
 protected void rebuildFromFileSystem() {
   try {
     var newContent = FileUtils.readFileToString(new File(uri), StandardCharsets.UTF_8);
     rebuild(newContent, 0);
   } catch (IOException e) {
     LOGGER.error("Can't rebuild content from uri", e);
+    rebuild("", 0); // Initialize with empty content to avoid NPE
   }
 }
src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java (1)

236-246: Potential race condition when removing document lock.

Removing the lock from documentLocks (line 245) while another thread might be waiting to acquire it could lead to inconsistent behavior. A subsequent call to getDocumentLock(uri) would return a new lock instance, breaking mutual exclusion guarantees.

Consider acquiring the write lock before removal to ensure no concurrent operations are in progress:

🔎 Suggested fix
 public void removeDocument(URI uri) {
+  var lock = getDocumentLock(uri);
+  lock.writeLock().lock();
+  try {
     var documentContext = documents.get(uri);
     if (openedDocuments.contains(documentContext)) {
       throw new IllegalStateException(String.format("Document %s is opened", uri));
     }

     removeDocumentMdoRefByUri(uri);
     states.remove(documentContext);
     documents.remove(uri);
     documentLocks.remove(uri);
+  } finally {
+    lock.writeLock().unlock();
+  }
 }
🧹 Nitpick comments (1)
src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java (1)

215-227: Nested lock acquisition in addDocument - verify reentrancy behavior.

addDocument acquires a write lock (line 217), then calls getDocument(uri) (line 219) which also acquires a read lock on the same URI (lines 167-168). While ReentrantReadWriteLock allows a write lock holder to acquire a read lock (downgrade), this nested acquisition pattern adds unnecessary overhead.

Consider accessing the documents map directly inside the write lock scope instead of calling getDocument.

🔎 Suggested simplification
 public DocumentContext addDocument(URI uri) {
   var lock = getDocumentLock(uri);
   lock.writeLock().lock();
   try {
-    var documentContext = getDocument(uri);
+    var documentContext = documents.get(uri);
     if (documentContext == null) {
       documentContext = createDocumentContext(uri);
     }
     return documentContext;
   } finally {
     lock.writeLock().unlock();
   }
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c1f478 and de0ee24.

📒 Files selected for processing (5)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutor.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentContext.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
🧰 Additional context used
📓 Path-based instructions (3)
src/test/java/**/*Test.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Maintain or improve test coverage and use appropriate test frameworks (JUnit, AssertJ, Mockito)

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
src/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Java 17 for language and follow Java naming conventions

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutor.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentContext.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
src/main/java/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/main/java/**/*.java: Follow the Style Guide for code formatting and conventions
Use Lombok annotations to reduce boilerplate code and enable annotation processing in IDE
Write JavaDoc for public APIs and include comments for complex logic
Use meaningful, descriptive names for classes and methods following Java naming conventions
Optimize imports before committing; DO NOT optimize imports across the entire project unless specifically working on that task

Files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutor.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentContext.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
🧠 Learnings (2)
📚 Learning: 2025-02-10T17:12:56.150Z
Learnt from: nixel2007
Repo: 1c-syntax/bsl-language-server PR: 3408
File: src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/ProtectedModuleDiagnostic.java:63-66
Timestamp: 2025-02-10T17:12:56.150Z
Learning: In BSL Language Server, `documentContext.getServerContext().getConfiguration()` is guaranteed to return a non-null value, making null checks unnecessary.

Applied to files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
📚 Learning: 2025-11-19T09:02:03.154Z
Learnt from: theshadowco
Repo: 1c-syntax/bsl-language-server PR: 3610
File: src/main/java/com/github/_1c_syntax/bsl/languageserver/folding/QueryPackageFoldingRangeSupplier.java:26-26
Timestamp: 2025-11-19T09:02:03.154Z
Learning: В проекте bsl-language-server используется кастомная версия ANTLR4 от 1c-syntax (io.github.1c-syntax:antlr4), которая включает базовый класс org.antlr.v4.runtime.Tokenizer с методами getAst() и getTokens(). SDBLTokenizer и BSLTokenizer наследуются от этого базового класса.

Applied to files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (15)
  • GitHub Check: Agent
  • GitHub Check: CodeQL analysis (java)
  • GitHub Check: build (21, ubuntu-latest)
  • GitHub Check: build (17, windows-latest)
  • GitHub Check: build (25, ubuntu-latest)
  • GitHub Check: build (25, windows-latest)
  • GitHub Check: build (17, ubuntu-latest)
  • GitHub Check: build (17, macOS-latest)
  • GitHub Check: build (21, windows-latest)
  • GitHub Check: build (21, macOS-latest)
  • GitHub Check: build (25, macOS-latest)
  • GitHub Check: Benchmark
  • GitHub Check: build (25, windows-latest)
  • GitHub Check: build (17, windows-latest)
  • GitHub Check: build (21, windows-latest)
🔇 Additional comments (9)
src/main/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutor.java (1)

244-257: LGTM! Per-document write lock correctly protects change application.

The lock acquisition pattern is correct: lock is acquired before the try block, and unlock is in the finally block. This ensures the lock is released even if changeListener.onChange throws.

src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java (2)

52-69: LGTM! Test setup correctly mocks per-document locking dependencies.

The mock wiring properly chains documentContext.getServerContext().getDocumentLock(uri) to return a ReentrantReadWriteLock, accurately reflecting the new locking architecture.


86-103: LGTM! Proper executor lifecycle management in test.

The pre-cleanup pattern correctly shuts down the executor created in setUp before creating a new one with a custom listener. This prevents resource leaks and potential interference between executor instances.

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java (2)

121-139: LGTM! Per-document locking in parallel context population.

The write lock correctly protects document creation and rebuilding. Progress reporting (tick()) is appropriately placed outside the lock scope to avoid holding locks during potentially slow operations.


258-268: LGTM! Lazy lock creation with computeIfAbsent.

The pattern is thread-safe and efficient. Using the default unfair lock provides better throughput for typical LSP workloads.

src/main/java/com/github/_1c_syntax/bsl/languageserver/BSLTextDocumentService.java (4)

469-496: LGTM! didOpen correctly uses write lock for document initialization.

The write lock appropriately protects the critical section where the document is added, executor is created, and document is opened. The conditional diagnostic validation is also correctly placed within the lock scope to prevent race conditions during initial document setup.


500-533: LGTM! didChange uses read lock appropriately for executor access.

The read lock correctly protects access to the executor map without blocking other readers. The actual document mutation is handled asynchronously by DocumentChangeExecutor with its own write lock, ensuring proper synchronization.


831-858: LGTM! Read-after-write consistency with awaitLatest and read lock.

The pattern correctly ensures:

  1. All pending changes are applied via awaitLatest()
  2. Read lock prevents concurrent modifications during supplier execution
  3. Lock is released in finally block

This provides strong consistency guarantees for LSP request handlers.


817-829: LGTM! Clean wrapper pattern for nullable vs non-nullable returns.

The separation between withFreshDocumentContextNullable and withFreshDocumentContext provides proper type safety while sharing the same implementation.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@nixel2007 nixel2007 requested a review from Copilot January 4, 2026 08:24
@nixel2007 nixel2007 changed the title Fix/lock race Исправлена гонка на заполнении контекста и LSP операциях Jan 4, 2026
@nixel2007
Copy link
Member Author

@copilot отработай замечания по ревью.

Copy link
Contributor

Copilot AI commented Jan 4, 2026

@nixel2007 I've opened a new pull request, #3731, to work on those changes. Once the pull request is ready, I'll request review from you.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated 5 comments.

Copilot AI and others added 2 commits January 4, 2026 08:35
…and nested locking in ServerContext

Co-authored-by: nixel2007 <1132840+nixel2007@users.noreply.github.com>
Устранена избыточная вложенная блокировка в методах работы с документами
Copy link
Contributor

@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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java (1)

236-246: Add lock acquisition to removeDocument to prevent race conditions.

The method removes documents without acquiring a write lock, violating the synchronization pattern established by getDocument (read lock) and addDocument (write lock). A thread calling getDocument could be reading a DocumentContext while another thread simultaneously removes it via removeDocument, causing a race condition. Acquire lock.writeLock() before modifying the documents map, consistent with addDocument:

public void removeDocument(URI uri) {
  var lock = getDocumentLock(uri);
  lock.writeLock().lock();
  try {
    var documentContext = documents.get(uri);
    if (openedDocuments.contains(documentContext)) {
      throw new IllegalStateException(String.format("Document %s is opened", uri));
    }
    removeDocumentMdoRefByUri(uri);
    states.remove(documentContext);
    documents.remove(uri);
    documentLocks.remove(uri);
  } finally {
    lock.writeLock().unlock();
  }
}
♻️ Duplicate comments (4)
src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java (1)

50-69: LGTM! Past review concern addressed.

The mock setup now correctly returns the same lock instance for the same URI using computeIfAbsent, addressing the previous review comment about lock instance consistency.

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java (3)

121-139: LGTM! Past review concern addressed.

The per-URI write lock is correctly acquired and released. Using documents.get(uri) directly avoids the nested locking issue flagged in previous reviews.


216-226: LGTM! Past review concern addressed.

The per-URI write lock is correctly acquired and released. Using documents.get(uri) directly avoids the nested locking issue flagged in previous reviews.


258-268: Potential memory leak from unused locks.

The getDocumentLock() method creates locks on-demand via computeIfAbsent. If called for URIs that never get documents added (e.g., from external code checking documents that don't exist), locks will accumulate in documentLocks without cleanup. Consider:

  1. Adding validation to ensure the URI corresponds to an existing or soon-to-be-added document, or
  2. Implementing periodic cleanup of locks for non-existent documents, or
  3. Documenting that callers must only request locks for documents they intend to create/access
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between de0ee24 and 9f79828.

📒 Files selected for processing (2)
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
  • src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
🧰 Additional context used
📓 Path-based instructions (3)
src/test/java/**/*Test.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Maintain or improve test coverage and use appropriate test frameworks (JUnit, AssertJ, Mockito)

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
src/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

Use Java 17 for language and follow Java naming conventions

Files:

  • src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java
  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
src/main/java/**/*.java

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/main/java/**/*.java: Follow the Style Guide for code formatting and conventions
Use Lombok annotations to reduce boilerplate code and enable annotation processing in IDE
Write JavaDoc for public APIs and include comments for complex logic
Use meaningful, descriptive names for classes and methods following Java naming conventions
Optimize imports before committing; DO NOT optimize imports across the entire project unless specifically working on that task

Files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
🧠 Learnings (1)
📚 Learning: 2025-02-10T17:12:56.150Z
Learnt from: nixel2007
Repo: 1c-syntax/bsl-language-server PR: 3408
File: src/main/java/com/github/_1c_syntax/bsl/languageserver/diagnostics/ProtectedModuleDiagnostic.java:63-66
Timestamp: 2025-02-10T17:12:56.150Z
Learning: In BSL Language Server, `documentContext.getServerContext().getConfiguration()` is guaranteed to return a non-null value, making null checks unnecessary.

Applied to files:

  • src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (12)
  • GitHub Check: Benchmark
  • GitHub Check: build
  • GitHub Check: build (17, ubuntu-latest)
  • GitHub Check: build (25, macOS-latest)
  • GitHub Check: build (25, ubuntu-latest)
  • GitHub Check: build (21, macOS-latest)
  • GitHub Check: build (17, macOS-latest)
  • GitHub Check: build (25, windows-latest)
  • GitHub Check: build (17, windows-latest)
  • GitHub Check: build (21, windows-latest)
  • GitHub Check: build (21, ubuntu-latest)
  • GitHub Check: Analyse
🔇 Additional comments (5)
src/test/java/com/github/_1c_syntax/bsl/languageserver/context/DocumentChangeExecutorTest.java (2)

29-47: LGTM!

The imports and constant declaration properly support the per-URI locking test infrastructure.


97-99: LGTM!

The pre-cleanup properly shuts down the executor from setUp before creating a new one, preventing resource leaks and test interference.

src/main/java/com/github/_1c_syntax/bsl/languageserver/context/ServerContext.java (3)

87-87: LGTM!

The per-URI lock map using ConcurrentHashMap is appropriate for thread-safe management of document locks.


167-174: LGTM!

The read lock acquisition properly protects document access in the new per-URI locking model.


312-319: LGTM!

The method call correctly uses rebuildFromFileSystem() to reflect the filesystem-based rebuild operation.

@nixel2007 nixel2007 merged commit 6acf373 into develop Jan 4, 2026
36 of 38 checks passed
@nixel2007 nixel2007 deleted the fix/lock-race branch January 4, 2026 08:46
@sonarqubecloud
Copy link

sonarqubecloud bot commented Jan 4, 2026

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.

2 participants