sammccall added a comment.

Thanks, this looks a lot better!
There do seem to be a lot of little classes that exist exactly one-per-TU 
(ASTWorker, ASTBuilder, CachedAST, to a lesser extent ParsedAST) and I'm not 
sure the balance of responsibilities is quite right. Some comments below.



================
Comment at: clangd/ClangdUnit.h:132
 
-/// Manages resources, required by clangd. Allows to rebuild file with new
-/// contents, and provides AST and Preamble for it.
-class CppFile {
+/// A helper class that handles building preambles and ASTs for a file. Also
+/// adds some logging.
----------------
ilya-biryukov wrote:
> sammccall wrote:
> > This may be change aversion, but I'm not sure this class does enough after 
> > this change - it doesn't store the inputs or the outputs/cache, so it kind 
> > of seems like it wants to be a function.
> > 
> > I guess the motivation here is that storing the outputs means dealing with 
> > the cache, and the cache is local to TUScheduler.
> > But `CppFile` is only used in TUScheduler, so we could move this there too? 
> > It feels like expanding the scope more than I'd like.
> > 
> > The upside is that I think it's a more natural division of responsibility: 
> > `CppFile` could continue to be the "main" holder of the 
> > `shared_ptr<Preamble>` (which we don't limit, but share), and instead of 
> > `Optional<ParsedAST>` it'd have a `weak_ptr<ParsedAST>` which is controlled 
> > and can be refreshed through the cache.
> > 
> > As discussed offline, the cache could look something like:
> > ```
> > class Cache {
> >    shared_ptr<ParsedAST> put(ParsedAST);
> >    void hintUsed(ParsedAST*); // optional, bumps LRU when client reads
> >    void hintUnused(ParsedAST*); // optional, releases when client abandons
> > }
> > 
> > shared_ptr<ParsedAST> CppFile::getAST() {
> >   shared_ptr<ParsedAST> AST = WeakAST.lock();
> >   if (AST)
> >     Cache.hintUsed(AST.get());
> >   else
> >     WeakAST = AST = Cache.put(build...);
> >   return AST;
> > }
> > ```
> I've reimplemented the cache with weak_ptr/shared_ptr. 
> With a slightly different interface to hide more stuff in the cache API. 
> Please take a look and let me know what you think.
> 
> Nevertheless, I still find `CppFile` refactoring useful. It unties preambles 
> from the ASTs and I believe this is a good thing, given that their lifetimes 
> are different.
I'm not sure how much they were tangled before, they were computed in the same 
place, but accessed separately, and it's not sure you ever *want* to compute 
them separately? (possibly in unit tests?)

I do think making ASTWorker maintain the old preamble and pass it in is 
confusing. The remaining members are trivial and unrelated enough that I do 
think if the references to the preamble/ast are removed, then moving the 
remaining members to ASTWorker or to a dumb struct, and making these free 
functions would make it easier to navigate the class structure.


================
Comment at: clangd/TUScheduler.cpp:71
+
+  /// Update the function used to compute the value.
+  void update(std::function<llvm::Optional<ParsedAST>()> ComputeF);
----------------
I think I understand this more as "updates the value" but the value is lazy...

I find this API somewhat hard to follow, maybe just because it's unfamiliar.
I've mostly seen cache APIs look like one of:
1. `Cache(function<Value(Input)> Compute)`, `Value Cache::get(Input)`
2. `void Cache::put(Key, Value)`, `Optional<Value> Cache::get(Key)`
3. `Handle Cache::put(Value)`, `Optional<Value> Handle::get()`

This one is `Slot Cache::create()`, `void Slot::update(function<Value()> 
LazyV)`, `Value Slot::get()`.

It's similar-ish to 3, but has 3 nontrivial operations instead of 2, and the 
slot object is externally mutable instead of immutable, so it seems more 
complex. What does it buy us in exchange?

(1 & 2 work well with a natural key or inputs that are easy to compare, which 
we don't particularly have)


================
Comment at: clangd/TUScheduler.cpp:91
+/// Provides an LRU cache of ASTs.
+class TUScheduler::IdleASTs {
+  friend class CachedAST;
----------------
naming: `IdleASTs` doesn't mention the function of this class, which is a cache.
I'd suggest swapping the names: call the class `ASTCache` and the *instance* 
`IdleASTs` as that reflects its role within the TUScheduler.

For `CachedAST`, I think the relationship would be well-exposed by nesting it 
as `ASTCache::Entry`. This also gives you the `friend` for free, which seems 
like a hint that it's an appropriate structure.
(Though I'm not sure CachedAST is that useful)


================
Comment at: clangd/TUScheduler.cpp:153
+  /// one.
+  std::vector<std::pair<CachedAST *, 
std::shared_ptr<llvm::Optional<ParsedAST>>>>
+      LRU; /* GUARDED_BY(Mut) */
----------------
as discussed offline, using a CachedAST* as a key shouldn't be necessary, the 
ParsedAST* should be enough I think.


================
Comment at: clangd/TUScheduler.cpp:157
+
+CachedAST::~CachedAST() { Owner.remove(*this); }
+
----------------
document why


================
Comment at: clangd/TUScheduler.h:48
+/// kept in memory.
+struct ASTRetentionParams {
+  /// Maximum number of ASTs to be retained in memory when there are no pending
----------------
nit: `Policy` would be more specific than `Params`


Repository:
  rCTE Clang Tools Extra

https://reviews.llvm.org/D47063



_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to