Improve memory used in the Web IDE state by moving properties away from the file object

Description

There's opportunity for improving the memory footprint of the Vuex state in the Web IDE... This includes both the actual data being stored but also the number of callbacks and functions registered.

Original description

Over time in the Web IDE we have added more data into the Vuex store, most of the data doesn't get used. We should do an audit on the data & remove the data that is no longer required.

We also need to figure out the hanging when receiving the file list. For this we pass the data into a web worker to put into the format that we require, however when the data comes back Vue makes it reactive which then makes the browser hang (the more files, the larger the hang). I'm not really sure what we can do here, but its worth investigating as its noticeable especially with GitLab CE.

Actionable items

Remove dead code

We'll clearly gain performance / reduce memory usage if we remove dead code. Even if the benefit is like 1ms, we should do it. I have identified that the following properties on the file object are not used anymore:

  1. parentTreeUrl !33654 (merged)
  2. permalink !33654 (merged)
  3. commitsPath !33654 (merged)
  4. blamePath !33654 (merged)
  5. replaces !33654 (merged)
  6. renderError !33654 (merged)
  7. lastCommitPath !33654 (merged)
  8. html !33654 (merged)
  9. renderError !33654 (merged)
  10. lastCommit

Move some properties to view / utils

Some properties on the file object are used in certain views. It is quite wasteful to store that property on every file, instead of computing the property in the particular view:

  1. previewMode -> should be moved to repo_editor.vue, compute based on file extension. !33870 (merged)

  2. eol -> should be moved to ide_status_list.vue, compute based on file contents. !33870 (merged)

  3. fileLanguage -> we can write a util function that asks Monaco what language a file is using based on its extension. This would probably break in the future when we add support for custom languages via .gitattributes, but we can handle that later when we begin implementing that feature.

  4. base64 -> When we upload a new file in the IDE, base64 is set to true, and is false in all other cases. Finally when the file is about to be committed, we use this property to send a key encoding to the backend. The key has two values: text or base64. We can get rid of the base64 property and when we commit, we can use a utility function called isBase64 that computes on the file's rawPath (which will always be a data URL for a base64 file). !33870 (merged)

  5. projectId -> This properties are unnecessary on the file object since at a time only one project and branch can be open in the Web IDE. The usage can be replaced with currentProjectId in state.

  6. branchId -> Same as above. Can be replaced with currentBranchId in state.

  7. url -> Can be computed based on the currentBranchId, currentProjectId and file.path. We can define a getter called getFileURL, that does this job.

  8. parentPath -> There is a util called getPathParent that does this. So we don't need this property on every file.

  9. name -> The name of the file can be computed again by getting the lastPathComponent.

  10. binary -> We have a util function called isTextFile. We can check if a file is binary or not by doing !isTextFile(...).

  11. changed -> We already have an array of changedFiles. We can create a getter called isFileChanged, that looks up the file in that array. This makes our lookup in changedFiles O(n), where n is the size of changed files, but it also reduces memory usage by O(n), where n is the number of files in a repository. So I think this optimises the average case, but worsens the worst case (where a very large folder is renamed and a lot of files are changed).

    Also, since the changedFiles array just contains references to the state.entries object, this can be turned into a Set.

  12. staged -> Same as above, but for stagedFiles array. Except the items in this array are not references, so this array cannot be turned into a Set.

  13. opened -> Similarly, we have an openFiles array. But this one is tricky because we use this property for folders too to determine which folders were open in the file tree. So to solve this one for both files and folders, we might need to introduce a new property in state called openFolders

    Also, if we get rid of the three properties above, we wouldn't need to clone objects to use in staged and opened arrays. So those could be converted to Sets or array of references too.

  14. active -> At a time, there can only be one file active. So it makes sense to turn the existing getter activeFile into a state property instead of storing active on each file.

When we fetch data for a file, do not store all properties the backend returns in Vue state

  • We should only store the properties we really need. See c85b8763.
Edited Jun 16, 2020 by Himanshu Kapoor
Assignee Loading
Time tracking Loading