@@ -5,7 +5,7 @@ use crate::{
5
5
db:: { Pool , PoolClient } ,
6
6
impl_webpage,
7
7
web:: { error:: Nope , match_version, page:: WebPage , redirect_base} ,
8
- BuildQueue ,
8
+ BuildQueue , Config ,
9
9
} ;
10
10
use chrono:: { DateTime , Utc } ;
11
11
use iron:: {
@@ -498,13 +498,18 @@ impl Default for Search {
498
498
}
499
499
500
500
fn redirect_to_random_crate ( req : & Request , conn : & mut PoolClient ) -> IronResult < Response > {
501
- // since there is a chance of this query returning an empty result,
502
- // we retry a certain amount of times, and log a warning.
503
- for i in 0 ..20 {
504
- let rows = ctry ! (
505
- req,
506
- conn. query(
507
- "WITH params AS (
501
+ // We try to find a random crate and redirect to it.
502
+ //
503
+ // The query is efficient, but relies on a static factor which depends
504
+ // on the amount of crates with > 100 GH stars over the amount of all crates.
505
+ //
506
+ // If random-crate-searches end up being empty, increase that value.
507
+
508
+ let config = extension ! ( req, Config ) ;
509
+ let rows = ctry ! (
510
+ req,
511
+ conn. query(
512
+ "WITH params AS (
508
513
-- get maximum possible id-value in crates-table
509
514
SELECT last_value AS max_id FROM crates_id_seq
510
515
)
@@ -513,55 +518,44 @@ fn redirect_to_random_crate(req: &Request, conn: &mut PoolClient) -> IronResult<
513
518
releases.version,
514
519
releases.target_name
515
520
FROM (
516
- -- generate 500 random numbers in the ID-range.
517
- -- this might have to be increased when we have to repeat
518
- -- this query too often.
519
- -- it depends on the percentage of crates with > 100 stars
521
+ -- generate random numbers in the ID-range.
520
522
SELECT DISTINCT 1 + trunc(random() * params.max_id)::INTEGER AS id
521
- FROM params, generate_series(1, 500 )
523
+ FROM params, generate_series(1, $1 )
522
524
) AS r
523
525
INNER JOIN crates ON r.id = crates.id
524
526
INNER JOIN releases ON crates.latest_version_id = releases.id
525
527
INNER JOIN github_repos ON releases.github_repo = github_repos.id
526
528
WHERE
527
529
releases.rustdoc_status = TRUE AND
528
530
github_repos.stars >= 100
529
- LIMIT 1
530
- " ,
531
- & [ ]
532
- ) ,
533
- ) ;
534
-
535
- if let Some ( row) = rows. into_iter ( ) . next ( ) {
536
- let name: String = row. get ( "name" ) ;
537
- let version: String = row. get ( "version" ) ;
538
- let target_name: String = row. get ( "target_name" ) ;
539
- let url = ctry ! (
540
- req,
541
- Url :: parse( & format!(
542
- "{}/{}/{}/{}/" ,
543
- redirect_base( req) ,
544
- name,
545
- version,
546
- target_name
547
- ) ) ,
548
- ) ;
531
+ LIMIT 1" ,
532
+ & [ & ( config. random_crate_search_view_size as i32 ) ]
533
+ )
534
+ ) ;
549
535
550
- let mut resp = Response :: with ( ( status:: Found , Redirect ( url) ) ) ;
551
- resp. headers . set ( Expires ( HttpDate ( time:: now ( ) ) ) ) ;
536
+ if let Some ( row) = rows. into_iter ( ) . next ( ) {
537
+ let name: String = row. get ( "name" ) ;
538
+ let version: String = row. get ( "version" ) ;
539
+ let target_name: String = row. get ( "target_name" ) ;
540
+ let url = ctry ! (
541
+ req,
542
+ Url :: parse( & format!(
543
+ "{}/{}/{}/{}/" ,
544
+ redirect_base( req) ,
545
+ name,
546
+ version,
547
+ target_name
548
+ ) ) ,
549
+ ) ;
552
550
553
- let metrics = extension ! ( req, crate :: Metrics ) . clone ( ) ;
554
- metrics. im_feeling_lucky_searches . inc ( ) ;
551
+ let metrics = extension ! ( req, crate :: Metrics ) . clone ( ) ;
552
+ metrics. im_feeling_lucky_searches . inc ( ) ;
555
553
556
- log:: debug!( "finished random crate search on iteration {}" , i) ;
557
- return Ok ( resp) ;
558
- } else {
559
- log:: warn!( "retrying random crate search" ) ;
560
- }
554
+ Ok ( super :: redirect ( url) )
555
+ } else {
556
+ log:: error!( "found no result in random crate search" ) ;
557
+ Err ( Nope :: NoResults . into ( ) )
561
558
}
562
- log:: error!( "found no result in random crate search" ) ;
563
-
564
- Err ( Nope :: NoResults . into ( ) )
565
559
}
566
560
567
561
impl_webpage ! {
@@ -1095,6 +1089,18 @@ mod tests {
1095
1089
#[ test]
1096
1090
fn im_feeling_lucky_with_stars ( ) {
1097
1091
wrapper ( |env| {
1092
+ {
1093
+ // The normal test-setup will offset all primary sequences by 10k
1094
+ // to prevent errors with foreign key relations.
1095
+ // Random-crate-search relies on the sequence for the crates-table
1096
+ // to find a maximum possible ID. This combined with only one actual
1097
+ // crate in the db breaks this test.
1098
+ // That's why we reset the id-sequence to zero for this test.
1099
+
1100
+ let mut conn = env. db ( ) . conn ( ) ;
1101
+ conn. execute ( r#"ALTER SEQUENCE crates_id_seq RESTART WITH 1"# , & [ ] ) ?;
1102
+ }
1103
+
1098
1104
let web = env. frontend ( ) ;
1099
1105
env. fake_release ( )
1100
1106
. github_stats ( "some/repo" , 333 , 22 , 11 )
0 commit comments