Repository: mlflow/mlflow
Pull request: Timebased gc
<!-- 🚨 We recommend pull requests be filed from a non-master branch on a repository fork (e.g. <username>:fix-xxx). 🚨 -->

## Related Issues/PRs


<!--
Please reference any related feature requests, issues, or PRs here. For example, `#123`. To automatically close the referenced items when this PR is merged, please use a closing keyword (close, fix, or resolve). For example, `Close #123`. See https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue for more information.
-->
Resolves #6128 

## What changes are proposed in this pull request?

Added `delete_time` column in `Run` table to support `--older-than` flag in `mlflow gc` command. Allows to delete runs marked for deletion that has not been restored by a certain time. 

(Please fill in changes proposed in this fix)

## How is this patch tested?
Unit tests
<!--
If you're unsure about what to test, where to add tests, or how to run tests, please feel free to ask. We'd be happy to help.
-->
- [x] I have written tests (not required for typo or doc fix) and confirmed the proposed feature/bug-fix/change works.

<!--
Please describe how you confirmed the proposed feature/bug-fix/change works here. For example, if you fixed an MLflow client API, you could attach the code that didn't work prior to the fix but works now, or if you added a new feature on MLflow UI, you could attach a video that demonstrates the feature.
-->

Example command to delete runs that are marked for deletion more than 30 days ago.
```sh
mlflow gc --run-ids 52705128 --older-than 30d
```
The `Runs` table has an additional column called `delete_time`, that updates on the timestamp when the run is marked for deletion. This allows the `gc` command to delete runs that are stale for a certain amount of time during routing cleaning. The column is updated to null value once the run is restored from a deleted state.

The `--older-than` flag is a string in #d#h#m#s format. For example: `mlflow gc --older-than 1d2h3m4s` Defaults to 0 (all runs). 

## Does this PR change the documentation?

- [x] No. You can skip the rest of this section.
- [ ] Yes. Make sure the changed pages / sections render correctly by following the steps below.

1. Check the status of the `ci/circleci: build_doc` check. If it's successful, proceed to the
   next step, otherwise fix it.
2. Click `Details` on the right to open the job page of CircleCI.
3. Click the `Artifacts` tab.
4. Click `docs/build/html/index.html`.
5. Find the changed pages / sections and make sure they render correctly.

## Release Notes

### Is this a user-facing change?

- [x] No. You can skip the rest of this section.
- [ ] Yes. Give a description of this change to be included in the release notes for MLflow users.

(Details in 1-2 sentences. You can just refer to another PR with a description if this PR is part of a larger change.)
Added `--older-than` flag in `mlflow gc` command to only hard delete runs that's been marked for deletion for a period of time.

### What component(s), interfaces, languages, and integrations does this PR affect?
Components
- [ ] `area/artifacts`: Artifact stores and artifact logging
- [ ] `area/build`: Build and test infrastructure for MLflow
- [ ] `area/docs`: MLflow documentation pages
- [ ] `area/examples`: Example code
- [ ] `area/model-registry`: Model Registry service, APIs, and the fluent client calls for Model Registry
- [ ] `area/models`: MLmodel format, model serialization/deserialization, flavors
- [ ] `area/pipelines`: Pipelines, Pipeline APIs, Pipeline configs, Pipeline Templates
- [ ] `area/projects`: MLproject format, project running backends
- [ ] `area/scoring`: MLflow Model server, model deployment tools, Spark UDFs
- [ ] `area/server-infra`: MLflow Tracking server backend
- [x] `area/tracking`: Tracking Service, tracking client APIs, autologging

Interface
- [ ] `area/uiux`: Front-end, user experience, plotting, JavaScript, JavaScript dev server
- [ ] `area/docker`: Docker use across MLflow's components, such as MLflow Projects and MLflow Models
- [x] `area/sqlalchemy`: Use of SQLAlchemy in the Tracking Service or Model Registry
- [ ] `area/windows`: Windows support

Language
- [ ] `language/r`: R APIs and clients
- [ ] `language/java`: Java APIs and clients
- [ ] `language/new`: Proposals for new client languages

Integrations
- [ ] `integrations/azure`: Azure and Azure ML integrations
- [ ] `integrations/sagemaker`: SageMaker integrations
- [ ] `integrations/databricks`: Databricks integrations

<!--
Insert an empty named anchor here to allow jumping to this section with a fragment URL
(e.g. https://github.com/mlflow/mlflow/pull/123#user-content-release-note-category).
Note that GitHub prefixes anchor names in markdown with "user-content-".
-->
<a name="release-note-category"></a>
### How should the PR be classified in the release notes? Choose one:

- [ ] `rn/breaking-change` - The PR will be mentioned in the "Breaking Changes" section
- [ ] `rn/none` - No description will be included. The PR will be mentioned only by the PR number in the "Small Bugfixes and Documentation Updates" section
- [x] `rn/feature` - A new user-facing feature worth mentioning in the release notes
- [ ] `rn/bug-fix` - A user-facing bug fix worth mentioning in the release notes
- [ ] `rn/documentation` - A user-facing documentation change worth mentioning in the release notes


Problem statement:
[FR] Run `mlflow gc` based on time since last deletion
### Willingness to contribute

Yes. I would be willing to contribute this feature with guidance from the MLflow community.

### Proposal Summary

Adding more functionality to `mlflow gc`, where administrators can delete runs based on time criteria (e.g. delete runs that have been tagged as `deleted` > 1 month ago). This could be done by adding a `delete_date` column into `runs` table in the sqlstore.

### Motivation

> #### What is the use case for this feature?
Sometimes developers would want to restore their runs that they previously deleted, so just running `mlflow gc` to delete all `deleted` runs periodically might cause developers to lose their data. By being able to delete runs that have been deleted for some time, we can be more sure that the deleted run is no longer needed.

> #### Why is this use case valuable to support for MLflow users in general?
Sometimes developers would want to restore their runs that they previously deleted, so just running `mlflow gc` to delete all `deleted` runs periodically might cause developers to lose their data. By being able to delete runs that have been deleted for some time, we can be more sure that the deleted run is no longer needed.

> #### Why is this use case valuable to support for your project(s) or organization?
Sometimes developers would want to restore their runs that they previously deleted, so just running `mlflow gc` to delete all `deleted` runs periodically might cause developers to lose their data. By being able to delete runs that have been deleted for some time, we can be more sure that the deleted run is no longer needed.

> #### Why is it currently difficult to achieve this use case?
`runs` table only have `start_time` and `end_time` column that tracks when the run is created and finished. However, it does not track when the run is deleted so it is impossible to delete based on this criteria.

### Details

_No response_

### What component(s) does this bug affect?

- [ ] `area/artifacts`: Artifact stores and artifact logging
- [ ] `area/build`: Build and test infrastructure for MLflow
- [ ] `area/docs`: MLflow documentation pages
- [ ] `area/examples`: Example code
- [ ] `area/model-registry`: Model Registry service, APIs, and the fluent client calls for Model Registry
- [ ] `area/models`: MLmodel format, model serialization/deserialization, flavors
- [ ] `area/projects`: MLproject format, project running backends
- [ ] `area/scoring`: MLflow Model server, model deployment tools, Spark UDFs
- [ ] `area/server-infra`: MLflow Tracking server backend
- [ ] `area/tracking`: Tracking Service, tracking client APIs, autologging

### What interface(s) does this bug affect?

- [ ] `area/uiux`: Front-end, user experience, plotting, JavaScript, JavaScript dev server
- [ ] `area/docker`: Docker use across MLflow's components, such as MLflow Projects and MLflow Models
- [X] `area/sqlalchemy`: Use of SQLAlchemy in the Tracking Service or Model Registry
- [ ] `area/windows`: Windows support

### What language(s) does this bug affect?

- [ ] `language/r`: R APIs and clients
- [ ] `language/java`: Java APIs and clients
- [ ] `language/new`: Proposals for new client languages

### What integration(s) does this bug affect?

- [ ] `integrations/azure`: Azure and Azure ML integrations
- [ ] `integrations/sagemaker`: SageMaker integrations
- [ ] `integrations/databricks`: Databricks integrations

Hints from issue discussion:
Hi @Jason-CKY, thank you for requesting this feature. We would be very excited to review a PR that implements it. Feel free to file a pull request, and please let me know if you have any questions. cc @WeichenXu123 
Thanks, was busy for the past few weeks. I will work on this and put up a PR for this feature!

Commit message: Added --older-than flag in mlflow gc command, and added tests for that cli command

Signed-off-by: Jason Cheng <jasoncky96@gmail.com>

Patch to review:
diff --git a/mlflow/cli.py b/mlflow/cli.py
index c35c193d166fe..9ab1a6e82a49c 100644
--- a/mlflow/cli.py
+++ b/mlflow/cli.py
@@ -1,10 +1,13 @@
 import json
 import os
+import time
+import re
 import sys
 import logging
 
 import click
 from click import UsageError
+from datetime import datetime, timedelta
 
 import mlflow.db
 import mlflow.experiments
@@ -483,6 +486,14 @@ def server(
 
 
 @cli.command(short_help="Permanently delete runs in the `deleted` lifecycle stage.")
+@click.option(
+    "--older-than",
+    default="0",
+    help="Optional Remove run(s) older than the specified time limit. "
+    "Specify a string in #d#h#m#s format. "
+    "For example: --older-than 1d2h3m4s"
+    "Defaults to 0 (all runs).",
+)
 @click.option(
     "--backend-store-uri",
     metavar="PATH",
@@ -500,7 +511,7 @@ def server(
     " are not specified, data is removed for all runs in the `deleted`"
     " lifecycle stage.",
 )
-def gc(backend_store_uri, run_ids):
+def gc(older_than, backend_store_uri, run_ids):
     """
     Permanently delete runs in the `deleted` lifecycle stage from the specified backend store.
     This command deletes all artifacts and metadata associated with the specified runs.
@@ -510,8 +521,35 @@ def gc(backend_store_uri, run_ids):
         raise MlflowException(
             "This cli can only be used with a backend that allows hard-deleting runs"
         )
+
+    current_time = int(time.time() * 1000)
+
+    if older_than != "0":
+        regex = re.compile(
+            r"^((?P<days>[\.\d]+?)d)?((?P<hours>[\.\d]+?)h)?((?P<minutes>[\.\d]+?)m)?((?P<seconds>[\.\d]+?)s)?$"
+        )
+        parts = regex.match(older_than)
+        if parts is None:
+            raise MlflowException(
+                "Could not parse any time information from '{}'.  Examples of valid strings: '8h', '2d8h5m20s', '2m4s'".format(
+                    older_than
+                )
+            )
+        time_params = {name: float(param) for name, param in parts.groupdict().items() if param}
+        time_delta = int(timedelta(**time_params).total_seconds() * 1000)
+
     if not run_ids:
-        run_ids = backend_store._get_deleted_runs()
+        if older_than != "0":
+            # filter run_ids based on older_than parameter
+            _run_ids = backend_store._get_deleted_runs()
+            run_ids = []
+            for run_id in _run_ids:
+                run = backend_store.get_run(run_id)
+                if current_time - run.info.delete_time > time_delta:
+                    run_ids.append(run_id)
+        else:
+            run_ids = backend_store._get_deleted_runs()
+
     else:
         run_ids = run_ids.split(",")
 
@@ -522,6 +560,11 @@ def gc(backend_store_uri, run_ids):
                 "Run % is not in `deleted` lifecycle stage. Only runs in "
                 "`deleted` lifecycle stage can be deleted." % run_id
             )
+        # raise MlflowException if run_id is newer than older_than parameter
+        if older_than != "0" and current_time - run.info.delete_time <= time_delta:
+            raise MlflowException(
+                f"Run {run_id} is not older than the required age. Only runs older than {older_than} can be deleted."
+            )
         artifact_repo = get_artifact_repository(run.info.artifact_uri)
         artifact_repo.delete_artifacts()
         backend_store._hard_delete_run(run_id)
diff --git a/mlflow/entities/run_info.py b/mlflow/entities/run_info.py
index 3b7d03a9ded05..0696bad361a30 100644
--- a/mlflow/entities/run_info.py
+++ b/mlflow/entities/run_info.py
@@ -48,6 +48,7 @@ def __init__(
         status,
         start_time,
         end_time,
+        delete_time,
         lifecycle_stage,
         artifact_uri=None,
         run_id=None,
@@ -72,6 +73,7 @@ def __init__(
         self._status = status
         self._start_time = start_time
         self._end_time = end_time
+        self._delete_time = delete_time
         self._lifecycle_stage = lifecycle_stage
         self._artifact_uri = artifact_uri
 
@@ -81,13 +83,17 @@ def __eq__(self, other):
             return self.__dict__ == other.__dict__
         return False
 
-    def _copy_with_overrides(self, status=None, end_time=None, lifecycle_stage=None):
+    def _copy_with_overrides(
+        self, status=None, end_time=None, delete_time=None, lifecycle_stage=None
+    ):
         """A copy of the RunInfo with certain attributes modified."""
         proto = self.to_proto()
         if status:
             proto.status = status
         if end_time:
             proto.end_time = end_time
+        if delete_time or delete_time == 0:
+            proto.delete_time = delete_time
         if lifecycle_stage:
             proto.lifecycle_stage = lifecycle_stage
         return RunInfo.from_proto(proto)
@@ -130,6 +136,11 @@ def end_time(self):
         """End time of the run, in number of milliseconds since the UNIX epoch."""
         return self._end_time
 
+    @orderable_attribute
+    def delete_time(self):
+        """Time of deletion of the run, in number of milliseconds since the UNIX epoch."""
+        return self._delete_time
+
     @searchable_attribute
     def artifact_uri(self):
         """String root artifact URI of the run."""
@@ -149,6 +160,8 @@ def to_proto(self):
         proto.start_time = self.start_time
         if self.end_time:
             proto.end_time = self.end_time
+        if self.delete_time:
+            proto.delete_time = self.delete_time
         if self.artifact_uri:
             proto.artifact_uri = self.artifact_uri
         proto.lifecycle_stage = self.lifecycle_stage
@@ -157,10 +170,13 @@ def to_proto(self):
     @classmethod
     def from_proto(cls, proto):
         end_time = proto.end_time
+        delete_time = proto.delete_time
         # The proto2 default scalar value of zero indicates that the run's end time is absent.
         # An absent end time is represented with a NoneType in the `RunInfo` class
         if end_time == 0:
             end_time = None
+        if delete_time == 0:
+            delete_time = None
         return cls(
             run_uuid=proto.run_uuid,
             run_id=proto.run_id,
@@ -169,6 +185,7 @@ def from_proto(cls, proto):
             status=RunStatus.to_string(proto.status),
             start_time=proto.start_time,
             end_time=end_time,
+            delete_time=delete_time,
             lifecycle_stage=proto.lifecycle_stage,
             artifact_uri=proto.artifact_uri,
         )
diff --git a/mlflow/java/client/src/main/java/org/mlflow/api/proto/Service.java b/mlflow/java/client/src/main/java/org/mlflow/api/proto/Service.java
index 5fef3e6dc7dbd..7e8c6b7dd943f 100644
--- a/mlflow/java/client/src/main/java/org/mlflow/api/proto/Service.java
+++ b/mlflow/java/client/src/main/java/org/mlflow/api/proto/Service.java
@@ -7251,6 +7251,25 @@ public interface RunInfoOrBuilder extends
      */
     long getEndTime();
 
+    /**
+     * <pre>
+     * Unix timestamp of when the run is deleted in milliseconds.
+     * </pre>
+     *
+     * <code>optional int64 delete_time = 10;</code>
+     * @return Whether the deleteTime field is set.
+     */
+    boolean hasDeleteTime();
+    /**
+     * <pre>
+     * Unix timestamp of when the run is deleted in milliseconds.
+     * </pre>
+     *
+     * <code>optional int64 delete_time = 10;</code>
+     * @return The deleteTime.
+     */
+    long getDeleteTime();
+
     /**
      * <pre>
      * URI of the directory where artifacts should be uploaded.
@@ -7415,15 +7434,20 @@ private RunInfo(
               endTime_ = input.readInt64();
               break;
             }
+            case 80: {
+              bitField0_ |= 0x00000080;
+              deleteTime_ = input.readInt64();
+              break;
+            }
             case 106: {
               com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00000080;
+              bitField0_ |= 0x00000100;
               artifactUri_ = bs;
               break;
             }
             case 114: {
               com.google.protobuf.ByteString bs = input.readBytes();
-              bitField0_ |= 0x00000100;
+              bitField0_ |= 0x00000200;
               lifecycleStage_ = bs;
               break;
             }
@@ -7796,6 +7820,33 @@ public long getEndTime() {
       return endTime_;
     }
 
+    public static final int DELETE_TIME_FIELD_NUMBER = 10;
+    private long deleteTime_;
+    /**
+     * <pre>
+     * Unix timestamp of when the run is deleted in milliseconds.
+     * </pre>
+     *
+     * <code>optional int64 delete_time = 10;</code>
+     * @return Whether the deleteTime field is set.
+     */
+    @java.lang.Override
+    public boolean hasDeleteTime() {
+      return ((bitField0_ & 0x00000080) != 0);
+    }
+    /**
+     * <pre>
+     * Unix timestamp of when the run is deleted in milliseconds.
+     * </pre>
+     *
+     * <code>optional int64 delete_time = 10;</code>
+     * @return The deleteTime.
+     */
+    @java.lang.Override
+    public long getDeleteTime() {
+      return deleteTime_;
+    }
+
     public static final int ARTIFACT_URI_FIELD_NUMBER = 13;
     private volatile java.lang.Object artifactUri_;
     /**
@@ -7811,7 +7862,7 @@ public long getEndTime() {
      */
     @java.lang.Override
     public boolean hasArtifactUri() {
-      return ((bitField0_ & 0x00000080) != 0);
+      return ((bitField0_ & 0x00000100) != 0);
     }
     /**
      * <pre>
@@ -7877,7 +7928,7 @@ public java.lang.String getArtifactUri() {
      */
     @java.lang.Override
     public boolean hasLifecycleStage() {
-      return ((bitField0_ & 0x00000100) != 0);
+      return ((bitField0_ & 0x00000200) != 0);
     }
     /**
      * <pre>
@@ -7958,9 +8009,12 @@ public void writeTo(com.google.protobuf.CodedOutputStream output)
         output.writeInt64(9, endTime_);
       }
       if (((bitField0_ & 0x00000080) != 0)) {
-        com.google.protobuf.GeneratedMessageV3.writeString(output, 13, artifactUri_);
+        output.writeInt64(10, deleteTime_);
       }
       if (((bitField0_ & 0x00000100) != 0)) {
+        com.google.protobuf.GeneratedMessageV3.writeString(output, 13, artifactUri_);
+      }
+      if (((bitField0_ & 0x00000200) != 0)) {
         com.google.protobuf.GeneratedMessageV3.writeString(output, 14, lifecycleStage_);
       }
       if (((bitField0_ & 0x00000001) != 0)) {
@@ -7997,9 +8051,13 @@ public int getSerializedSize() {
           .computeInt64Size(9, endTime_);
       }
       if (((bitField0_ & 0x00000080) != 0)) {
-        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(13, artifactUri_);
+        size += com.google.protobuf.CodedOutputStream
+          .computeInt64Size(10, deleteTime_);
       }
       if (((bitField0_ & 0x00000100) != 0)) {
+        size += com.google.protobuf.GeneratedMessageV3.computeStringSize(13, artifactUri_);
+      }
+      if (((bitField0_ & 0x00000200) != 0)) {
         size += com.google.protobuf.GeneratedMessageV3.computeStringSize(14, lifecycleStage_);
       }
       if (((bitField0_ & 0x00000001) != 0)) {
@@ -8054,6 +8112,11 @@ public boolean equals(final java.lang.Object obj) {
         if (getEndTime()
             != other.getEndTime()) return false;
       }
+      if (hasDeleteTime() != other.hasDeleteTime()) return false;
+      if (hasDeleteTime()) {
+        if (getDeleteTime()
+            != other.getDeleteTime()) return false;
+      }
       if (hasArtifactUri() != other.hasArtifactUri()) return false;
       if (hasArtifactUri()) {
         if (!getArtifactUri()
@@ -8105,6 +8168,11 @@ public int hashCode() {
         hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
             getEndTime());
       }
+      if (hasDeleteTime()) {
+        hash = (37 * hash) + DELETE_TIME_FIELD_NUMBER;
+        hash = (53 * hash) + com.google.protobuf.Internal.hashLong(
+            getDeleteTime());
+      }
       if (hasArtifactUri()) {
         hash = (37 * hash) + ARTIFACT_URI_FIELD_NUMBER;
         hash = (53 * hash) + getArtifactUri().hashCode();
@@ -8264,10 +8332,12 @@ public Builder clear() {
         bitField0_ = (bitField0_ & ~0x00000020);
         endTime_ = 0L;
         bitField0_ = (bitField0_ & ~0x00000040);
-        artifactUri_ = "";
+        deleteTime_ = 0L;
         bitField0_ = (bitField0_ & ~0x00000080);
-        lifecycleStage_ = "";
+        artifactUri_ = "";
         bitField0_ = (bitField0_ & ~0x00000100);
+        lifecycleStage_ = "";
+        bitField0_ = (bitField0_ & ~0x00000200);
         return this;
       }
 
@@ -8325,12 +8395,16 @@ public org.mlflow.api.proto.Service.RunInfo buildPartial() {
           to_bitField0_ |= 0x00000040;
         }
         if (((from_bitField0_ & 0x00000080) != 0)) {
+          result.deleteTime_ = deleteTime_;
           to_bitField0_ |= 0x00000080;
         }
-        result.artifactUri_ = artifactUri_;
         if (((from_bitField0_ & 0x00000100) != 0)) {
           to_bitField0_ |= 0x00000100;
         }
+        result.artifactUri_ = artifactUri_;
+        if (((from_bitField0_ & 0x00000200) != 0)) {
+          to_bitField0_ |= 0x00000200;
+        }
         result.lifecycleStage_ = lifecycleStage_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
@@ -8410,13 +8484,16 @@ public Builder mergeFrom(org.mlflow.api.proto.Service.RunInfo other) {
         if (other.hasEndTime()) {
           setEndTime(other.getEndTime());
         }
+        if (other.hasDeleteTime()) {
+          setDeleteTime(other.getDeleteTime());
+        }
         if (other.hasArtifactUri()) {
-          bitField0_ |= 0x00000080;
+          bitField0_ |= 0x00000100;
           artifactUri_ = other.artifactUri_;
           onChanged();
         }
         if (other.hasLifecycleStage()) {
-          bitField0_ |= 0x00000100;
+          bitField0_ |= 0x00000200;
           lifecycleStage_ = other.lifecycleStage_;
           onChanged();
         }
@@ -9069,6 +9146,61 @@ public Builder clearEndTime() {
         return this;
       }
 
+      private long deleteTime_ ;
+      /**
+       * <pre>
+       * Unix timestamp of when the run is deleted in milliseconds.
+       * </pre>
+       *
+       * <code>optional int64 delete_time = 10;</code>
+       * @return Whether the deleteTime field is set.
+       */
+      @java.lang.Override
+      public boolean hasDeleteTime() {
+        return ((bitField0_ & 0x00000080) != 0);
+      }
+      /**
+       * <pre>
+       * Unix timestamp of when the run is deleted in milliseconds.
+       * </pre>
+       *
+       * <code>optional int64 delete_time = 10;</code>
+       * @return The deleteTime.
+       */
+      @java.lang.Override
+      public long getDeleteTime() {
+        return deleteTime_;
+      }
+      /**
+       * <pre>
+       * Unix timestamp of when the run is deleted in milliseconds.
+       * </pre>
+       *
+       * <code>optional int64 delete_time = 10;</code>
+       * @param value The deleteTime to set.
+       * @return This builder for chaining.
+       */
+      public Builder setDeleteTime(long value) {
+        bitField0_ |= 0x00000080;
+        deleteTime_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <pre>
+       * Unix timestamp of when the run is deleted in milliseconds.
+       * </pre>
+       *
+       * <code>optional int64 delete_time = 10;</code>
+       * @return This builder for chaining.
+       */
+      public Builder clearDeleteTime() {
+        bitField0_ = (bitField0_ & ~0x00000080);
+        deleteTime_ = 0L;
+        onChanged();
+        return this;
+      }
+
       private java.lang.Object artifactUri_ = "";
       /**
        * <pre>
@@ -9082,7 +9214,7 @@ public Builder clearEndTime() {
        * @return Whether the artifactUri field is set.
        */
       public boolean hasArtifactUri() {
-        return ((bitField0_ & 0x00000080) != 0);
+        return ((bitField0_ & 0x00000100) != 0);
       }
       /**
        * <pre>
@@ -9150,7 +9282,7 @@ public Builder setArtifactUri(
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00000080;
+  bitField0_ |= 0x00000100;
         artifactUri_ = value;
         onChanged();
         return this;
@@ -9167,7 +9299,7 @@ public Builder setArtifactUri(
        * @return This builder for chaining.
        */
       public Builder clearArtifactUri() {
-        bitField0_ = (bitField0_ & ~0x00000080);
+        bitField0_ = (bitField0_ & ~0x00000100);
         artifactUri_ = getDefaultInstance().getArtifactUri();
         onChanged();
         return this;
@@ -9189,7 +9321,7 @@ public Builder setArtifactUriBytes(
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00000080;
+  bitField0_ |= 0x00000100;
         artifactUri_ = value;
         onChanged();
         return this;
@@ -9205,7 +9337,7 @@ public Builder setArtifactUriBytes(
        * @return Whether the lifecycleStage field is set.
        */
       public boolean hasLifecycleStage() {
-        return ((bitField0_ & 0x00000100) != 0);
+        return ((bitField0_ & 0x00000200) != 0);
       }
       /**
        * <pre>
@@ -9264,7 +9396,7 @@ public Builder setLifecycleStage(
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00000100;
+  bitField0_ |= 0x00000200;
         lifecycleStage_ = value;
         onChanged();
         return this;
@@ -9278,7 +9410,7 @@ public Builder setLifecycleStage(
        * @return This builder for chaining.
        */
       public Builder clearLifecycleStage() {
-        bitField0_ = (bitField0_ & ~0x00000100);
+        bitField0_ = (bitField0_ & ~0x00000200);
         lifecycleStage_ = getDefaultInstance().getLifecycleStage();
         onChanged();
         return this;
@@ -9297,7 +9429,7 @@ public Builder setLifecycleStageBytes(
         if (value == null) {
     throw new NullPointerException();
   }
-  bitField0_ |= 0x00000100;
+  bitField0_ |= 0x00000200;
         lifecycleStage_ = value;
         onChanged();
         return this;
@@ -54153,220 +54285,220 @@ public org.mlflow.api.proto.Service.GetExperimentByName getDefaultInstanceForTyp
       "w.Metric\022\035\n\006params\030\002 \003(\0132\r.mlflow.Param\022" +
       "\034\n\004tags\030\003 \003(\0132\016.mlflow.RunTag\"$\n\006RunTag\022" +
       "\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t\"+\n\rExperimen" +
-      "tTag\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t\"\313\001\n\007Run" +
+      "tTag\022\013\n\003key\030\001 \001(\t\022\r\n\005value\030\002 \001(\t\"\340\001\n\007Run" +
       "Info\022\016\n\006run_id\030\017 \001(\t\022\020\n\010run_uuid\030\001 \001(\t\022\025" +
       "\n\rexperiment_id\030\002 \001(\t\022\017\n\007user_id\030\006 \001(\t\022!" +
       "\n\006status\030\007 \001(\0162\021.mlflow.RunStatus\022\022\n\nsta" +
-      "rt_time\030\010 \001(\003\022\020\n\010end_time\030\t \001(\003\022\024\n\014artif" +
-      "act_uri\030\r \001(\t\022\027\n\017lifecycle_stage\030\016 \001(\t\"\273" +
-      "\001\n\nExperiment\022\025\n\rexperiment_id\030\001 \001(\t\022\014\n\004" +
-      "name\030\002 \001(\t\022\031\n\021artifact_location\030\003 \001(\t\022\027\n" +
-      "\017lifecycle_stage\030\004 \001(\t\022\030\n\020last_update_ti" +
-      "me\030\005 \001(\003\022\025\n\rcreation_time\030\006 \001(\003\022#\n\004tags\030" +
-      "\007 \003(\0132\025.mlflow.ExperimentTag\"\266\001\n\020CreateE" +
-      "xperiment\022\022\n\004name\030\001 \001(\tB\004\370\206\031\001\022\031\n\021artifac" +
-      "t_location\030\002 \001(\t\022#\n\004tags\030\003 \003(\0132\025.mlflow." +
-      "ExperimentTag\032!\n\010Response\022\025\n\rexperiment_" +
-      "id\030\001 \001(\t:+\342?(\n&com.databricks.rpc.RPC[$t" +
-      "his.Response]\"\332\001\n\017ListExperiments\022#\n\tvie" +
-      "w_type\030\001 \001(\0162\020.mlflow.ViewType\022\023\n\013max_re" +
-      "sults\030\002 \001(\003\022\022\n\npage_token\030\003 \001(\t\032L\n\010Respo" +
-      "nse\022\'\n\013experiments\030\001 \003(\0132\022.mlflow.Experi" +
-      "ment\022\027\n\017next_page_token\030\002 \001(\t:+\342?(\n&com." +
-      "databricks.rpc.RPC[$this.Response]\"\376\001\n\021S" +
-      "earchExperiments\022\023\n\013max_results\030\001 \001(\003\022\022\n" +
-      "\npage_token\030\002 \001(\t\022\016\n\006filter\030\003 \001(\t\022\020\n\010ord" +
-      "er_by\030\004 \003(\t\022#\n\tview_type\030\005 \001(\0162\020.mlflow." +
-      "ViewType\032L\n\010Response\022\'\n\013experiments\030\001 \003(" +
-      "\0132\022.mlflow.Experiment\022\027\n\017next_page_token" +
-      "\030\002 \001(\t:+\342?(\n&com.databricks.rpc.RPC[$thi" +
-      "s.Response]\"\260\001\n\rGetExperiment\022\033\n\rexperim" +
-      "ent_id\030\001 \001(\tB\004\370\206\031\001\032U\n\010Response\022&\n\nexperi" +
-      "ment\030\001 \001(\0132\022.mlflow.Experiment\022!\n\004runs\030\002" +
-      " \003(\0132\017.mlflow.RunInfoB\002\030\001:+\342?(\n&com.data" +
-      "bricks.rpc.RPC[$this.Response]\"h\n\020Delete" +
+      "rt_time\030\010 \001(\003\022\020\n\010end_time\030\t \001(\003\022\023\n\013delet" +
+      "e_time\030\n \001(\003\022\024\n\014artifact_uri\030\r \001(\t\022\027\n\017li" +
+      "fecycle_stage\030\016 \001(\t\"\273\001\n\nExperiment\022\025\n\rex" +
+      "periment_id\030\001 \001(\t\022\014\n\004name\030\002 \001(\t\022\031\n\021artif" +
+      "act_location\030\003 \001(\t\022\027\n\017lifecycle_stage\030\004 " +
+      "\001(\t\022\030\n\020last_update_time\030\005 \001(\003\022\025\n\rcreatio" +
+      "n_time\030\006 \001(\003\022#\n\004tags\030\007 \003(\0132\025.mlflow.Expe" +
+      "rimentTag\"\266\001\n\020CreateExperiment\022\022\n\004name\030\001" +
+      " \001(\tB\004\370\206\031\001\022\031\n\021artifact_location\030\002 \001(\t\022#\n" +
+      "\004tags\030\003 \003(\0132\025.mlflow.ExperimentTag\032!\n\010Re" +
+      "sponse\022\025\n\rexperiment_id\030\001 \001(\t:+\342?(\n&com." +
+      "databricks.rpc.RPC[$this.Response]\"\332\001\n\017L" +
+      "istExperiments\022#\n\tview_type\030\001 \001(\0162\020.mlfl" +
+      "ow.ViewType\022\023\n\013max_results\030\002 \001(\003\022\022\n\npage" +
+      "_token\030\003 \001(\t\032L\n\010Response\022\'\n\013experiments\030" +
+      "\001 \003(\0132\022.mlflow.Experiment\022\027\n\017next_page_t" +
+      "oken\030\002 \001(\t:+\342?(\n&com.databricks.rpc.RPC[" +
+      "$this.Response]\"\376\001\n\021SearchExperiments\022\023\n" +
+      "\013max_results\030\001 \001(\003\022\022\n\npage_token\030\002 \001(\t\022\016" +
+      "\n\006filter\030\003 \001(\t\022\020\n\010order_by\030\004 \003(\t\022#\n\tview" +
+      "_type\030\005 \001(\0162\020.mlflow.ViewType\032L\n\010Respons" +
+      "e\022\'\n\013experiments\030\001 \003(\0132\022.mlflow.Experime" +
+      "nt\022\027\n\017next_page_token\030\002 \001(\t:+\342?(\n&com.da" +
+      "tabricks.rpc.RPC[$this.Response]\"\260\001\n\rGet" +
       "Experiment\022\033\n\rexperiment_id\030\001 \001(\tB\004\370\206\031\001\032" +
-      "\n\n\010Response:+\342?(\n&com.databricks.rpc.RPC" +
-      "[$this.Response]\"i\n\021RestoreExperiment\022\033\n" +
-      "\rexperiment_id\030\001 \001(\tB\004\370\206\031\001\032\n\n\010Response:+" +
-      "\342?(\n&com.databricks.rpc.RPC[$this.Respon" +
-      "se]\"z\n\020UpdateExperiment\022\033\n\rexperiment_id" +
-      "\030\001 \001(\tB\004\370\206\031\001\022\020\n\010new_name\030\002 \001(\t\032\n\n\010Respon" +
-      "se:+\342?(\n&com.databricks.rpc.RPC[$this.Re" +
-      "sponse]\"\270\001\n\tCreateRun\022\025\n\rexperiment_id\030\001" +
-      " \001(\t\022\017\n\007user_id\030\002 \001(\t\022\022\n\nstart_time\030\007 \001(" +
-      "\003\022\034\n\004tags\030\t \003(\0132\016.mlflow.RunTag\032$\n\010Respo" +
-      "nse\022\030\n\003run\030\001 \001(\0132\013.mlflow.Run:+\342?(\n&com." +
-      "databricks.rpc.RPC[$this.Response]\"\276\001\n\tU" +
-      "pdateRun\022\016\n\006run_id\030\004 \001(\t\022\020\n\010run_uuid\030\001 \001" +
-      "(\t\022!\n\006status\030\002 \001(\0162\021.mlflow.RunStatus\022\020\n" +
-      "\010end_time\030\003 \001(\003\032-\n\010Response\022!\n\010run_info\030" +
-      "\001 \001(\0132\017.mlflow.RunInfo:+\342?(\n&com.databri" +
-      "cks.rpc.RPC[$this.Response]\"Z\n\tDeleteRun" +
-      "\022\024\n\006run_id\030\001 \001(\tB\004\370\206\031\001\032\n\n\010Response:+\342?(\n" +
-      "&com.databricks.rpc.RPC[$this.Response]\"" +
-      "[\n\nRestoreRun\022\024\n\006run_id\030\001 \001(\tB\004\370\206\031\001\032\n\n\010R" +
-      "esponse:+\342?(\n&com.databricks.rpc.RPC[$th" +
-      "is.Response]\"\270\001\n\tLogMetric\022\016\n\006run_id\030\006 \001" +
-      "(\t\022\020\n\010run_uuid\030\001 \001(\t\022\021\n\003key\030\002 \001(\tB\004\370\206\031\001\022" +
-      "\023\n\005value\030\003 \001(\001B\004\370\206\031\001\022\027\n\ttimestamp\030\004 \001(\003B" +
-      "\004\370\206\031\001\022\017\n\004step\030\005 \001(\003:\0010\032\n\n\010Response:+\342?(\n" +
-      "&com.databricks.rpc.RPC[$this.Response]\"" +
-      "\215\001\n\010LogParam\022\016\n\006run_id\030\004 \001(\t\022\020\n\010run_uuid" +
-      "\030\001 \001(\t\022\021\n\003key\030\002 \001(\tB\004\370\206\031\001\022\023\n\005value\030\003 \001(\t" +
-      "B\004\370\206\031\001\032\n\n\010Response:+\342?(\n&com.databricks." +
-      "rpc.RPC[$this.Response]\"\220\001\n\020SetExperimen" +
-      "tTag\022\033\n\rexperiment_id\030\001 \001(\tB\004\370\206\031\001\022\021\n\003key" +
-      "\030\002 \001(\tB\004\370\206\031\001\022\023\n\005value\030\003 \001(\tB\004\370\206\031\001\032\n\n\010Res" +
-      "ponse:+\342?(\n&com.databricks.rpc.RPC[$this" +
-      ".Response]\"\213\001\n\006SetTag\022\016\n\006run_id\030\004 \001(\t\022\020\n" +
-      "\010run_uuid\030\001 \001(\t\022\021\n\003key\030\002 \001(\tB\004\370\206\031\001\022\023\n\005va" +
-      "lue\030\003 \001(\tB\004\370\206\031\001\032\n\n\010Response:+\342?(\n&com.da" +
-      "tabricks.rpc.RPC[$this.Response]\"m\n\tDele" +
-      "teTag\022\024\n\006run_id\030\001 \001(\tB\004\370\206\031\001\022\021\n\003key\030\002 \001(\t" +
-      "B\004\370\206\031\001\032\n\n\010Response:+\342?(\n&com.databricks." +
-      "rpc.RPC[$this.Response]\"}\n\006GetRun\022\016\n\006run" +
-      "_id\030\002 \001(\t\022\020\n\010run_uuid\030\001 \001(\t\032$\n\010Response\022" +
-      "\030\n\003run\030\001 \001(\0132\013.mlflow.Run:+\342?(\n&com.data" +
-      "bricks.rpc.RPC[$this.Response]\"\230\002\n\nSearc" +
-      "hRuns\022\026\n\016experiment_ids\030\001 \003(\t\022\016\n\006filter\030" +
-      "\004 \001(\t\0224\n\rrun_view_type\030\003 \001(\0162\020.mlflow.Vi" +
-      "ewType:\013ACTIVE_ONLY\022\031\n\013max_results\030\005 \001(\005" +
-      ":\0041000\022\020\n\010order_by\030\006 \003(\t\022\022\n\npage_token\030\007" +
-      " \001(\t\032>\n\010Response\022\031\n\004runs\030\001 \003(\0132\013.mlflow." +
-      "Run\022\027\n\017next_page_token\030\002 \001(\t:+\342?(\n&com.d" +
-      "atabricks.rpc.RPC[$this.Response]\"\330\001\n\rLi" +
-      "stArtifacts\022\016\n\006run_id\030\003 \001(\t\022\020\n\010run_uuid\030" +
-      "\001 \001(\t\022\014\n\004path\030\002 \001(\t\022\022\n\npage_token\030\004 \001(\t\032" +
-      "V\n\010Response\022\020\n\010root_uri\030\001 \001(\t\022\037\n\005files\030\002" +
-      " \003(\0132\020.mlflow.FileInfo\022\027\n\017next_page_toke" +
-      "n\030\003 \001(\t:+\342?(\n&com.databricks.rpc.RPC[$th" +
-      "is.Response]\";\n\010FileInfo\022\014\n\004path\030\001 \001(\t\022\016" +
-      "\n\006is_dir\030\002 \001(\010\022\021\n\tfile_size\030\003 \001(\003\"\250\001\n\020Ge" +
-      "tMetricHistory\022\016\n\006run_id\030\003 \001(\t\022\020\n\010run_uu" +
-      "id\030\001 \001(\t\022\030\n\nmetric_key\030\002 \001(\tB\004\370\206\031\001\032+\n\010Re" +
-      "sponse\022\037\n\007metrics\030\001 \003(\0132\016.mlflow.Metric:" +
+      "U\n\010Response\022&\n\nexperiment\030\001 \001(\0132\022.mlflow" +
+      ".Experiment\022!\n\004runs\030\002 \003(\0132\017.mlflow.RunIn" +
+      "foB\002\030\001:+\342?(\n&com.databricks.rpc.RPC[$thi" +
+      "s.Response]\"h\n\020DeleteExperiment\022\033\n\rexper" +
+      "iment_id\030\001 \001(\tB\004\370\206\031\001\032\n\n\010Response:+\342?(\n&c" +
+      "om.databricks.rpc.RPC[$this.Response]\"i\n" +
+      "\021RestoreExperiment\022\033\n\rexperiment_id\030\001 \001(" +
+      "\tB\004\370\206\031\001\032\n\n\010Response:+\342?(\n&com.databricks" +
+      ".rpc.RPC[$this.Response]\"z\n\020UpdateExperi" +
+      "ment\022\033\n\rexperiment_id\030\001 \001(\tB\004\370\206\031\001\022\020\n\010new" +
+      "_name\030\002 \001(\t\032\n\n\010Response:+\342?(\n&com.databr" +
+      "icks.rpc.RPC[$this.Response]\"\270\001\n\tCreateR" +
+      "un\022\025\n\rexperiment_id\030\001 \001(\t\022\017\n\007user_id\030\002 \001" +
+      "(\t\022\022\n\nstart_time\030\007 \001(\003\022\034\n\004tags\030\t \003(\0132\016.m" +
+      "lflow.RunTag\032$\n\010Response\022\030\n\003run\030\001 \001(\0132\013." +
+      "mlflow.Run:+\342?(\n&com.databricks.rpc.RPC[" +
+      "$this.Response]\"\276\001\n\tUpdateRun\022\016\n\006run_id\030" +
+      "\004 \001(\t\022\020\n\010run_uuid\030\001 \001(\t\022!\n\006status\030\002 \001(\0162" +
+      "\021.mlflow.RunStatus\022\020\n\010end_time\030\003 \001(\003\032-\n\010" +
+      "Response\022!\n\010run_info\030\001 \001(\0132\017.mlflow.RunI" +
+      "nfo:+\342?(\n&com.databricks.rpc.RPC[$this.R" +
+      "esponse]\"Z\n\tDeleteRun\022\024\n\006run_id\030\001 \001(\tB\004\370" +
+      "\206\031\001\032\n\n\010Response:+\342?(\n&com.databricks.rpc" +
+      ".RPC[$this.Response]\"[\n\nRestoreRun\022\024\n\006ru" +
+      "n_id\030\001 \001(\tB\004\370\206\031\001\032\n\n\010Response:+\342?(\n&com.d" +
+      "atabricks.rpc.RPC[$this.Response]\"\270\001\n\tLo" +
+      "gMetric\022\016\n\006run_id\030\006 \001(\t\022\020\n\010run_uuid\030\001 \001(" +
+      "\t\022\021\n\003key\030\002 \001(\tB\004\370\206\031\001\022\023\n\005value\030\003 \001(\001B\004\370\206\031" +
+      "\001\022\027\n\ttimestamp\030\004 \001(\003B\004\370\206\031\001\022\017\n\004step\030\005 \001(\003" +
+      ":\0010\032\n\n\010Response:+\342?(\n&com.databricks.rpc" +
+      ".RPC[$this.Response]\"\215\001\n\010LogParam\022\016\n\006run" +
+      "_id\030\004 \001(\t\022\020\n\010run_uuid\030\001 \001(\t\022\021\n\003key\030\002 \001(\t" +
+      "B\004\370\206\031\001\022\023\n\005value\030\003 \001(\tB\004\370\206\031\001\032\n\n\010Response:" +
+      "+\342?(\n&com.databricks.rpc.RPC[$this.Respo" +
+      "nse]\"\220\001\n\020SetExperimentTag\022\033\n\rexperiment_" +
+      "id\030\001 \001(\tB\004\370\206\031\001\022\021\n\003key\030\002 \001(\tB\004\370\206\031\001\022\023\n\005val" +
+      "ue\030\003 \001(\tB\004\370\206\031\001\032\n\n\010Response:+\342?(\n&com.dat" +
+      "abricks.rpc.RPC[$this.Response]\"\213\001\n\006SetT" +
+      "ag\022\016\n\006run_id\030\004 \001(\t\022\020\n\010run_uuid\030\001 \001(\t\022\021\n\003" +
+      "key\030\002 \001(\tB\004\370\206\031\001\022\023\n\005value\030\003 \001(\tB\004\370\206\031\001\032\n\n\010" +
+      "Response:+\342?(\n&com.databricks.rpc.RPC[$t" +
+      "his.Response]\"m\n\tDeleteTag\022\024\n\006run_id\030\001 \001" +
+      "(\tB\004\370\206\031\001\022\021\n\003key\030\002 \001(\tB\004\370\206\031\001\032\n\n\010Response:" +
       "+\342?(\n&com.databricks.rpc.RPC[$this.Respo" +
-      "nse]\"\261\001\n\010LogBatch\022\016\n\006run_id\030\001 \001(\t\022\037\n\007met" +
-      "rics\030\002 \003(\0132\016.mlflow.Metric\022\035\n\006params\030\003 \003" +
-      "(\0132\r.mlflow.Param\022\034\n\004tags\030\004 \003(\0132\016.mlflow" +
-      ".RunTag\032\n\n\010Response:+\342?(\n&com.databricks" +
-      ".rpc.RPC[$this.Response]\"g\n\010LogModel\022\016\n\006" +
-      "run_id\030\001 \001(\t\022\022\n\nmodel_json\030\002 \001(\t\032\n\n\010Resp" +
-      "onse:+\342?(\n&com.databricks.rpc.RPC[$this." +
-      "Response]\"\225\001\n\023GetExperimentByName\022\035\n\017exp" +
-      "eriment_name\030\001 \001(\tB\004\370\206\031\001\0322\n\010Response\022&\n\n" +
-      "experiment\030\001 \001(\0132\022.mlflow.Experiment:+\342?" +
-      "(\n&com.databricks.rpc.RPC[$this.Response" +
-      "]*6\n\010ViewType\022\017\n\013ACTIVE_ONLY\020\001\022\020\n\014DELETE" +
-      "D_ONLY\020\002\022\007\n\003ALL\020\003*I\n\nSourceType\022\014\n\010NOTEB" +
-      "OOK\020\001\022\007\n\003JOB\020\002\022\013\n\007PROJECT\020\003\022\t\n\005LOCAL\020\004\022\014" +
-      "\n\007UNKNOWN\020\350\007*M\n\tRunStatus\022\013\n\007RUNNING\020\001\022\r" +
-      "\n\tSCHEDULED\020\002\022\014\n\010FINISHED\020\003\022\n\n\006FAILED\020\004\022" +
-      "\n\n\006KILLED\020\0052\373\037\n\rMlflowService\022\246\001\n\023getExp" +
-      "erimentByName\022\033.mlflow.GetExperimentByNa" +
-      "me\032$.mlflow.GetExperimentByName.Response" +
-      "\"L\362\206\031H\n,\n\003GET\022\037/mlflow/experiments/get-b" +
-      "y-name\032\004\010\002\020\000\020\001*\026Get Experiment By Name\022\306" +
-      "\001\n\020createExperiment\022\030.mlflow.CreateExper" +
-      "iment\032!.mlflow.CreateExperiment.Response" +
-      "\"u\362\206\031q\n(\n\004POST\022\032/mlflow/experiments/crea" +
-      "te\032\004\010\002\020\000\n0\n\004POST\022\"/preview/mlflow/experi" +
-      "ments/create\032\004\010\002\020\000\020\001*\021Create Experiment\022" +
-      "\274\001\n\017listExperiments\022\027.mlflow.ListExperim" +
-      "ents\032 .mlflow.ListExperiments.Response\"n" +
-      "\362\206\031j\n%\n\003GET\022\030/mlflow/experiments/list\032\004\010" +
-      "\002\020\000\n-\n\003GET\022 /preview/mlflow/experiments/" +
-      "list\032\004\010\002\020\000\020\001*\020List Experiments\022\227\001\n\021searc" +
-      "hExperiments\022\031.mlflow.SearchExperiments\032" +
-      "\".mlflow.SearchExperiments.Response\"C\362\206\031" +
-      "?\n\'\n\003GET\022\032/mlflow/experiments/search\032\004\010\002" +
-      "\020\000\020\001*\022Search Experiments\022\262\001\n\rgetExperime" +
-      "nt\022\025.mlflow.GetExperiment\032\036.mlflow.GetEx" +
-      "periment.Response\"j\362\206\031f\n$\n\003GET\022\027/mlflow/" +
-      "experiments/get\032\004\010\002\020\000\n,\n\003GET\022\037/preview/m" +
-      "lflow/experiments/get\032\004\010\002\020\000\020\001*\016Get Exper" +
-      "iment\022\306\001\n\020deleteExperiment\022\030.mlflow.Dele" +
-      "teExperiment\032!.mlflow.DeleteExperiment.R" +
-      "esponse\"u\362\206\031q\n(\n\004POST\022\032/mlflow/experimen" +
-      "ts/delete\032\004\010\002\020\000\n0\n\004POST\022\"/preview/mlflow" +
-      "/experiments/delete\032\004\010\002\020\000\020\001*\021Delete Expe" +
-      "riment\022\314\001\n\021restoreExperiment\022\031.mlflow.Re" +
-      "storeExperiment\032\".mlflow.RestoreExperime" +
-      "nt.Response\"x\362\206\031t\n)\n\004POST\022\033/mlflow/exper" +
-      "iments/restore\032\004\010\002\020\000\n1\n\004POST\022#/preview/m" +
-      "lflow/experiments/restore\032\004\010\002\020\000\020\001*\022Resto" +
-      "re Experiment\022\306\001\n\020updateExperiment\022\030.mlf" +
-      "low.UpdateExperiment\032!.mlflow.UpdateExpe" +
-      "riment.Response\"u\362\206\031q\n(\n\004POST\022\032/mlflow/e" +
-      "xperiments/update\032\004\010\002\020\000\n0\n\004POST\022\"/previe" +
-      "w/mlflow/experiments/update\032\004\010\002\020\000\020\001*\021Upd" +
-      "ate Experiment\022\234\001\n\tcreateRun\022\021.mlflow.Cr" +
-      "eateRun\032\032.mlflow.CreateRun.Response\"`\362\206\031" +
-      "\\\n!\n\004POST\022\023/mlflow/runs/create\032\004\010\002\020\000\n)\n\004" +
-      "POST\022\033/preview/mlflow/runs/create\032\004\010\002\020\000\020" +
-      "\001*\nCreate Run\022\234\001\n\tupdateRun\022\021.mlflow.Upd" +
-      "ateRun\032\032.mlflow.UpdateRun.Response\"`\362\206\031\\" +
-      "\n!\n\004POST\022\023/mlflow/runs/update\032\004\010\002\020\000\n)\n\004P" +
-      "OST\022\033/preview/mlflow/runs/update\032\004\010\002\020\000\020\001" +
-      "*\nUpdate Run\022\234\001\n\tdeleteRun\022\021.mlflow.Dele" +
-      "teRun\032\032.mlflow.DeleteRun.Response\"`\362\206\031\\\n" +
-      "!\n\004POST\022\023/mlflow/runs/delete\032\004\010\002\020\000\n)\n\004PO" +
-      "ST\022\033/preview/mlflow/runs/delete\032\004\010\002\020\000\020\001*" +
-      "\nDelete Run\022\242\001\n\nrestoreRun\022\022.mlflow.Rest" +
-      "oreRun\032\033.mlflow.RestoreRun.Response\"c\362\206\031" +
-      "_\n\"\n\004POST\022\024/mlflow/runs/restore\032\004\010\002\020\000\n*\n" +
-      "\004POST\022\034/preview/mlflow/runs/restore\032\004\010\002\020" +
-      "\000\020\001*\013Restore Run\022\244\001\n\tlogMetric\022\021.mlflow." +
-      "LogMetric\032\032.mlflow.LogMetric.Response\"h\362" +
-      "\206\031d\n%\n\004POST\022\027/mlflow/runs/log-metric\032\004\010\002" +
-      "\020\000\n-\n\004POST\022\037/preview/mlflow/runs/log-met" +
-      "ric\032\004\010\002\020\000\020\001*\nLog Metric\022\246\001\n\010logParam\022\020.m" +
-      "lflow.LogParam\032\031.mlflow.LogParam.Respons" +
-      "e\"m\362\206\031i\n(\n\004POST\022\032/mlflow/runs/log-parame" +
-      "ter\032\004\010\002\020\000\n0\n\004POST\022\"/preview/mlflow/runs/" +
-      "log-parameter\032\004\010\002\020\000\020\001*\tLog Param\022\341\001\n\020set" +
-      "ExperimentTag\022\030.mlflow.SetExperimentTag\032" +
-      "!.mlflow.SetExperimentTag.Response\"\217\001\362\206\031" +
-      "\212\001\n4\n\004POST\022&/mlflow/experiments/set-expe" +
-      "riment-tag\032\004\010\002\020\000\n<\n\004POST\022./preview/mlflo" +
-      "w/experiments/set-experiment-tag\032\004\010\002\020\000\020\001" +
-      "*\022Set Experiment Tag\022\222\001\n\006setTag\022\016.mlflow" +
-      ".SetTag\032\027.mlflow.SetTag.Response\"_\362\206\031[\n\"" +
-      "\n\004POST\022\024/mlflow/runs/set-tag\032\004\010\002\020\000\n*\n\004PO" +
-      "ST\022\034/preview/mlflow/runs/set-tag\032\004\010\002\020\000\020\001" +
-      "*\007Set Tag\022\244\001\n\tdeleteTag\022\021.mlflow.DeleteT" +
-      "ag\032\032.mlflow.DeleteTag.Response\"h\362\206\031d\n%\n\004" +
-      "POST\022\027/mlflow/runs/delete-tag\032\004\010\002\020\000\n-\n\004P" +
-      "OST\022\037/preview/mlflow/runs/delete-tag\032\004\010\002" +
-      "\020\000\020\001*\nDelete Tag\022\210\001\n\006getRun\022\016.mlflow.Get" +
-      "Run\032\027.mlflow.GetRun.Response\"U\362\206\031Q\n\035\n\003GE" +
-      "T\022\020/mlflow/runs/get\032\004\010\002\020\000\n%\n\003GET\022\030/previ" +
-      "ew/mlflow/runs/get\032\004\010\002\020\000\020\001*\007Get Run\022\314\001\n\n" +
-      "searchRuns\022\022.mlflow.SearchRuns\032\033.mlflow." +
-      "SearchRuns.Response\"\214\001\362\206\031\207\001\n!\n\004POST\022\023/ml" +
-      "flow/runs/search\032\004\010\002\020\000\n)\n\004POST\022\033/preview" +
-      "/mlflow/runs/search\032\004\010\002\020\000\n(\n\003GET\022\033/previ" +
-      "ew/mlflow/runs/search\032\004\010\002\020\000\020\001*\013Search Ru" +
-      "ns\022\260\001\n\rlistArtifacts\022\025.mlflow.ListArtifa" +
-      "cts\032\036.mlflow.ListArtifacts.Response\"h\362\206\031" +
-      "d\n#\n\003GET\022\026/mlflow/artifacts/list\032\004\010\002\020\000\n+" +
-      "\n\003GET\022\036/preview/mlflow/artifacts/list\032\004\010" +
-      "\002\020\000\020\001*\016List Artifacts\022\307\001\n\020getMetricHisto" +
-      "ry\022\030.mlflow.GetMetricHistory\032!.mlflow.Ge" +
-      "tMetricHistory.Response\"v\362\206\031r\n(\n\003GET\022\033/m" +
-      "lflow/metrics/get-history\032\004\010\002\020\000\n0\n\003GET\022#" +
-      "/preview/mlflow/metrics/get-history\032\004\010\002\020" +
-      "\000\020\001*\022Get Metric History\022\236\001\n\010logBatch\022\020.m" +
-      "lflow.LogBatch\032\031.mlflow.LogBatch.Respons" +
-      "e\"e\362\206\031a\n$\n\004POST\022\026/mlflow/runs/log-batch\032" +
-      "\004\010\002\020\000\n,\n\004POST\022\036/preview/mlflow/runs/log-" +
-      "batch\032\004\010\002\020\000\020\001*\tLog Batch\022\236\001\n\010logModel\022\020." +
-      "mlflow.LogModel\032\031.mlflow.LogModel.Respon" +
-      "se\"e\362\206\031a\n$\n\004POST\022\026/mlflow/runs/log-model" +
-      "\032\004\010\002\020\000\n,\n\004POST\022\036/preview/mlflow/runs/log" +
-      "-model\032\004\010\002\020\000\020\001*\tLog ModelB\036\n\024org.mlflow." +
-      "api.proto\220\001\001\342?\002\020\001"
+      "nse]\"}\n\006GetRun\022\016\n\006run_id\030\002 \001(\t\022\020\n\010run_uu" +
+      "id\030\001 \001(\t\032$\n\010Response\022\030\n\003run\030\001 \001(\0132\013.mlfl" +
+      "ow.Run:+\342?(\n&com.databricks.rpc.RPC[$thi" +
+      "s.Response]\"\230\002\n\nSearchRuns\022\026\n\016experiment" +
+      "_ids\030\001 \003(\t\022\016\n\006filter\030\004 \001(\t\0224\n\rrun_view_t" +
+      "ype\030\003 \001(\0162\020.mlflow.ViewType:\013ACTIVE_ONLY" +
+      "\022\031\n\013max_results\030\005 \001(\005:\0041000\022\020\n\010order_by\030" +
+      "\006 \003(\t\022\022\n\npage_token\030\007 \001(\t\032>\n\010Response\022\031\n" +
+      "\004runs\030\001 \003(\0132\013.mlflow.Run\022\027\n\017next_page_to" +
+      "ken\030\002 \001(\t:+\342?(\n&com.databricks.rpc.RPC[$" +
+      "this.Response]\"\330\001\n\rListArtifacts\022\016\n\006run_" +
+      "id\030\003 \001(\t\022\020\n\010run_uuid\030\001 \001(\t\022\014\n\004path\030\002 \001(\t" +
+      "\022\022\n\npage_token\030\004 \001(\t\032V\n\010Response\022\020\n\010root" +
+      "_uri\030\001 \001(\t\022\037\n\005files\030\002 \003(\0132\020.mlflow.FileI" +
+      "nfo\022\027\n\017next_page_token\030\003 \001(\t:+\342?(\n&com.d" +
+      "atabricks.rpc.RPC[$this.Response]\";\n\010Fil" +
+      "eInfo\022\014\n\004path\030\001 \001(\t\022\016\n\006is_dir\030\002 \001(\010\022\021\n\tf" +
+      "ile_size\030\003 \001(\003\"\250\001\n\020GetMetricHistory\022\016\n\006r" +
+      "un_id\030\003 \001(\t\022\020\n\010run_uuid\030\001 \001(\t\022\030\n\nmetric_" +
+      "key\030\002 \001(\tB\004\370\206\031\001\032+\n\010Response\022\037\n\007metrics\030\001" +
+      " \003(\0132\016.mlflow.Metric:+\342?(\n&com.databrick" +
+      "s.rpc.RPC[$this.Response]\"\261\001\n\010LogBatch\022\016" +
+      "\n\006run_id\030\001 \001(\t\022\037\n\007metrics\030\002 \003(\0132\016.mlflow" +
+      ".Metric\022\035\n\006params\030\003 \003(\0132\r.mlflow.Param\022\034" +
+      "\n\004tags\030\004 \003(\0132\016.mlflow.RunTag\032\n\n\010Response" +
+      ":+\342?(\n&com.databricks.rpc.RPC[$this.Resp" +
+      "onse]\"g\n\010LogModel\022\016\n\006run_id\030\001 \001(\t\022\022\n\nmod" +
+      "el_json\030\002 \001(\t\032\n\n\010Response:+\342?(\n&com.data" +
+      "bricks.rpc.RPC[$this.Response]\"\225\001\n\023GetEx" +
+      "perimentByName\022\035\n\017experiment_name\030\001 \001(\tB" +
+      "\004\370\206\031\001\0322\n\010Response\022&\n\nexperiment\030\001 \001(\0132\022." +
+      "mlflow.Experiment:+\342?(\n&com.databricks.r" +
+      "pc.RPC[$this.Response]*6\n\010ViewType\022\017\n\013AC" +
+      "TIVE_ONLY\020\001\022\020\n\014DELETED_ONLY\020\002\022\007\n\003ALL\020\003*I" +
+      "\n\nSourceType\022\014\n\010NOTEBOOK\020\001\022\007\n\003JOB\020\002\022\013\n\007P" +
+      "ROJECT\020\003\022\t\n\005LOCAL\020\004\022\014\n\007UNKNOWN\020\350\007*M\n\tRun" +
+      "Status\022\013\n\007RUNNING\020\001\022\r\n\tSCHEDULED\020\002\022\014\n\010FI" +
+      "NISHED\020\003\022\n\n\006FAILED\020\004\022\n\n\006KILLED\020\0052\373\037\n\rMlf" +
+      "lowService\022\246\001\n\023getExperimentByName\022\033.mlf" +
+      "low.GetExperimentByName\032$.mlflow.GetExpe" +
+      "rimentByName.Response\"L\362\206\031H\n,\n\003GET\022\037/mlf" +
+      "low/experiments/get-by-name\032\004\010\002\020\000\020\001*\026Get" +
+      " Experiment By Name\022\306\001\n\020createExperiment" +
+      "\022\030.mlflow.CreateExperiment\032!.mlflow.Crea" +
+      "teExperiment.Response\"u\362\206\031q\n(\n\004POST\022\032/ml" +
+      "flow/experiments/create\032\004\010\002\020\000\n0\n\004POST\022\"/" +
+      "preview/mlflow/experiments/create\032\004\010\002\020\000\020" +
+      "\001*\021Create Experiment\022\274\001\n\017listExperiments" +
+      "\022\027.mlflow.ListExperiments\032 .mlflow.ListE" +
+      "xperiments.Response\"n\362\206\031j\n%\n\003GET\022\030/mlflo" +
+      "w/experiments/list\032\004\010\002\020\000\n-\n\003GET\022 /previe" +
+      "w/mlflow/experiments/list\032\004\010\002\020\000\020\001*\020List " +
+      "Experiments\022\227\001\n\021searchExperiments\022\031.mlfl" +
+      "ow.SearchExperiments\032\".mlflow.SearchExpe" +
+      "riments.Response\"C\362\206\031?\n\'\n\003GET\022\032/mlflow/e" +
+      "xperiments/search\032\004\010\002\020\000\020\001*\022Search Experi" +
+      "ments\022\262\001\n\rgetExperiment\022\025.mlflow.GetExpe" +
+      "riment\032\036.mlflow.GetExperiment.Response\"j" +
+      "\362\206\031f\n$\n\003GET\022\027/mlflow/experiments/get\032\004\010\002" +
+      "\020\000\n,\n\003GET\022\037/preview/mlflow/experiments/g" +
+      "et\032\004\010\002\020\000\020\001*\016Get Experiment\022\306\001\n\020deleteExp" +
+      "eriment\022\030.mlflow.DeleteExperiment\032!.mlfl" +
+      "ow.DeleteExperiment.Response\"u\362\206\031q\n(\n\004PO" +
+      "ST\022\032/mlflow/experiments/delete\032\004\010\002\020\000\n0\n\004" +
+      "POST\022\"/preview/mlflow/experiments/delete" +
+      "\032\004\010\002\020\000\020\001*\021Delete Experiment\022\314\001\n\021restoreE" +
+      "xperiment\022\031.mlflow.RestoreExperiment\032\".m" +
+      "lflow.RestoreExperiment.Response\"x\362\206\031t\n)" +
+      "\n\004POST\022\033/mlflow/experiments/restore\032\004\010\002\020" +
+      "\000\n1\n\004POST\022#/preview/mlflow/experiments/r" +
+      "estore\032\004\010\002\020\000\020\001*\022Restore Experiment\022\306\001\n\020u" +
+      "pdateExperiment\022\030.mlflow.UpdateExperimen" +
+      "t\032!.mlflow.UpdateExperiment.Response\"u\362\206" +
+      "\031q\n(\n\004POST\022\032/mlflow/experiments/update\032\004" +
+      "\010\002\020\000\n0\n\004POST\022\"/preview/mlflow/experiment" +
+      "s/update\032\004\010\002\020\000\020\001*\021Update Experiment\022\234\001\n\t" +
+      "createRun\022\021.mlflow.CreateRun\032\032.mlflow.Cr" +
+      "eateRun.Response\"`\362\206\031\\\n!\n\004POST\022\023/mlflow/" +
+      "runs/create\032\004\010\002\020\000\n)\n\004POST\022\033/preview/mlfl" +
+      "ow/runs/create\032\004\010\002\020\000\020\001*\nCreate Run\022\234\001\n\tu" +
+      "pdateRun\022\021.mlflow.UpdateRun\032\032.mlflow.Upd" +
+      "ateRun.Response\"`\362\206\031\\\n!\n\004POST\022\023/mlflow/r" +
+      "uns/update\032\004\010\002\020\000\n)\n\004POST\022\033/preview/mlflo" +
+      "w/runs/update\032\004\010\002\020\000\020\001*\nUpdate Run\022\234\001\n\tde" +
+      "leteRun\022\021.mlflow.DeleteRun\032\032.mlflow.Dele" +
+      "teRun.Response\"`\362\206\031\\\n!\n\004POST\022\023/mlflow/ru" +
+      "ns/delete\032\004\010\002\020\000\n)\n\004POST\022\033/preview/mlflow" +
+      "/runs/delete\032\004\010\002\020\000\020\001*\nDelete Run\022\242\001\n\nres" +
+      "toreRun\022\022.mlflow.RestoreRun\032\033.mlflow.Res" +
+      "toreRun.Response\"c\362\206\031_\n\"\n\004POST\022\024/mlflow/" +
+      "runs/restore\032\004\010\002\020\000\n*\n\004POST\022\034/preview/mlf" +
+      "low/runs/restore\032\004\010\002\020\000\020\001*\013Restore Run\022\244\001" +
+      "\n\tlogMetric\022\021.mlflow.LogMetric\032\032.mlflow." +
+      "LogMetric.Response\"h\362\206\031d\n%\n\004POST\022\027/mlflo" +
+      "w/runs/log-metric\032\004\010\002\020\000\n-\n\004POST\022\037/previe" +
+      "w/mlflow/runs/log-metric\032\004\010\002\020\000\020\001*\nLog Me" +
+      "tric\022\246\001\n\010logParam\022\020.mlflow.LogParam\032\031.ml" +
+      "flow.LogParam.Response\"m\362\206\031i\n(\n\004POST\022\032/m" +
+      "lflow/runs/log-parameter\032\004\010\002\020\000\n0\n\004POST\022\"" +
+      "/preview/mlflow/runs/log-parameter\032\004\010\002\020\000" +
+      "\020\001*\tLog Param\022\341\001\n\020setExperimentTag\022\030.mlf" +
+      "low.SetExperimentTag\032!.mlflow.SetExperim" +
+      "entTag.Response\"\217\001\362\206\031\212\001\n4\n\004POST\022&/mlflow" +
+      "/experiments/set-experiment-tag\032\004\010\002\020\000\n<\n" +
+      "\004POST\022./preview/mlflow/experiments/set-e" +
+      "xperiment-tag\032\004\010\002\020\000\020\001*\022Set Experiment Ta" +
+      "g\022\222\001\n\006setTag\022\016.mlflow.SetTag\032\027.mlflow.Se" +
+      "tTag.Response\"_\362\206\031[\n\"\n\004POST\022\024/mlflow/run" +
+      "s/set-tag\032\004\010\002\020\000\n*\n\004POST\022\034/preview/mlflow" +
+      "/runs/set-tag\032\004\010\002\020\000\020\001*\007Set Tag\022\244\001\n\tdelet" +
+      "eTag\022\021.mlflow.DeleteTag\032\032.mlflow.DeleteT" +
+      "ag.Response\"h\362\206\031d\n%\n\004POST\022\027/mlflow/runs/" +
+      "delete-tag\032\004\010\002\020\000\n-\n\004POST\022\037/preview/mlflo" +
+      "w/runs/delete-tag\032\004\010\002\020\000\020\001*\nDelete Tag\022\210\001" +
+      "\n\006getRun\022\016.mlflow.GetRun\032\027.mlflow.GetRun" +
+      ".Response\"U\362\206\031Q\n\035\n\003GET\022\020/mlflow/runs/get" +
+      "\032\004\010\002\020\000\n%\n\003GET\022\030/preview/mlflow/runs/get\032" +
+      "\004\010\002\020\000\020\001*\007Get Run\022\314\001\n\nsearchRuns\022\022.mlflow" +
+      ".SearchRuns\032\033.mlflow.SearchRuns.Response" +
+      "\"\214\001\362\206\031\207\001\n!\n\004POST\022\023/mlflow/runs/search\032\004\010" +
+      "\002\020\000\n)\n\004POST\022\033/preview/mlflow/runs/search" +
+      "\032\004\010\002\020\000\n(\n\003GET\022\033/preview/mlflow/runs/sear" +
+      "ch\032\004\010\002\020\000\020\001*\013Search Runs\022\260\001\n\rlistArtifact" +
+      "s\022\025.mlflow.ListArtifacts\032\036.mlflow.ListAr" +
+      "tifacts.Response\"h\362\206\031d\n#\n\003GET\022\026/mlflow/a" +
+      "rtifacts/list\032\004\010\002\020\000\n+\n\003GET\022\036/preview/mlf" +
+      "low/artifacts/list\032\004\010\002\020\000\020\001*\016List Artifac" +
+      "ts\022\307\001\n\020getMetricHistory\022\030.mlflow.GetMetr" +
+      "icHistory\032!.mlflow.GetMetricHistory.Resp" +
+      "onse\"v\362\206\031r\n(\n\003GET\022\033/mlflow/metrics/get-h" +
+      "istory\032\004\010\002\020\000\n0\n\003GET\022#/preview/mlflow/met" +
+      "rics/get-history\032\004\010\002\020\000\020\001*\022Get Metric His" +
+      "tory\022\236\001\n\010logBatch\022\020.mlflow.LogBatch\032\031.ml" +
+      "flow.LogBatch.Response\"e\362\206\031a\n$\n\004POST\022\026/m" +
+      "lflow/runs/log-batch\032\004\010\002\020\000\n,\n\004POST\022\036/pre" +
+      "view/mlflow/runs/log-batch\032\004\010\002\020\000\020\001*\tLog " +
+      "Batch\022\236\001\n\010logModel\022\020.mlflow.LogModel\032\031.m" +
+      "lflow.LogModel.Response\"e\362\206\031a\n$\n\004POST\022\026/" +
+      "mlflow/runs/log-model\032\004\010\002\020\000\n,\n\004POST\022\036/pr" +
+      "eview/mlflow/runs/log-model\032\004\010\002\020\000\020\001*\tLog" +
+      " ModelB\036\n\024org.mlflow.api.proto\220\001\001\342?\002\020\001"
     };
     descriptor = com.google.protobuf.Descriptors.FileDescriptor
       .internalBuildGeneratedFileFrom(descriptorData,
@@ -54415,7 +54547,7 @@ public org.mlflow.api.proto.Service.GetExperimentByName getDefaultInstanceForTyp
     internal_static_mlflow_RunInfo_fieldAccessorTable = new
       com.google.protobuf.GeneratedMessageV3.FieldAccessorTable(
         internal_static_mlflow_RunInfo_descriptor,
-        new java.lang.String[] { "RunId", "RunUuid", "ExperimentId", "UserId", "Status", "StartTime", "EndTime", "ArtifactUri", "LifecycleStage", });
+        new java.lang.String[] { "RunId", "RunUuid", "ExperimentId", "UserId", "Status", "StartTime", "EndTime", "DeleteTime", "ArtifactUri", "LifecycleStage", });
     internal_static_mlflow_Experiment_descriptor =
       getDescriptor().getMessageTypes().get(7);
     internal_static_mlflow_Experiment_fieldAccessorTable = new
diff --git a/mlflow/protos/service.proto b/mlflow/protos/service.proto
index afcd1924de72d..daa6d9efaf58f 100644
--- a/mlflow/protos/service.proto
+++ b/mlflow/protos/service.proto
@@ -636,6 +636,9 @@ message RunInfo {
   // Unix timestamp of when the run ended in milliseconds.
   optional int64 end_time = 9;
 
+  // Unix timestamp of when the run is deleted in milliseconds.
+  optional int64 delete_time = 10;
+
   // URI of the directory where artifacts should be uploaded.
   // This can be a local path (starting with "/"), or a distributed file system (DFS)
   // path, like ``s3://bucket/directory`` or ``dbfs:/my/directory``.
diff --git a/mlflow/protos/service_pb2.py b/mlflow/protos/service_pb2.py
index 0878e27915539..35d4e38592498 100644
--- a/mlflow/protos/service_pb2.py
+++ b/mlflow/protos/service_pb2.py
@@ -19,7 +19,7 @@
 from . import databricks_pb2 as databricks__pb2
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rservice.proto\x12\x06mlflow\x1a\x15scalapb/scalapb.proto\x1a\x10\x64\x61tabricks.proto\"H\n\x06Metric\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x01\x12\x11\n\ttimestamp\x18\x03 \x01(\x03\x12\x0f\n\x04step\x18\x04 \x01(\x03:\x01\x30\"#\n\x05Param\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"C\n\x03Run\x12\x1d\n\x04info\x18\x01 \x01(\x0b\x32\x0f.mlflow.RunInfo\x12\x1d\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x0f.mlflow.RunData\"g\n\x07RunData\x12\x1f\n\x07metrics\x18\x01 \x03(\x0b\x32\x0e.mlflow.Metric\x12\x1d\n\x06params\x18\x02 \x03(\x0b\x32\r.mlflow.Param\x12\x1c\n\x04tags\x18\x03 \x03(\x0b\x32\x0e.mlflow.RunTag\"$\n\x06RunTag\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"+\n\rExperimentTag\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xcb\x01\n\x07RunInfo\x12\x0e\n\x06run_id\x18\x0f \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x15\n\rexperiment_id\x18\x02 \x01(\t\x12\x0f\n\x07user_id\x18\x06 \x01(\t\x12!\n\x06status\x18\x07 \x01(\x0e\x32\x11.mlflow.RunStatus\x12\x12\n\nstart_time\x18\x08 \x01(\x03\x12\x10\n\x08\x65nd_time\x18\t \x01(\x03\x12\x14\n\x0c\x61rtifact_uri\x18\r \x01(\t\x12\x17\n\x0flifecycle_stage\x18\x0e \x01(\t\"\xbb\x01\n\nExperiment\x12\x15\n\rexperiment_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x19\n\x11\x61rtifact_location\x18\x03 \x01(\t\x12\x17\n\x0flifecycle_stage\x18\x04 \x01(\t\x12\x18\n\x10last_update_time\x18\x05 \x01(\x03\x12\x15\n\rcreation_time\x18\x06 \x01(\x03\x12#\n\x04tags\x18\x07 \x03(\x0b\x32\x15.mlflow.ExperimentTag\"\xb6\x01\n\x10\x43reateExperiment\x12\x12\n\x04name\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x12\x19\n\x11\x61rtifact_location\x18\x02 \x01(\t\x12#\n\x04tags\x18\x03 \x03(\x0b\x32\x15.mlflow.ExperimentTag\x1a!\n\x08Response\x12\x15\n\rexperiment_id\x18\x01 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xda\x01\n\x0fListExperiments\x12#\n\tview_type\x18\x01 \x01(\x0e\x32\x10.mlflow.ViewType\x12\x13\n\x0bmax_results\x18\x02 \x01(\x03\x12\x12\n\npage_token\x18\x03 \x01(\t\x1aL\n\x08Response\x12\'\n\x0b\x65xperiments\x18\x01 \x03(\x0b\x32\x12.mlflow.Experiment\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xfe\x01\n\x11SearchExperiments\x12\x13\n\x0bmax_results\x18\x01 \x01(\x03\x12\x12\n\npage_token\x18\x02 \x01(\t\x12\x0e\n\x06\x66ilter\x18\x03 \x01(\t\x12\x10\n\x08order_by\x18\x04 \x03(\t\x12#\n\tview_type\x18\x05 \x01(\x0e\x32\x10.mlflow.ViewType\x1aL\n\x08Response\x12\'\n\x0b\x65xperiments\x18\x01 \x03(\x0b\x32\x12.mlflow.Experiment\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xb0\x01\n\rGetExperiment\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1aU\n\x08Response\x12&\n\nexperiment\x18\x01 \x01(\x0b\x32\x12.mlflow.Experiment\x12!\n\x04runs\x18\x02 \x03(\x0b\x32\x0f.mlflow.RunInfoB\x02\x18\x01:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"h\n\x10\x44\x65leteExperiment\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"i\n\x11RestoreExperiment\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"z\n\x10UpdateExperiment\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x12\x10\n\x08new_name\x18\x02 \x01(\t\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xb8\x01\n\tCreateRun\x12\x15\n\rexperiment_id\x18\x01 \x01(\t\x12\x0f\n\x07user_id\x18\x02 \x01(\t\x12\x12\n\nstart_time\x18\x07 \x01(\x03\x12\x1c\n\x04tags\x18\t \x03(\x0b\x32\x0e.mlflow.RunTag\x1a$\n\x08Response\x12\x18\n\x03run\x18\x01 \x01(\x0b\x32\x0b.mlflow.Run:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xbe\x01\n\tUpdateRun\x12\x0e\n\x06run_id\x18\x04 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12!\n\x06status\x18\x02 \x01(\x0e\x32\x11.mlflow.RunStatus\x12\x10\n\x08\x65nd_time\x18\x03 \x01(\x03\x1a-\n\x08Response\x12!\n\x08run_info\x18\x01 \x01(\x0b\x32\x0f.mlflow.RunInfo:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"Z\n\tDeleteRun\x12\x14\n\x06run_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"[\n\nRestoreRun\x12\x14\n\x06run_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xb8\x01\n\tLogMetric\x12\x0e\n\x06run_id\x18\x06 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x12\x13\n\x05value\x18\x03 \x01(\x01\x42\x04\xf8\x86\x19\x01\x12\x17\n\ttimestamp\x18\x04 \x01(\x03\x42\x04\xf8\x86\x19\x01\x12\x0f\n\x04step\x18\x05 \x01(\x03:\x01\x30\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x8d\x01\n\x08LogParam\x12\x0e\n\x06run_id\x18\x04 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x12\x13\n\x05value\x18\x03 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x90\x01\n\x10SetExperimentTag\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x12\x13\n\x05value\x18\x03 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x8b\x01\n\x06SetTag\x12\x0e\n\x06run_id\x18\x04 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x12\x13\n\x05value\x18\x03 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"m\n\tDeleteTag\x12\x14\n\x06run_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"}\n\x06GetRun\x12\x0e\n\x06run_id\x18\x02 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x1a$\n\x08Response\x12\x18\n\x03run\x18\x01 \x01(\x0b\x32\x0b.mlflow.Run:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x98\x02\n\nSearchRuns\x12\x16\n\x0e\x65xperiment_ids\x18\x01 \x03(\t\x12\x0e\n\x06\x66ilter\x18\x04 \x01(\t\x12\x34\n\rrun_view_type\x18\x03 \x01(\x0e\x32\x10.mlflow.ViewType:\x0b\x41\x43TIVE_ONLY\x12\x19\n\x0bmax_results\x18\x05 \x01(\x05:\x04\x31\x30\x30\x30\x12\x10\n\x08order_by\x18\x06 \x03(\t\x12\x12\n\npage_token\x18\x07 \x01(\t\x1a>\n\x08Response\x12\x19\n\x04runs\x18\x01 \x03(\x0b\x32\x0b.mlflow.Run\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xd8\x01\n\rListArtifacts\x12\x0e\n\x06run_id\x18\x03 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\x12\n\npage_token\x18\x04 \x01(\t\x1aV\n\x08Response\x12\x10\n\x08root_uri\x18\x01 \x01(\t\x12\x1f\n\x05\x66iles\x18\x02 \x03(\x0b\x32\x10.mlflow.FileInfo\x12\x17\n\x0fnext_page_token\x18\x03 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\";\n\x08\x46ileInfo\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0e\n\x06is_dir\x18\x02 \x01(\x08\x12\x11\n\tfile_size\x18\x03 \x01(\x03\"\xa8\x01\n\x10GetMetricHistory\x12\x0e\n\x06run_id\x18\x03 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x18\n\nmetric_key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x1a+\n\x08Response\x12\x1f\n\x07metrics\x18\x01 \x03(\x0b\x32\x0e.mlflow.Metric:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xb1\x01\n\x08LogBatch\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x1f\n\x07metrics\x18\x02 \x03(\x0b\x32\x0e.mlflow.Metric\x12\x1d\n\x06params\x18\x03 \x03(\x0b\x32\r.mlflow.Param\x12\x1c\n\x04tags\x18\x04 \x03(\x0b\x32\x0e.mlflow.RunTag\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"g\n\x08LogModel\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x12\n\nmodel_json\x18\x02 \x01(\t\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x95\x01\n\x13GetExperimentByName\x12\x1d\n\x0f\x65xperiment_name\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\x32\n\x08Response\x12&\n\nexperiment\x18\x01 \x01(\x0b\x32\x12.mlflow.Experiment:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]*6\n\x08ViewType\x12\x0f\n\x0b\x41\x43TIVE_ONLY\x10\x01\x12\x10\n\x0c\x44\x45LETED_ONLY\x10\x02\x12\x07\n\x03\x41LL\x10\x03*I\n\nSourceType\x12\x0c\n\x08NOTEBOOK\x10\x01\x12\x07\n\x03JOB\x10\x02\x12\x0b\n\x07PROJECT\x10\x03\x12\t\n\x05LOCAL\x10\x04\x12\x0c\n\x07UNKNOWN\x10\xe8\x07*M\n\tRunStatus\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tSCHEDULED\x10\x02\x12\x0c\n\x08\x46INISHED\x10\x03\x12\n\n\x06\x46\x41ILED\x10\x04\x12\n\n\x06KILLED\x10\x05\x32\xfb\x1f\n\rMlflowService\x12\xa6\x01\n\x13getExperimentByName\x12\x1b.mlflow.GetExperimentByName\x1a$.mlflow.GetExperimentByName.Response\"L\xf2\x86\x19H\n,\n\x03GET\x12\x1f/mlflow/experiments/get-by-name\x1a\x04\x08\x02\x10\x00\x10\x01*\x16Get Experiment By Name\x12\xc6\x01\n\x10\x63reateExperiment\x12\x18.mlflow.CreateExperiment\x1a!.mlflow.CreateExperiment.Response\"u\xf2\x86\x19q\n(\n\x04POST\x12\x1a/mlflow/experiments/create\x1a\x04\x08\x02\x10\x00\n0\n\x04POST\x12\"/preview/mlflow/experiments/create\x1a\x04\x08\x02\x10\x00\x10\x01*\x11\x43reate Experiment\x12\xbc\x01\n\x0flistExperiments\x12\x17.mlflow.ListExperiments\x1a .mlflow.ListExperiments.Response\"n\xf2\x86\x19j\n%\n\x03GET\x12\x18/mlflow/experiments/list\x1a\x04\x08\x02\x10\x00\n-\n\x03GET\x12 /preview/mlflow/experiments/list\x1a\x04\x08\x02\x10\x00\x10\x01*\x10List Experiments\x12\x97\x01\n\x11searchExperiments\x12\x19.mlflow.SearchExperiments\x1a\".mlflow.SearchExperiments.Response\"C\xf2\x86\x19?\n\'\n\x03GET\x12\x1a/mlflow/experiments/search\x1a\x04\x08\x02\x10\x00\x10\x01*\x12Search Experiments\x12\xb2\x01\n\rgetExperiment\x12\x15.mlflow.GetExperiment\x1a\x1e.mlflow.GetExperiment.Response\"j\xf2\x86\x19\x66\n$\n\x03GET\x12\x17/mlflow/experiments/get\x1a\x04\x08\x02\x10\x00\n,\n\x03GET\x12\x1f/preview/mlflow/experiments/get\x1a\x04\x08\x02\x10\x00\x10\x01*\x0eGet Experiment\x12\xc6\x01\n\x10\x64\x65leteExperiment\x12\x18.mlflow.DeleteExperiment\x1a!.mlflow.DeleteExperiment.Response\"u\xf2\x86\x19q\n(\n\x04POST\x12\x1a/mlflow/experiments/delete\x1a\x04\x08\x02\x10\x00\n0\n\x04POST\x12\"/preview/mlflow/experiments/delete\x1a\x04\x08\x02\x10\x00\x10\x01*\x11\x44\x65lete Experiment\x12\xcc\x01\n\x11restoreExperiment\x12\x19.mlflow.RestoreExperiment\x1a\".mlflow.RestoreExperiment.Response\"x\xf2\x86\x19t\n)\n\x04POST\x12\x1b/mlflow/experiments/restore\x1a\x04\x08\x02\x10\x00\n1\n\x04POST\x12#/preview/mlflow/experiments/restore\x1a\x04\x08\x02\x10\x00\x10\x01*\x12Restore Experiment\x12\xc6\x01\n\x10updateExperiment\x12\x18.mlflow.UpdateExperiment\x1a!.mlflow.UpdateExperiment.Response\"u\xf2\x86\x19q\n(\n\x04POST\x12\x1a/mlflow/experiments/update\x1a\x04\x08\x02\x10\x00\n0\n\x04POST\x12\"/preview/mlflow/experiments/update\x1a\x04\x08\x02\x10\x00\x10\x01*\x11Update Experiment\x12\x9c\x01\n\tcreateRun\x12\x11.mlflow.CreateRun\x1a\x1a.mlflow.CreateRun.Response\"`\xf2\x86\x19\\\n!\n\x04POST\x12\x13/mlflow/runs/create\x1a\x04\x08\x02\x10\x00\n)\n\x04POST\x12\x1b/preview/mlflow/runs/create\x1a\x04\x08\x02\x10\x00\x10\x01*\nCreate Run\x12\x9c\x01\n\tupdateRun\x12\x11.mlflow.UpdateRun\x1a\x1a.mlflow.UpdateRun.Response\"`\xf2\x86\x19\\\n!\n\x04POST\x12\x13/mlflow/runs/update\x1a\x04\x08\x02\x10\x00\n)\n\x04POST\x12\x1b/preview/mlflow/runs/update\x1a\x04\x08\x02\x10\x00\x10\x01*\nUpdate Run\x12\x9c\x01\n\tdeleteRun\x12\x11.mlflow.DeleteRun\x1a\x1a.mlflow.DeleteRun.Response\"`\xf2\x86\x19\\\n!\n\x04POST\x12\x13/mlflow/runs/delete\x1a\x04\x08\x02\x10\x00\n)\n\x04POST\x12\x1b/preview/mlflow/runs/delete\x1a\x04\x08\x02\x10\x00\x10\x01*\nDelete Run\x12\xa2\x01\n\nrestoreRun\x12\x12.mlflow.RestoreRun\x1a\x1b.mlflow.RestoreRun.Response\"c\xf2\x86\x19_\n\"\n\x04POST\x12\x14/mlflow/runs/restore\x1a\x04\x08\x02\x10\x00\n*\n\x04POST\x12\x1c/preview/mlflow/runs/restore\x1a\x04\x08\x02\x10\x00\x10\x01*\x0bRestore Run\x12\xa4\x01\n\tlogMetric\x12\x11.mlflow.LogMetric\x1a\x1a.mlflow.LogMetric.Response\"h\xf2\x86\x19\x64\n%\n\x04POST\x12\x17/mlflow/runs/log-metric\x1a\x04\x08\x02\x10\x00\n-\n\x04POST\x12\x1f/preview/mlflow/runs/log-metric\x1a\x04\x08\x02\x10\x00\x10\x01*\nLog Metric\x12\xa6\x01\n\x08logParam\x12\x10.mlflow.LogParam\x1a\x19.mlflow.LogParam.Response\"m\xf2\x86\x19i\n(\n\x04POST\x12\x1a/mlflow/runs/log-parameter\x1a\x04\x08\x02\x10\x00\n0\n\x04POST\x12\"/preview/mlflow/runs/log-parameter\x1a\x04\x08\x02\x10\x00\x10\x01*\tLog Param\x12\xe1\x01\n\x10setExperimentTag\x12\x18.mlflow.SetExperimentTag\x1a!.mlflow.SetExperimentTag.Response\"\x8f\x01\xf2\x86\x19\x8a\x01\n4\n\x04POST\x12&/mlflow/experiments/set-experiment-tag\x1a\x04\x08\x02\x10\x00\n<\n\x04POST\x12./preview/mlflow/experiments/set-experiment-tag\x1a\x04\x08\x02\x10\x00\x10\x01*\x12Set Experiment Tag\x12\x92\x01\n\x06setTag\x12\x0e.mlflow.SetTag\x1a\x17.mlflow.SetTag.Response\"_\xf2\x86\x19[\n\"\n\x04POST\x12\x14/mlflow/runs/set-tag\x1a\x04\x08\x02\x10\x00\n*\n\x04POST\x12\x1c/preview/mlflow/runs/set-tag\x1a\x04\x08\x02\x10\x00\x10\x01*\x07Set Tag\x12\xa4\x01\n\tdeleteTag\x12\x11.mlflow.DeleteTag\x1a\x1a.mlflow.DeleteTag.Response\"h\xf2\x86\x19\x64\n%\n\x04POST\x12\x17/mlflow/runs/delete-tag\x1a\x04\x08\x02\x10\x00\n-\n\x04POST\x12\x1f/preview/mlflow/runs/delete-tag\x1a\x04\x08\x02\x10\x00\x10\x01*\nDelete Tag\x12\x88\x01\n\x06getRun\x12\x0e.mlflow.GetRun\x1a\x17.mlflow.GetRun.Response\"U\xf2\x86\x19Q\n\x1d\n\x03GET\x12\x10/mlflow/runs/get\x1a\x04\x08\x02\x10\x00\n%\n\x03GET\x12\x18/preview/mlflow/runs/get\x1a\x04\x08\x02\x10\x00\x10\x01*\x07Get Run\x12\xcc\x01\n\nsearchRuns\x12\x12.mlflow.SearchRuns\x1a\x1b.mlflow.SearchRuns.Response\"\x8c\x01\xf2\x86\x19\x87\x01\n!\n\x04POST\x12\x13/mlflow/runs/search\x1a\x04\x08\x02\x10\x00\n)\n\x04POST\x12\x1b/preview/mlflow/runs/search\x1a\x04\x08\x02\x10\x00\n(\n\x03GET\x12\x1b/preview/mlflow/runs/search\x1a\x04\x08\x02\x10\x00\x10\x01*\x0bSearch Runs\x12\xb0\x01\n\rlistArtifacts\x12\x15.mlflow.ListArtifacts\x1a\x1e.mlflow.ListArtifacts.Response\"h\xf2\x86\x19\x64\n#\n\x03GET\x12\x16/mlflow/artifacts/list\x1a\x04\x08\x02\x10\x00\n+\n\x03GET\x12\x1e/preview/mlflow/artifacts/list\x1a\x04\x08\x02\x10\x00\x10\x01*\x0eList Artifacts\x12\xc7\x01\n\x10getMetricHistory\x12\x18.mlflow.GetMetricHistory\x1a!.mlflow.GetMetricHistory.Response\"v\xf2\x86\x19r\n(\n\x03GET\x12\x1b/mlflow/metrics/get-history\x1a\x04\x08\x02\x10\x00\n0\n\x03GET\x12#/preview/mlflow/metrics/get-history\x1a\x04\x08\x02\x10\x00\x10\x01*\x12Get Metric History\x12\x9e\x01\n\x08logBatch\x12\x10.mlflow.LogBatch\x1a\x19.mlflow.LogBatch.Response\"e\xf2\x86\x19\x61\n$\n\x04POST\x12\x16/mlflow/runs/log-batch\x1a\x04\x08\x02\x10\x00\n,\n\x04POST\x12\x1e/preview/mlflow/runs/log-batch\x1a\x04\x08\x02\x10\x00\x10\x01*\tLog Batch\x12\x9e\x01\n\x08logModel\x12\x10.mlflow.LogModel\x1a\x19.mlflow.LogModel.Response\"e\xf2\x86\x19\x61\n$\n\x04POST\x12\x16/mlflow/runs/log-model\x1a\x04\x08\x02\x10\x00\n,\n\x04POST\x12\x1e/preview/mlflow/runs/log-model\x1a\x04\x08\x02\x10\x00\x10\x01*\tLog ModelB\x1e\n\x14org.mlflow.api.proto\x90\x01\x01\xe2?\x02\x10\x01')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\rservice.proto\x12\x06mlflow\x1a\x15scalapb/scalapb.proto\x1a\x10\x64\x61tabricks.proto\"H\n\x06Metric\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x01\x12\x11\n\ttimestamp\x18\x03 \x01(\x03\x12\x0f\n\x04step\x18\x04 \x01(\x03:\x01\x30\"#\n\x05Param\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"C\n\x03Run\x12\x1d\n\x04info\x18\x01 \x01(\x0b\x32\x0f.mlflow.RunInfo\x12\x1d\n\x04\x64\x61ta\x18\x02 \x01(\x0b\x32\x0f.mlflow.RunData\"g\n\x07RunData\x12\x1f\n\x07metrics\x18\x01 \x03(\x0b\x32\x0e.mlflow.Metric\x12\x1d\n\x06params\x18\x02 \x03(\x0b\x32\r.mlflow.Param\x12\x1c\n\x04tags\x18\x03 \x03(\x0b\x32\x0e.mlflow.RunTag\"$\n\x06RunTag\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"+\n\rExperimentTag\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t\"\xe0\x01\n\x07RunInfo\x12\x0e\n\x06run_id\x18\x0f \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x15\n\rexperiment_id\x18\x02 \x01(\t\x12\x0f\n\x07user_id\x18\x06 \x01(\t\x12!\n\x06status\x18\x07 \x01(\x0e\x32\x11.mlflow.RunStatus\x12\x12\n\nstart_time\x18\x08 \x01(\x03\x12\x10\n\x08\x65nd_time\x18\t \x01(\x03\x12\x13\n\x0b\x64\x65lete_time\x18\n \x01(\x03\x12\x14\n\x0c\x61rtifact_uri\x18\r \x01(\t\x12\x17\n\x0flifecycle_stage\x18\x0e \x01(\t\"\xbb\x01\n\nExperiment\x12\x15\n\rexperiment_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x19\n\x11\x61rtifact_location\x18\x03 \x01(\t\x12\x17\n\x0flifecycle_stage\x18\x04 \x01(\t\x12\x18\n\x10last_update_time\x18\x05 \x01(\x03\x12\x15\n\rcreation_time\x18\x06 \x01(\x03\x12#\n\x04tags\x18\x07 \x03(\x0b\x32\x15.mlflow.ExperimentTag\"\xb6\x01\n\x10\x43reateExperiment\x12\x12\n\x04name\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x12\x19\n\x11\x61rtifact_location\x18\x02 \x01(\t\x12#\n\x04tags\x18\x03 \x03(\x0b\x32\x15.mlflow.ExperimentTag\x1a!\n\x08Response\x12\x15\n\rexperiment_id\x18\x01 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xda\x01\n\x0fListExperiments\x12#\n\tview_type\x18\x01 \x01(\x0e\x32\x10.mlflow.ViewType\x12\x13\n\x0bmax_results\x18\x02 \x01(\x03\x12\x12\n\npage_token\x18\x03 \x01(\t\x1aL\n\x08Response\x12\'\n\x0b\x65xperiments\x18\x01 \x03(\x0b\x32\x12.mlflow.Experiment\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xfe\x01\n\x11SearchExperiments\x12\x13\n\x0bmax_results\x18\x01 \x01(\x03\x12\x12\n\npage_token\x18\x02 \x01(\t\x12\x0e\n\x06\x66ilter\x18\x03 \x01(\t\x12\x10\n\x08order_by\x18\x04 \x03(\t\x12#\n\tview_type\x18\x05 \x01(\x0e\x32\x10.mlflow.ViewType\x1aL\n\x08Response\x12\'\n\x0b\x65xperiments\x18\x01 \x03(\x0b\x32\x12.mlflow.Experiment\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xb0\x01\n\rGetExperiment\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1aU\n\x08Response\x12&\n\nexperiment\x18\x01 \x01(\x0b\x32\x12.mlflow.Experiment\x12!\n\x04runs\x18\x02 \x03(\x0b\x32\x0f.mlflow.RunInfoB\x02\x18\x01:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"h\n\x10\x44\x65leteExperiment\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"i\n\x11RestoreExperiment\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"z\n\x10UpdateExperiment\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x12\x10\n\x08new_name\x18\x02 \x01(\t\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xb8\x01\n\tCreateRun\x12\x15\n\rexperiment_id\x18\x01 \x01(\t\x12\x0f\n\x07user_id\x18\x02 \x01(\t\x12\x12\n\nstart_time\x18\x07 \x01(\x03\x12\x1c\n\x04tags\x18\t \x03(\x0b\x32\x0e.mlflow.RunTag\x1a$\n\x08Response\x12\x18\n\x03run\x18\x01 \x01(\x0b\x32\x0b.mlflow.Run:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xbe\x01\n\tUpdateRun\x12\x0e\n\x06run_id\x18\x04 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12!\n\x06status\x18\x02 \x01(\x0e\x32\x11.mlflow.RunStatus\x12\x10\n\x08\x65nd_time\x18\x03 \x01(\x03\x1a-\n\x08Response\x12!\n\x08run_info\x18\x01 \x01(\x0b\x32\x0f.mlflow.RunInfo:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"Z\n\tDeleteRun\x12\x14\n\x06run_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"[\n\nRestoreRun\x12\x14\n\x06run_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xb8\x01\n\tLogMetric\x12\x0e\n\x06run_id\x18\x06 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x12\x13\n\x05value\x18\x03 \x01(\x01\x42\x04\xf8\x86\x19\x01\x12\x17\n\ttimestamp\x18\x04 \x01(\x03\x42\x04\xf8\x86\x19\x01\x12\x0f\n\x04step\x18\x05 \x01(\x03:\x01\x30\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x8d\x01\n\x08LogParam\x12\x0e\n\x06run_id\x18\x04 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x12\x13\n\x05value\x18\x03 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x90\x01\n\x10SetExperimentTag\x12\x1b\n\rexperiment_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x12\x13\n\x05value\x18\x03 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x8b\x01\n\x06SetTag\x12\x0e\n\x06run_id\x18\x04 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x12\x13\n\x05value\x18\x03 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"m\n\tDeleteTag\x12\x14\n\x06run_id\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x12\x11\n\x03key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"}\n\x06GetRun\x12\x0e\n\x06run_id\x18\x02 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x1a$\n\x08Response\x12\x18\n\x03run\x18\x01 \x01(\x0b\x32\x0b.mlflow.Run:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x98\x02\n\nSearchRuns\x12\x16\n\x0e\x65xperiment_ids\x18\x01 \x03(\t\x12\x0e\n\x06\x66ilter\x18\x04 \x01(\t\x12\x34\n\rrun_view_type\x18\x03 \x01(\x0e\x32\x10.mlflow.ViewType:\x0b\x41\x43TIVE_ONLY\x12\x19\n\x0bmax_results\x18\x05 \x01(\x05:\x04\x31\x30\x30\x30\x12\x10\n\x08order_by\x18\x06 \x03(\t\x12\x12\n\npage_token\x18\x07 \x01(\t\x1a>\n\x08Response\x12\x19\n\x04runs\x18\x01 \x03(\x0b\x32\x0b.mlflow.Run\x12\x17\n\x0fnext_page_token\x18\x02 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xd8\x01\n\rListArtifacts\x12\x0e\n\x06run_id\x18\x03 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x0c\n\x04path\x18\x02 \x01(\t\x12\x12\n\npage_token\x18\x04 \x01(\t\x1aV\n\x08Response\x12\x10\n\x08root_uri\x18\x01 \x01(\t\x12\x1f\n\x05\x66iles\x18\x02 \x03(\x0b\x32\x10.mlflow.FileInfo\x12\x17\n\x0fnext_page_token\x18\x03 \x01(\t:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\";\n\x08\x46ileInfo\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0e\n\x06is_dir\x18\x02 \x01(\x08\x12\x11\n\tfile_size\x18\x03 \x01(\x03\"\xa8\x01\n\x10GetMetricHistory\x12\x0e\n\x06run_id\x18\x03 \x01(\t\x12\x10\n\x08run_uuid\x18\x01 \x01(\t\x12\x18\n\nmetric_key\x18\x02 \x01(\tB\x04\xf8\x86\x19\x01\x1a+\n\x08Response\x12\x1f\n\x07metrics\x18\x01 \x03(\x0b\x32\x0e.mlflow.Metric:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\xb1\x01\n\x08LogBatch\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x1f\n\x07metrics\x18\x02 \x03(\x0b\x32\x0e.mlflow.Metric\x12\x1d\n\x06params\x18\x03 \x03(\x0b\x32\r.mlflow.Param\x12\x1c\n\x04tags\x18\x04 \x03(\x0b\x32\x0e.mlflow.RunTag\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"g\n\x08LogModel\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x12\n\nmodel_json\x18\x02 \x01(\t\x1a\n\n\x08Response:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]\"\x95\x01\n\x13GetExperimentByName\x12\x1d\n\x0f\x65xperiment_name\x18\x01 \x01(\tB\x04\xf8\x86\x19\x01\x1a\x32\n\x08Response\x12&\n\nexperiment\x18\x01 \x01(\x0b\x32\x12.mlflow.Experiment:+\xe2?(\n&com.databricks.rpc.RPC[$this.Response]*6\n\x08ViewType\x12\x0f\n\x0b\x41\x43TIVE_ONLY\x10\x01\x12\x10\n\x0c\x44\x45LETED_ONLY\x10\x02\x12\x07\n\x03\x41LL\x10\x03*I\n\nSourceType\x12\x0c\n\x08NOTEBOOK\x10\x01\x12\x07\n\x03JOB\x10\x02\x12\x0b\n\x07PROJECT\x10\x03\x12\t\n\x05LOCAL\x10\x04\x12\x0c\n\x07UNKNOWN\x10\xe8\x07*M\n\tRunStatus\x12\x0b\n\x07RUNNING\x10\x01\x12\r\n\tSCHEDULED\x10\x02\x12\x0c\n\x08\x46INISHED\x10\x03\x12\n\n\x06\x46\x41ILED\x10\x04\x12\n\n\x06KILLED\x10\x05\x32\xfb\x1f\n\rMlflowService\x12\xa6\x01\n\x13getExperimentByName\x12\x1b.mlflow.GetExperimentByName\x1a$.mlflow.GetExperimentByName.Response\"L\xf2\x86\x19H\n,\n\x03GET\x12\x1f/mlflow/experiments/get-by-name\x1a\x04\x08\x02\x10\x00\x10\x01*\x16Get Experiment By Name\x12\xc6\x01\n\x10\x63reateExperiment\x12\x18.mlflow.CreateExperiment\x1a!.mlflow.CreateExperiment.Response\"u\xf2\x86\x19q\n(\n\x04POST\x12\x1a/mlflow/experiments/create\x1a\x04\x08\x02\x10\x00\n0\n\x04POST\x12\"/preview/mlflow/experiments/create\x1a\x04\x08\x02\x10\x00\x10\x01*\x11\x43reate Experiment\x12\xbc\x01\n\x0flistExperiments\x12\x17.mlflow.ListExperiments\x1a .mlflow.ListExperiments.Response\"n\xf2\x86\x19j\n%\n\x03GET\x12\x18/mlflow/experiments/list\x1a\x04\x08\x02\x10\x00\n-\n\x03GET\x12 /preview/mlflow/experiments/list\x1a\x04\x08\x02\x10\x00\x10\x01*\x10List Experiments\x12\x97\x01\n\x11searchExperiments\x12\x19.mlflow.SearchExperiments\x1a\".mlflow.SearchExperiments.Response\"C\xf2\x86\x19?\n\'\n\x03GET\x12\x1a/mlflow/experiments/search\x1a\x04\x08\x02\x10\x00\x10\x01*\x12Search Experiments\x12\xb2\x01\n\rgetExperiment\x12\x15.mlflow.GetExperiment\x1a\x1e.mlflow.GetExperiment.Response\"j\xf2\x86\x19\x66\n$\n\x03GET\x12\x17/mlflow/experiments/get\x1a\x04\x08\x02\x10\x00\n,\n\x03GET\x12\x1f/preview/mlflow/experiments/get\x1a\x04\x08\x02\x10\x00\x10\x01*\x0eGet Experiment\x12\xc6\x01\n\x10\x64\x65leteExperiment\x12\x18.mlflow.DeleteExperiment\x1a!.mlflow.DeleteExperiment.Response\"u\xf2\x86\x19q\n(\n\x04POST\x12\x1a/mlflow/experiments/delete\x1a\x04\x08\x02\x10\x00\n0\n\x04POST\x12\"/preview/mlflow/experiments/delete\x1a\x04\x08\x02\x10\x00\x10\x01*\x11\x44\x65lete Experiment\x12\xcc\x01\n\x11restoreExperiment\x12\x19.mlflow.RestoreExperiment\x1a\".mlflow.RestoreExperiment.Response\"x\xf2\x86\x19t\n)\n\x04POST\x12\x1b/mlflow/experiments/restore\x1a\x04\x08\x02\x10\x00\n1\n\x04POST\x12#/preview/mlflow/experiments/restore\x1a\x04\x08\x02\x10\x00\x10\x01*\x12Restore Experiment\x12\xc6\x01\n\x10updateExperiment\x12\x18.mlflow.UpdateExperiment\x1a!.mlflow.UpdateExperiment.Response\"u\xf2\x86\x19q\n(\n\x04POST\x12\x1a/mlflow/experiments/update\x1a\x04\x08\x02\x10\x00\n0\n\x04POST\x12\"/preview/mlflow/experiments/update\x1a\x04\x08\x02\x10\x00\x10\x01*\x11Update Experiment\x12\x9c\x01\n\tcreateRun\x12\x11.mlflow.CreateRun\x1a\x1a.mlflow.CreateRun.Response\"`\xf2\x86\x19\\\n!\n\x04POST\x12\x13/mlflow/runs/create\x1a\x04\x08\x02\x10\x00\n)\n\x04POST\x12\x1b/preview/mlflow/runs/create\x1a\x04\x08\x02\x10\x00\x10\x01*\nCreate Run\x12\x9c\x01\n\tupdateRun\x12\x11.mlflow.UpdateRun\x1a\x1a.mlflow.UpdateRun.Response\"`\xf2\x86\x19\\\n!\n\x04POST\x12\x13/mlflow/runs/update\x1a\x04\x08\x02\x10\x00\n)\n\x04POST\x12\x1b/preview/mlflow/runs/update\x1a\x04\x08\x02\x10\x00\x10\x01*\nUpdate Run\x12\x9c\x01\n\tdeleteRun\x12\x11.mlflow.DeleteRun\x1a\x1a.mlflow.DeleteRun.Response\"`\xf2\x86\x19\\\n!\n\x04POST\x12\x13/mlflow/runs/delete\x1a\x04\x08\x02\x10\x00\n)\n\x04POST\x12\x1b/preview/mlflow/runs/delete\x1a\x04\x08\x02\x10\x00\x10\x01*\nDelete Run\x12\xa2\x01\n\nrestoreRun\x12\x12.mlflow.RestoreRun\x1a\x1b.mlflow.RestoreRun.Response\"c\xf2\x86\x19_\n\"\n\x04POST\x12\x14/mlflow/runs/restore\x1a\x04\x08\x02\x10\x00\n*\n\x04POST\x12\x1c/preview/mlflow/runs/restore\x1a\x04\x08\x02\x10\x00\x10\x01*\x0bRestore Run\x12\xa4\x01\n\tlogMetric\x12\x11.mlflow.LogMetric\x1a\x1a.mlflow.LogMetric.Response\"h\xf2\x86\x19\x64\n%\n\x04POST\x12\x17/mlflow/runs/log-metric\x1a\x04\x08\x02\x10\x00\n-\n\x04POST\x12\x1f/preview/mlflow/runs/log-metric\x1a\x04\x08\x02\x10\x00\x10\x01*\nLog Metric\x12\xa6\x01\n\x08logParam\x12\x10.mlflow.LogParam\x1a\x19.mlflow.LogParam.Response\"m\xf2\x86\x19i\n(\n\x04POST\x12\x1a/mlflow/runs/log-parameter\x1a\x04\x08\x02\x10\x00\n0\n\x04POST\x12\"/preview/mlflow/runs/log-parameter\x1a\x04\x08\x02\x10\x00\x10\x01*\tLog Param\x12\xe1\x01\n\x10setExperimentTag\x12\x18.mlflow.SetExperimentTag\x1a!.mlflow.SetExperimentTag.Response\"\x8f\x01\xf2\x86\x19\x8a\x01\n4\n\x04POST\x12&/mlflow/experiments/set-experiment-tag\x1a\x04\x08\x02\x10\x00\n<\n\x04POST\x12./preview/mlflow/experiments/set-experiment-tag\x1a\x04\x08\x02\x10\x00\x10\x01*\x12Set Experiment Tag\x12\x92\x01\n\x06setTag\x12\x0e.mlflow.SetTag\x1a\x17.mlflow.SetTag.Response\"_\xf2\x86\x19[\n\"\n\x04POST\x12\x14/mlflow/runs/set-tag\x1a\x04\x08\x02\x10\x00\n*\n\x04POST\x12\x1c/preview/mlflow/runs/set-tag\x1a\x04\x08\x02\x10\x00\x10\x01*\x07Set Tag\x12\xa4\x01\n\tdeleteTag\x12\x11.mlflow.DeleteTag\x1a\x1a.mlflow.DeleteTag.Response\"h\xf2\x86\x19\x64\n%\n\x04POST\x12\x17/mlflow/runs/delete-tag\x1a\x04\x08\x02\x10\x00\n-\n\x04POST\x12\x1f/preview/mlflow/runs/delete-tag\x1a\x04\x08\x02\x10\x00\x10\x01*\nDelete Tag\x12\x88\x01\n\x06getRun\x12\x0e.mlflow.GetRun\x1a\x17.mlflow.GetRun.Response\"U\xf2\x86\x19Q\n\x1d\n\x03GET\x12\x10/mlflow/runs/get\x1a\x04\x08\x02\x10\x00\n%\n\x03GET\x12\x18/preview/mlflow/runs/get\x1a\x04\x08\x02\x10\x00\x10\x01*\x07Get Run\x12\xcc\x01\n\nsearchRuns\x12\x12.mlflow.SearchRuns\x1a\x1b.mlflow.SearchRuns.Response\"\x8c\x01\xf2\x86\x19\x87\x01\n!\n\x04POST\x12\x13/mlflow/runs/search\x1a\x04\x08\x02\x10\x00\n)\n\x04POST\x12\x1b/preview/mlflow/runs/search\x1a\x04\x08\x02\x10\x00\n(\n\x03GET\x12\x1b/preview/mlflow/runs/search\x1a\x04\x08\x02\x10\x00\x10\x01*\x0bSearch Runs\x12\xb0\x01\n\rlistArtifacts\x12\x15.mlflow.ListArtifacts\x1a\x1e.mlflow.ListArtifacts.Response\"h\xf2\x86\x19\x64\n#\n\x03GET\x12\x16/mlflow/artifacts/list\x1a\x04\x08\x02\x10\x00\n+\n\x03GET\x12\x1e/preview/mlflow/artifacts/list\x1a\x04\x08\x02\x10\x00\x10\x01*\x0eList Artifacts\x12\xc7\x01\n\x10getMetricHistory\x12\x18.mlflow.GetMetricHistory\x1a!.mlflow.GetMetricHistory.Response\"v\xf2\x86\x19r\n(\n\x03GET\x12\x1b/mlflow/metrics/get-history\x1a\x04\x08\x02\x10\x00\n0\n\x03GET\x12#/preview/mlflow/metrics/get-history\x1a\x04\x08\x02\x10\x00\x10\x01*\x12Get Metric History\x12\x9e\x01\n\x08logBatch\x12\x10.mlflow.LogBatch\x1a\x19.mlflow.LogBatch.Response\"e\xf2\x86\x19\x61\n$\n\x04POST\x12\x16/mlflow/runs/log-batch\x1a\x04\x08\x02\x10\x00\n,\n\x04POST\x12\x1e/preview/mlflow/runs/log-batch\x1a\x04\x08\x02\x10\x00\x10\x01*\tLog Batch\x12\x9e\x01\n\x08logModel\x12\x10.mlflow.LogModel\x1a\x19.mlflow.LogModel.Response\"e\xf2\x86\x19\x61\n$\n\x04POST\x12\x16/mlflow/runs/log-model\x1a\x04\x08\x02\x10\x00\n,\n\x04POST\x12\x1e/preview/mlflow/runs/log-model\x1a\x04\x08\x02\x10\x00\x10\x01*\tLog ModelB\x1e\n\x14org.mlflow.api.proto\x90\x01\x01\xe2?\x02\x10\x01')
 
 _VIEWTYPE = DESCRIPTOR.enum_types_by_name['ViewType']
 ViewType = enum_type_wrapper.EnumTypeWrapper(_VIEWTYPE)
@@ -646,12 +646,12 @@
   _MLFLOWSERVICE.methods_by_name['logBatch']._serialized_options = b'\362\206\031a\n$\n\004POST\022\026/mlflow/runs/log-batch\032\004\010\002\020\000\n,\n\004POST\022\036/preview/mlflow/runs/log-batch\032\004\010\002\020\000\020\001*\tLog Batch'
   _MLFLOWSERVICE.methods_by_name['logModel']._options = None
   _MLFLOWSERVICE.methods_by_name['logModel']._serialized_options = b'\362\206\031a\n$\n\004POST\022\026/mlflow/runs/log-model\032\004\010\002\020\000\n,\n\004POST\022\036/preview/mlflow/runs/log-model\032\004\010\002\020\000\020\001*\tLog Model'
-  _VIEWTYPE._serialized_start=4603
-  _VIEWTYPE._serialized_end=4657
-  _SOURCETYPE._serialized_start=4659
-  _SOURCETYPE._serialized_end=4732
-  _RUNSTATUS._serialized_start=4734
-  _RUNSTATUS._serialized_end=4811
+  _VIEWTYPE._serialized_start=4624
+  _VIEWTYPE._serialized_end=4678
+  _SOURCETYPE._serialized_start=4680
+  _SOURCETYPE._serialized_end=4753
+  _RUNSTATUS._serialized_start=4755
+  _RUNSTATUS._serialized_end=4832
   _METRIC._serialized_start=66
   _METRIC._serialized_end=138
   _PARAM._serialized_start=140
@@ -665,105 +665,105 @@
   _EXPERIMENTTAG._serialized_start=389
   _EXPERIMENTTAG._serialized_end=432
   _RUNINFO._serialized_start=435
-  _RUNINFO._serialized_end=638
-  _EXPERIMENT._serialized_start=641
-  _EXPERIMENT._serialized_end=828
-  _CREATEEXPERIMENT._serialized_start=831
-  _CREATEEXPERIMENT._serialized_end=1013
-  _CREATEEXPERIMENT_RESPONSE._serialized_start=935
-  _CREATEEXPERIMENT_RESPONSE._serialized_end=968
-  _LISTEXPERIMENTS._serialized_start=1016
-  _LISTEXPERIMENTS._serialized_end=1234
-  _LISTEXPERIMENTS_RESPONSE._serialized_start=1113
-  _LISTEXPERIMENTS_RESPONSE._serialized_end=1189
-  _SEARCHEXPERIMENTS._serialized_start=1237
-  _SEARCHEXPERIMENTS._serialized_end=1491
-  _SEARCHEXPERIMENTS_RESPONSE._serialized_start=1113
-  _SEARCHEXPERIMENTS_RESPONSE._serialized_end=1189
-  _GETEXPERIMENT._serialized_start=1494
-  _GETEXPERIMENT._serialized_end=1670
-  _GETEXPERIMENT_RESPONSE._serialized_start=1540
-  _GETEXPERIMENT_RESPONSE._serialized_end=1625
-  _DELETEEXPERIMENT._serialized_start=1672
-  _DELETEEXPERIMENT._serialized_end=1776
-  _DELETEEXPERIMENT_RESPONSE._serialized_start=935
-  _DELETEEXPERIMENT_RESPONSE._serialized_end=945
-  _RESTOREEXPERIMENT._serialized_start=1778
-  _RESTOREEXPERIMENT._serialized_end=1883
-  _RESTOREEXPERIMENT_RESPONSE._serialized_start=935
-  _RESTOREEXPERIMENT_RESPONSE._serialized_end=945
-  _UPDATEEXPERIMENT._serialized_start=1885
-  _UPDATEEXPERIMENT._serialized_end=2007
-  _UPDATEEXPERIMENT_RESPONSE._serialized_start=935
-  _UPDATEEXPERIMENT_RESPONSE._serialized_end=945
-  _CREATERUN._serialized_start=2010
-  _CREATERUN._serialized_end=2194
-  _CREATERUN_RESPONSE._serialized_start=2113
-  _CREATERUN_RESPONSE._serialized_end=2149
-  _UPDATERUN._serialized_start=2197
-  _UPDATERUN._serialized_end=2387
-  _UPDATERUN_RESPONSE._serialized_start=2297
-  _UPDATERUN_RESPONSE._serialized_end=2342
-  _DELETERUN._serialized_start=2389
-  _DELETERUN._serialized_end=2479
-  _DELETERUN_RESPONSE._serialized_start=935
-  _DELETERUN_RESPONSE._serialized_end=945
-  _RESTORERUN._serialized_start=2481
-  _RESTORERUN._serialized_end=2572
-  _RESTORERUN_RESPONSE._serialized_start=935
-  _RESTORERUN_RESPONSE._serialized_end=945
-  _LOGMETRIC._serialized_start=2575
-  _LOGMETRIC._serialized_end=2759
-  _LOGMETRIC_RESPONSE._serialized_start=935
-  _LOGMETRIC_RESPONSE._serialized_end=945
-  _LOGPARAM._serialized_start=2762
-  _LOGPARAM._serialized_end=2903
-  _LOGPARAM_RESPONSE._serialized_start=935
-  _LOGPARAM_RESPONSE._serialized_end=945
-  _SETEXPERIMENTTAG._serialized_start=2906
-  _SETEXPERIMENTTAG._serialized_end=3050
-  _SETEXPERIMENTTAG_RESPONSE._serialized_start=935
-  _SETEXPERIMENTTAG_RESPONSE._serialized_end=945
-  _SETTAG._serialized_start=3053
-  _SETTAG._serialized_end=3192
-  _SETTAG_RESPONSE._serialized_start=935
-  _SETTAG_RESPONSE._serialized_end=945
-  _DELETETAG._serialized_start=3194
-  _DELETETAG._serialized_end=3303
-  _DELETETAG_RESPONSE._serialized_start=935
-  _DELETETAG_RESPONSE._serialized_end=945
-  _GETRUN._serialized_start=3305
-  _GETRUN._serialized_end=3430
-  _GETRUN_RESPONSE._serialized_start=2113
-  _GETRUN_RESPONSE._serialized_end=2149
-  _SEARCHRUNS._serialized_start=3433
-  _SEARCHRUNS._serialized_end=3713
-  _SEARCHRUNS_RESPONSE._serialized_start=3606
-  _SEARCHRUNS_RESPONSE._serialized_end=3668
-  _LISTARTIFACTS._serialized_start=3716
-  _LISTARTIFACTS._serialized_end=3932
-  _LISTARTIFACTS_RESPONSE._serialized_start=3801
-  _LISTARTIFACTS_RESPONSE._serialized_end=3887
-  _FILEINFO._serialized_start=3934
-  _FILEINFO._serialized_end=3993
-  _GETMETRICHISTORY._serialized_start=3996
-  _GETMETRICHISTORY._serialized_end=4164
-  _GETMETRICHISTORY_RESPONSE._serialized_start=4076
-  _GETMETRICHISTORY_RESPONSE._serialized_end=4119
-  _LOGBATCH._serialized_start=4167
-  _LOGBATCH._serialized_end=4344
-  _LOGBATCH_RESPONSE._serialized_start=935
-  _LOGBATCH_RESPONSE._serialized_end=945
-  _LOGMODEL._serialized_start=4346
-  _LOGMODEL._serialized_end=4449
-  _LOGMODEL_RESPONSE._serialized_start=935
-  _LOGMODEL_RESPONSE._serialized_end=945
-  _GETEXPERIMENTBYNAME._serialized_start=4452
-  _GETEXPERIMENTBYNAME._serialized_end=4601
-  _GETEXPERIMENTBYNAME_RESPONSE._serialized_start=1540
-  _GETEXPERIMENTBYNAME_RESPONSE._serialized_end=1590
-  _MLFLOWSERVICE._serialized_start=4814
-  _MLFLOWSERVICE._serialized_end=8905
+  _RUNINFO._serialized_end=659
+  _EXPERIMENT._serialized_start=662
+  _EXPERIMENT._serialized_end=849
+  _CREATEEXPERIMENT._serialized_start=852
+  _CREATEEXPERIMENT._serialized_end=1034
+  _CREATEEXPERIMENT_RESPONSE._serialized_start=956
+  _CREATEEXPERIMENT_RESPONSE._serialized_end=989
+  _LISTEXPERIMENTS._serialized_start=1037
+  _LISTEXPERIMENTS._serialized_end=1255
+  _LISTEXPERIMENTS_RESPONSE._serialized_start=1134
+  _LISTEXPERIMENTS_RESPONSE._serialized_end=1210
+  _SEARCHEXPERIMENTS._serialized_start=1258
+  _SEARCHEXPERIMENTS._serialized_end=1512
+  _SEARCHEXPERIMENTS_RESPONSE._serialized_start=1134
+  _SEARCHEXPERIMENTS_RESPONSE._serialized_end=1210
+  _GETEXPERIMENT._serialized_start=1515
+  _GETEXPERIMENT._serialized_end=1691
+  _GETEXPERIMENT_RESPONSE._serialized_start=1561
+  _GETEXPERIMENT_RESPONSE._serialized_end=1646
+  _DELETEEXPERIMENT._serialized_start=1693
+  _DELETEEXPERIMENT._serialized_end=1797
+  _DELETEEXPERIMENT_RESPONSE._serialized_start=956
+  _DELETEEXPERIMENT_RESPONSE._serialized_end=966
+  _RESTOREEXPERIMENT._serialized_start=1799
+  _RESTOREEXPERIMENT._serialized_end=1904
+  _RESTOREEXPERIMENT_RESPONSE._serialized_start=956
+  _RESTOREEXPERIMENT_RESPONSE._serialized_end=966
+  _UPDATEEXPERIMENT._serialized_start=1906
+  _UPDATEEXPERIMENT._serialized_end=2028
+  _UPDATEEXPERIMENT_RESPONSE._serialized_start=956
+  _UPDATEEXPERIMENT_RESPONSE._serialized_end=966
+  _CREATERUN._serialized_start=2031
+  _CREATERUN._serialized_end=2215
+  _CREATERUN_RESPONSE._serialized_start=2134
+  _CREATERUN_RESPONSE._serialized_end=2170
+  _UPDATERUN._serialized_start=2218
+  _UPDATERUN._serialized_end=2408
+  _UPDATERUN_RESPONSE._serialized_start=2318
+  _UPDATERUN_RESPONSE._serialized_end=2363
+  _DELETERUN._serialized_start=2410
+  _DELETERUN._serialized_end=2500
+  _DELETERUN_RESPONSE._serialized_start=956
+  _DELETERUN_RESPONSE._serialized_end=966
+  _RESTORERUN._serialized_start=2502
+  _RESTORERUN._serialized_end=2593
+  _RESTORERUN_RESPONSE._serialized_start=956
+  _RESTORERUN_RESPONSE._serialized_end=966
+  _LOGMETRIC._serialized_start=2596
+  _LOGMETRIC._serialized_end=2780
+  _LOGMETRIC_RESPONSE._serialized_start=956
+  _LOGMETRIC_RESPONSE._serialized_end=966
+  _LOGPARAM._serialized_start=2783
+  _LOGPARAM._serialized_end=2924
+  _LOGPARAM_RESPONSE._serialized_start=956
+  _LOGPARAM_RESPONSE._serialized_end=966
+  _SETEXPERIMENTTAG._serialized_start=2927
+  _SETEXPERIMENTTAG._serialized_end=3071
+  _SETEXPERIMENTTAG_RESPONSE._serialized_start=956
+  _SETEXPERIMENTTAG_RESPONSE._serialized_end=966
+  _SETTAG._serialized_start=3074
+  _SETTAG._serialized_end=3213
+  _SETTAG_RESPONSE._serialized_start=956
+  _SETTAG_RESPONSE._serialized_end=966
+  _DELETETAG._serialized_start=3215
+  _DELETETAG._serialized_end=3324
+  _DELETETAG_RESPONSE._serialized_start=956
+  _DELETETAG_RESPONSE._serialized_end=966
+  _GETRUN._serialized_start=3326
+  _GETRUN._serialized_end=3451
+  _GETRUN_RESPONSE._serialized_start=2134
+  _GETRUN_RESPONSE._serialized_end=2170
+  _SEARCHRUNS._serialized_start=3454
+  _SEARCHRUNS._serialized_end=3734
+  _SEARCHRUNS_RESPONSE._serialized_start=3627
+  _SEARCHRUNS_RESPONSE._serialized_end=3689
+  _LISTARTIFACTS._serialized_start=3737
+  _LISTARTIFACTS._serialized_end=3953
+  _LISTARTIFACTS_RESPONSE._serialized_start=3822
+  _LISTARTIFACTS_RESPONSE._serialized_end=3908
+  _FILEINFO._serialized_start=3955
+  _FILEINFO._serialized_end=4014
+  _GETMETRICHISTORY._serialized_start=4017
+  _GETMETRICHISTORY._serialized_end=4185
+  _GETMETRICHISTORY_RESPONSE._serialized_start=4097
+  _GETMETRICHISTORY_RESPONSE._serialized_end=4140
+  _LOGBATCH._serialized_start=4188
+  _LOGBATCH._serialized_end=4365
+  _LOGBATCH_RESPONSE._serialized_start=956
+  _LOGBATCH_RESPONSE._serialized_end=966
+  _LOGMODEL._serialized_start=4367
+  _LOGMODEL._serialized_end=4470
+  _LOGMODEL_RESPONSE._serialized_start=956
+  _LOGMODEL_RESPONSE._serialized_end=966
+  _GETEXPERIMENTBYNAME._serialized_start=4473
+  _GETEXPERIMENTBYNAME._serialized_end=4622
+  _GETEXPERIMENTBYNAME_RESPONSE._serialized_start=1561
+  _GETEXPERIMENTBYNAME_RESPONSE._serialized_end=1611
+  _MLFLOWSERVICE._serialized_start=4835
+  _MLFLOWSERVICE._serialized_end=8926
 MlflowService = service_reflection.GeneratedServiceType('MlflowService', (_service.Service,), dict(
   DESCRIPTOR = _MLFLOWSERVICE,
   __module__ = 'service_pb2'
diff --git a/mlflow/store/db_migrations/versions/0c779009ac13_add_delete_time_field_to_runs_table.py b/mlflow/store/db_migrations/versions/0c779009ac13_add_delete_time_field_to_runs_table.py
new file mode 100644
index 0000000000000..7722f52ec2521
--- /dev/null
+++ b/mlflow/store/db_migrations/versions/0c779009ac13_add_delete_time_field_to_runs_table.py
@@ -0,0 +1,24 @@
+"""add delete_time field to runs table
+
+Revision ID: 0c779009ac13
+Revises: bd07f7e963c5
+Create Date: 2022-07-27 14:13:36.162861
+
+"""
+from alembic import op
+import sqlalchemy as sa
+
+
+# revision identifiers, used by Alembic.
+revision = "0c779009ac13"
+down_revision = "bd07f7e963c5"
+branch_labels = None
+depends_on = None
+
+
+def upgrade():
+    op.add_column("runs", sa.Column("delete_time", sa.BigInteger, nullable=True, default=None))
+
+
+def downgrade():
+    pass
diff --git a/mlflow/store/tracking/dbmodels/models.py b/mlflow/store/tracking/dbmodels/models.py
index 20979681fd980..20e118d1d8bab 100644
--- a/mlflow/store/tracking/dbmodels/models.py
+++ b/mlflow/store/tracking/dbmodels/models.py
@@ -142,6 +142,10 @@ class SqlRun(Base):
     """
     Run end time: `BigInteger`.
     """
+    delete_time = Column(BigInteger, nullable=True, default=None)
+    """
+    Run delete time: `BigInteger`. Timestamp of when run is deleted, defaults to none.
+    """
     source_version = Column(String(50))
     """
     Source version: `String` (limit 50 characters).
@@ -198,6 +202,7 @@ def to_mlflow_entity(self):
             status=self.status,
             start_time=self.start_time,
             end_time=self.end_time,
+            delete_time=self.delete_time,
             lifecycle_stage=self.lifecycle_stage,
             artifact_uri=self.artifact_uri,
         )
diff --git a/mlflow/store/tracking/file_store.py b/mlflow/store/tracking/file_store.py
index 82e0b56bed7a2..61ff40d5aa3a3 100644
--- a/mlflow/store/tracking/file_store.py
+++ b/mlflow/store/tracking/file_store.py
@@ -1,5 +1,6 @@
 import json
 import logging
+import time
 import os
 import sys
 import shutil
@@ -473,7 +474,9 @@ def delete_run(self, run_id):
                 "Run '%s' metadata is in invalid state." % run_id, databricks_pb2.INVALID_STATE
             )
         check_run_is_active(run_info)
-        new_info = run_info._copy_with_overrides(lifecycle_stage=LifecycleStage.DELETED)
+        new_info = run_info._copy_with_overrides(
+            lifecycle_stage=LifecycleStage.DELETED, delete_time=int(time.time() * 1000)
+        )
         self._overwrite_run_info(new_info)
 
     def _hard_delete_run(self, run_id):
@@ -498,7 +501,9 @@ def restore_run(self, run_id):
                 "Run '%s' metadata is in invalid state." % run_id, databricks_pb2.INVALID_STATE
             )
         check_run_is_deleted(run_info)
-        new_info = run_info._copy_with_overrides(lifecycle_stage=LifecycleStage.ACTIVE)
+        new_info = run_info._copy_with_overrides(
+            lifecycle_stage=LifecycleStage.ACTIVE, delete_time=0
+        )
         self._overwrite_run_info(new_info)
 
     def _find_experiment_folder(self, run_path):
@@ -557,6 +562,7 @@ def create_run(self, experiment_id, user_id, start_time, tags):
             status=RunStatus.to_string(RunStatus.RUNNING),
             start_time=start_time,
             end_time=None,
+            delete_time=None,
             lifecycle_stage=LifecycleStage.ACTIVE,
         )
         # Persist run metadata and create directories for logging metrics, parameters, artifacts
diff --git a/mlflow/store/tracking/sqlalchemy_store.py b/mlflow/store/tracking/sqlalchemy_store.py
index 7d3303889ea75..55b25c928baf6 100644
--- a/mlflow/store/tracking/sqlalchemy_store.py
+++ b/mlflow/store/tracking/sqlalchemy_store.py
@@ -479,10 +479,12 @@ def delete_experiment(self, experiment_id):
     def _mark_run_deleted(self, session, run):
         self._check_run_is_active(run)
         run.lifecycle_stage = LifecycleStage.DELETED
+        run.delete_time = int(time.time() * 1000)
         self._save_to_db(objs=run, session=session)
 
     def _mark_run_active(self, session, run):
         run.lifecycle_stage = LifecycleStage.ACTIVE
+        run.delete_time = None
         self._save_to_db(objs=run, session=session)
 
     def _list_run_infos(self, session, experiment_id):
@@ -528,6 +530,7 @@ def create_run(self, experiment_id, user_id, start_time, tags):
                 status=RunStatus.to_string(RunStatus.RUNNING),
                 start_time=start_time,
                 end_time=None,
+                delete_time=None,
                 source_version="",
                 lifecycle_stage=LifecycleStage.ACTIVE,
             )
@@ -639,6 +642,7 @@ def restore_run(self, run_id):
             run = self._get_run(run_uuid=run_id, session=session)
             self._check_run_is_deleted(run)
             run.lifecycle_stage = LifecycleStage.ACTIVE
+            run.delete_time = None
             self._save_to_db(objs=run, session=session)
 
     def delete_run(self, run_id):
@@ -646,6 +650,7 @@ def delete_run(self, run_id):
             run = self._get_run(run_uuid=run_id, session=session)
             self._check_run_is_active(run)
             run.lifecycle_stage = LifecycleStage.DELETED
+            run.delete_time = int(time.time() * 1000)
             self._save_to_db(objs=run, session=session)
 
     def _hard_delete_run(self, run_id):
diff --git a/tests/db/schemas/mssql.sql b/tests/db/schemas/mssql.sql
index b7de513583bd9..a2c4a8c0f5e28 100644
--- a/tests/db/schemas/mssql.sql
+++ b/tests/db/schemas/mssql.sql
@@ -69,6 +69,7 @@ CREATE TABLE runs (
 	status VARCHAR(9) COLLATE "SQL_Latin1_General_CP1_CI_AS",
 	start_time BIGINT,
 	end_time BIGINT,
+	delete_time BIGINT,
 	source_version VARCHAR(50) COLLATE "SQL_Latin1_General_CP1_CI_AS",
 	lifecycle_stage VARCHAR(20) COLLATE "SQL_Latin1_General_CP1_CI_AS",
 	artifact_uri VARCHAR(200) COLLATE "SQL_Latin1_General_CP1_CI_AS",
diff --git a/tests/db/schemas/mysql.sql b/tests/db/schemas/mysql.sql
index 560dd0d7a747e..39a06574c6e31 100644
--- a/tests/db/schemas/mysql.sql
+++ b/tests/db/schemas/mysql.sql
@@ -70,6 +70,7 @@ CREATE TABLE runs (
 	status VARCHAR(9),
 	start_time BIGINT,
 	end_time BIGINT,
+	delete_time BIGINT,
 	source_version VARCHAR(50),
 	lifecycle_stage VARCHAR(20),
 	artifact_uri VARCHAR(200),
diff --git a/tests/db/schemas/postgresql.sql b/tests/db/schemas/postgresql.sql
index 44c328cfdab75..09370076fd7f7 100644
--- a/tests/db/schemas/postgresql.sql
+++ b/tests/db/schemas/postgresql.sql
@@ -71,6 +71,7 @@ CREATE TABLE runs (
 	status VARCHAR(9),
 	start_time BIGINT,
 	end_time BIGINT,
+	delete_time BIGINT,
 	source_version VARCHAR(50),
 	lifecycle_stage VARCHAR(20),
 	artifact_uri VARCHAR(200),
diff --git a/tests/db/schemas/sqlite.sql b/tests/db/schemas/sqlite.sql
index 23ae7efdda94a..d8e061f2d1b3a 100644
--- a/tests/db/schemas/sqlite.sql
+++ b/tests/db/schemas/sqlite.sql
@@ -72,6 +72,7 @@ CREATE TABLE runs (
 	status VARCHAR(9),
 	start_time BIGINT,
 	end_time BIGINT,
+	delete_time BIGINT,
 	source_version VARCHAR(50),
 	lifecycle_stage VARCHAR(20),
 	artifact_uri VARCHAR(200),
diff --git a/tests/resources/db/initial_models.py b/tests/resources/db/initial_models.py
index 3e7fb1a922535..8b89ce19378e2 100644
--- a/tests/resources/db/initial_models.py
+++ b/tests/resources/db/initial_models.py
@@ -118,6 +118,10 @@ class SqlRun(Base):
     """
     Run end time: `BigInteger`.
     """
+    delete_time = Column(BigInteger, nullable=True, default=None)
+    """
+    Run delete time: `BigInteger`. Timestamp of when run is deleted, defaults to none.
+    """
     source_version = Column(String(50))
     """
     Source version: `String` (limit 50 characters).
diff --git a/tests/resources/db/latest_schema.sql b/tests/resources/db/latest_schema.sql
index a9f32807e6c0c..bcf9f1d8aba35 100644
--- a/tests/resources/db/latest_schema.sql
+++ b/tests/resources/db/latest_schema.sql
@@ -76,10 +76,11 @@ CREATE TABLE runs (
 	lifecycle_stage VARCHAR(20),
 	artifact_uri VARCHAR(200),
 	experiment_id INTEGER,
+	delete_time BIGINT,
 	CONSTRAINT run_pk PRIMARY KEY (run_uuid),
 	FOREIGN KEY(experiment_id) REFERENCES experiments (experiment_id),
-	CONSTRAINT source_type CHECK (source_type IN ('NOTEBOOK', 'JOB', 'LOCAL', 'UNKNOWN', 'PROJECT')),
 	CONSTRAINT runs_lifecycle_stage CHECK (lifecycle_stage IN ('active', 'deleted')),
+	CONSTRAINT source_type CHECK (source_type IN ('NOTEBOOK', 'JOB', 'LOCAL', 'UNKNOWN', 'PROJECT')),
 	CHECK (status IN ('SCHEDULED', 'FAILED', 'FINISHED', 'RUNNING', 'KILLED'))
 )
 
diff --git a/tests/store/tracking/test_file_store.py b/tests/store/tracking/test_file_store.py
index c8f365c1f109d..0d7f20ca4ccb5 100644
--- a/tests/store/tracking/test_file_store.py
+++ b/tests/store/tracking/test_file_store.py
@@ -92,6 +92,7 @@ def _create_root(self, root):
                     "status": random.choice(RunStatus.all_status()),
                     "start_time": random_int(1, 10),
                     "end_time": random_int(20, 30),
+                    "delete_time": random_int(20, 30),
                     "tags": [],
                     "artifact_uri": os.path.join(run_folder, FileStore.ARTIFACTS_FOLDER_NAME),
                 }
@@ -519,8 +520,10 @@ def test_delete_restore_run(self):
         assert fs.get_run(run_id).info.lifecycle_stage == "active"
         fs.delete_run(run_id)
         assert fs.get_run(run_id).info.lifecycle_stage == "deleted"
+        assert fs.get_run(run_id).info.delete_time is not None
         fs.restore_run(run_id)
         assert fs.get_run(run_id).info.lifecycle_stage == "active"
+        assert fs.get_run(run_id).info.delete_time is None
 
     def test_hard_delete_run(self):
         fs = FileStore(self.test_root)
diff --git a/tests/store/tracking/test_sqlalchemy_store.py b/tests/store/tracking/test_sqlalchemy_store.py
index a8d96dd7440f4..51ef27cf360fe 100644
--- a/tests/store/tracking/test_sqlalchemy_store.py
+++ b/tests/store/tracking/test_sqlalchemy_store.py
@@ -284,6 +284,7 @@ def test_delete_restore_experiment_with_runs(self):
         self.assertEqual(len(restored_run_list), 2)
         for restored_run in restored_run_list:
             self.assertEqual(restored_run.lifecycle_stage, entities.LifecycleStage.ACTIVE)
+            self.assertTrue(restored_run.delete_time is None)
             self.assertTrue(restored_run.experiment_id in experiment_id)
             self.assertTrue(restored_run.run_id in run_ids)
 
@@ -743,6 +744,7 @@ def test_run_info(self):
             "entry_point_name": "main.py",
             "start_time": int(time.time()),
             "end_time": int(time.time()),
+            "delete_time": int(time.time()),
             "source_version": mlflow.__version__,
             "lifecycle_stage": entities.LifecycleStage.ACTIVE,
             "artifact_uri": "//",
@@ -829,6 +831,9 @@ def test_delete_run(self):
         with self.store.ManagedSessionMaker() as session:
             actual = session.query(models.SqlRun).filter_by(run_uuid=run.info.run_id).first()
             self.assertEqual(actual.lifecycle_stage, entities.LifecycleStage.DELETED)
+            self.assertTrue(
+                actual.delete_time is not None
+            )  # delete time should be updated and thus not None anymore
 
             deleted_run = self.store.get_run(run.info.run_id)
             self.assertEqual(actual.run_uuid, deleted_run.info.run_id)
@@ -1244,6 +1249,7 @@ def test_delete_restore_run(self):
         restored = self.store.get_run(run.info.run_id)
         self.assertEqual(restored.info.run_id, run.info.run_id)
         self.assertEqual(restored.info.lifecycle_stage, entities.LifecycleStage.ACTIVE)
+        self.assertTrue(restored.info.delete_time is None)
 
     def test_error_logging_to_deleted_run(self):
         exp = self._experiment_factory("error_logging")
@@ -2335,6 +2341,7 @@ def test_get_attribute_name():
     assert models.SqlRun.get_attribute_name("status") == "status"
     assert models.SqlRun.get_attribute_name("start_time") == "start_time"
     assert models.SqlRun.get_attribute_name("end_time") == "end_time"
+    assert models.SqlRun.get_attribute_name("delete_time") == "delete_time"
 
     # we want this to break if a searchable or orderable attribute has been added
     # and not referred to in this test
diff --git a/tests/test_cli.py b/tests/test_cli.py
index 6256d49003ba5..b6b7d1deb4e3c 100644
--- a/tests/test_cli.py
+++ b/tests/test_cli.py
@@ -237,6 +237,43 @@ def test_mlflow_gc_not_deleted_run(file_store):
     assert len(runs) == 1
 
 
+def test_mlflow_gc_older_than(file_store):
+    store = file_store[0]
+    run = _create_run_in_store(store)
+    store.delete_run(run.info.run_uuid)
+    with pytest.raises(subprocess.CalledProcessError, match=r".+"):
+        subprocess.check_output(
+            [
+                "mlflow",
+                "gc",
+                "--backend-store-uri",
+                file_store[1],
+                "--older-than",
+                "10d10h10m10s",
+                "--run-ids",
+                run.info.run_uuid,
+            ]
+        )
+    runs = store.search_runs(experiment_ids=["0"], filter_string="", run_view_type=ViewType.ALL)
+    assert len(runs) == 1
+
+    time.sleep(1)
+    subprocess.check_output(
+        [
+            "mlflow",
+            "gc",
+            "--backend-store-uri",
+            file_store[1],
+            "--older-than",
+            "1s",
+            "--run-ids",
+            run.info.run_uuid,
+        ]
+    )
+    runs = store.search_runs(experiment_ids=["0"], filter_string="", run_view_type=ViewType.ALL)
+    assert len(runs) == 0
+
+
 @pytest.mark.parametrize(
     "enable_mlserver",
     [


Code review comments:
diff_hunk: @@ -636,6 +636,9 @@ message RunInfo {
   // Unix timestamp of when the run ended in milliseconds.
   optional int64 end_time = 9;
 
+  // Unix timestamp of when the run is deleted in milliseconds.
+  optional int64 delete_time = 10;
+
path: mlflow/protos/service.proto
text: @user2:
@user1-CKY Rather than introducing a change to the `RunInfo` entity / proto, which has a larger change footprint that includes implementation work across several third-party MLflow services, can we start by adding the `delete_time` column / attribute to the SQLAlchemyStore / FileStore without modifying the proto? In the future, we may choose to extend the proto.

@author:
I understand. we can start with small changes first. I changed the proto as it was causing some of the test cases to fail, but i'll revert the changes to protos!