77 */ 
88namespace  OCA \Files_Trashbin \BackgroundJob ;
99
10+ use  OC \Files \SetupManager ;
1011use  OC \Files \View ;
1112use  OCA \Files_Trashbin \Expiration ;
1213use  OCA \Files_Trashbin \Helper ;
1314use  OCA \Files_Trashbin \Trashbin ;
1415use  OCP \AppFramework \Utility \ITimeFactory ;
1516use  OCP \BackgroundJob \TimedJob ;
1617use  OCP \IAppConfig ;
18+ use  OCP \IUser ;
1719use  OCP \IUserManager ;
20+ use  OCP \Lock \ILockingProvider ;
1821use  Psr \Log \LoggerInterface ;
1922
2023class  ExpireTrash extends  TimedJob {
24+ 	private  const  THIRTY_MINUTES  = 30  * 60 ;
25+ 	private  const  USER_BATCH_SIZE  = 10 ;
26+ 
2127	public  function  __construct (
2228		private  IAppConfig $ appConfig
2329		private  IUserManager $ userManager
2430		private  Expiration $ expiration
2531		private  LoggerInterface $ logger
32+ 		private  SetupManager $ setupManager
33+ 		private  ILockingProvider $ lockingProvider
2634		ITimeFactory $ time
2735	) {
2836		parent ::__construct ($ time
29- 		// Run once per 30 minutes 
30- 		$ this setInterval (60  * 30 );
37+ 		$ this setInterval (self ::THIRTY_MINUTES );
3138	}
3239
3340	protected  function  run ($ argument
@@ -41,48 +48,86 @@ protected function run($argument) {
4148			return ;
4249		}
4350
44- 		$ stopTimetime () + 60  * 30 ; // Stops after 30 minutes. 
45- 		$ offset$ this appConfig ->getValueInt ('files_trashbin ' , 'background_job_expire_trash_offset ' , 0 );
46- 		$ users$ this userManager ->getSeenUsers ($ offset
51+ 		$ stopTimetime () + self ::THIRTY_MINUTES ;
4752
48- 		foreach  ($ usersas  $ user
49- 			try  {
53+ 		do  {
54+ 			$ offset$ this getNextOffset ();
55+ 			$ users$ this userManager ->getSeenUsers ($ offsetself ::USER_BATCH_SIZE );
56+ 			$ count0 ;
57+ 
58+ 			foreach  ($ usersas  $ user
5059				$ uid$ usergetUID ();
51- 				if  (!$ this setupFS ($ uid
52- 					continue ;
60+ 				$ count
61+ 
62+ 				try  {
63+ 					if  ($ this setupFS ($ user
64+ 						$ dirContentgetTrashFiles ('/ ' , $ uid'mtime ' );
65+ 						Trashbin::deleteExpiredFiles ($ dirContent$ uid
66+ 					}
67+ 				} catch  (\Throwable   $ e
68+ 					$ this logger ->error ('Error while expiring trashbin for user  '  . $ uid'exception '  => $ e
69+ 				} finally  {
70+ 					$ this setupManager ->tearDown ();
5371				}
54- 				$ dirContentgetTrashFiles ('/ ' , $ uid'mtime ' );
55- 				Trashbin::deleteExpiredFiles ($ dirContent$ uid
56- 			} catch  (\Throwable   $ e
57- 				$ this logger ->error ('Error while expiring trashbin for user  '  . $ usergetUID (), ['exception '  => $ e
5872			}
5973
60- 			 $ offset ++ ;
74+ 		}  while  ( time () <  $ stopTime  &&  $ count  ===  self :: USER_BATCH_SIZE ) ;
6175
62- 			if  ($ stopTimetime ()) {
63- 				$ this appConfig ->setValueInt ('files_trashbin ' , 'background_job_expire_trash_offset ' , $ offset
64- 				\OC_Util::tearDownFS ();
65- 				return ;
66- 			}
76+ 		if  ($ countself ::USER_BATCH_SIZE ) {
77+ 			$ this resetOffset ();
6778		}
68- 
69- 		$ this appConfig ->setValueInt ('files_trashbin ' , 'background_job_expire_trash_offset ' , 0 );
70- 		\OC_Util::tearDownFS ();
7179	}
7280
7381	/** 
7482	 * Act on behalf on trash item owner 
7583	 */ 
76- 	protected  function  setupFS (string  $ userbool  {
77- 		\OC_Util::tearDownFS ();
78- 		\OC_Util::setupFS ($ user
84+ 	protected  function  setupFS (IUser $ userbool  {
85+ 		$ this setupManager ->setupForUser ($ user
7986
8087		// Check if this user has a trashbin directory 
81- 		$ viewnew  View ('/ '  . $ user
88+ 		$ viewnew  View ('/ '  . $ user-> getUID () );
8289		if  (!$ viewis_dir ('/files_trashbin/files ' )) {
8390			return  false ;
8491		}
8592
8693		return  true ;
8794	}
95+ 
96+ 	private  function  getNextOffset (): int  {
97+ 		return  $ this runMutexOperation (function () {
98+ 			$ this appConfig ->clearCache ();
99+ 
100+ 			$ offset$ this appConfig ->getValueInt ('files_trashbin ' , 'background_job_expire_trash_offset ' , 0 );
101+ 			$ this appConfig ->setValueInt ('files_trashbin ' , 'background_job_expire_trash_offset ' , $ offsetself ::USER_BATCH_SIZE );
102+ 
103+ 			return  $ offset
104+ 		});
105+ 
106+ 	}
107+ 
108+ 	private  function  resetOffset () {
109+ 		$ this runMutexOperation (function () {
110+ 			$ this appConfig ->setValueInt ('files_trashbin ' , 'background_job_expire_trash_offset ' , 0 );
111+ 		});
112+ 	}
113+ 
114+ 	private  function  runMutexOperation ($ operationmixed  {
115+ 		$ acquiredfalse ;
116+ 
117+ 		while  ($ acquiredfalse ) {
118+ 			try  {
119+ 				$ this lockingProvider ->acquireLock ('background_job_expire_trash ' , ILockingProvider::LOCK_EXCLUSIVE , 'Expire trashbin background job ' );
120+ 				$ acquiredtrue ;
121+ 			} catch  (\OCP \Lock \LockedException   $ e
122+ 				// wait a bit and try again 
123+ 				usleep (100000 );
124+ 			}
125+ 		}
126+ 
127+ 		$ result$ operation
128+ 
129+ 		$ this lockingProvider ->releaseLock ('background_job_expire_trash ' , ILockingProvider::LOCK_EXCLUSIVE );
130+ 
131+ 		return  $ result
132+ 	}
88133}
0 commit comments