Skip to content

Commit

Permalink
fix(license): ignore access event when watching license key file chan…
Browse files Browse the repository at this point in the history
…ges (#20122)

Signed-off-by: Bugen Zhao <[email protected]>
  • Loading branch information
BugenZhao authored Jan 13, 2025
1 parent b3de6d1 commit c6ab2f8
Showing 1 changed file with 29 additions and 8 deletions.
37 changes: 29 additions & 8 deletions src/meta/src/manager/license.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;

use anyhow::Context;
use notify::Watcher;
use risingwave_common::system_param::LICENSE_KEY_KEY;
Expand All @@ -22,6 +25,9 @@ use tokio::task::JoinHandle;
use super::MetaSrvEnv;
use crate::MetaResult;

/// For test purposes, we count the number of times the license key file is reloaded.
static RELOAD_TIMES: AtomicUsize = AtomicUsize::new(0);

impl MetaSrvEnv {
/// Spawn background tasks to watch the license key file and update the system parameter,
/// if configured.
Expand All @@ -36,15 +42,22 @@ impl MetaSrvEnv {

let mut watcher =
notify::recommended_watcher(move |event: Result<notify::Event, notify::Error>| {
if let Err(e) = event {
tracing::warn!(
error = %e.as_report(),
"error occurred while watching license key file"
);
return;
match event {
Ok(event) => {
if event.kind.is_access() {
// Ignore access events as they do not indicate changes and will be
// triggered on our own read operations.
} else {
let _ = changed_tx.send(());
}
}
Err(e) => {
tracing::warn!(
error = %e.as_report(),
"error occurred while watching license key file"
);
}
}
// We don't check the event type but always notify the updater for simplicity.
let _ = changed_tx.send(());
})
.context("failed to create license key file watcher")?;

Expand All @@ -56,6 +69,7 @@ impl MetaSrvEnv {
let updater = {
let mgr = self.system_params_manager_impl_ref();
let path = path.to_path_buf();

async move {
// Let the watcher live until the end of the updater to prevent dropping (then stopping).
let _watcher = watcher;
Expand All @@ -65,6 +79,7 @@ impl MetaSrvEnv {
// will do the initialization then.
while changed_rx.changed().await.is_ok() {
tracing::info!(path = %path.display(), "license key file changed, reloading...");
RELOAD_TIMES.fetch_add(1, Relaxed);

let content = match tokio::fs::read_to_string(&path).await {
Ok(v) => v,
Expand Down Expand Up @@ -144,14 +159,20 @@ mod tests {

// Since we've filled the key file with the initial key, the license should be loaded.
tokio::time::sleep(Duration::from_secs(1)).await;
assert_eq!(RELOAD_TIMES.load(Relaxed), 1);
let license = LicenseManager::get().license().unwrap();
assert_eq!(license.sub, "rw-test");
assert_eq!(license.tier, Tier::Free);

// Update the key file with an empty content, which should reset the license to the default.
std::fs::write(key_file.path(), "").unwrap();
tokio::time::sleep(Duration::from_secs(1)).await;
assert_eq!(RELOAD_TIMES.load(Relaxed), 2);
let license = LicenseManager::get().license().unwrap();
assert_eq!(license, License::default());

// Show that our "access" on the key file does not trigger a reload recursively.
tokio::time::sleep(Duration::from_secs(3)).await;
assert_eq!(RELOAD_TIMES.load(Relaxed), 2);
}
}

0 comments on commit c6ab2f8

Please sign in to comment.