I poked around in the file header page, as suggested by Martin Smith in the comments. I think this is part of the answer, but it's mostly speculation based on observing changes to the file header page flag values between performing shrinks and other operations.
First I created a database to test with, including a secondary filegroup:
CREATE DATABASE [Shrinkfile_Test]
ON PRIMARY
(
NAME = N'Shrinkfile_Test',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\Shrinkfile_Test.mdf',
SIZE = 8192KB,
FILEGROWTH = 65536KB
),
FILEGROUP [SECONDARY]
(
NAME = N'ShrinkFile_Test_Secondary',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\ShrinkFile_Test_Secondary.ndf',
SIZE = 1024KB,
FILEGROWTH = 65536KB
)
LOG ON
(
NAME = N'Shrinkfile_Test_log',
FILENAME = N'C:\Program Files\Microsoft SQL Server\MSSQL13.SQL2016\MSSQL\DATA\Shrinkfile_Test_log.ldf',
SIZE = 73728KB,
FILEGROWTH = 65536KB
)
GO
USE Shrinkfile_Test;
GO
The I looked at "page 0" for the secondary file, which is file_id 3:
DBCC TRACEON (3604);
GO
DBCC PAGE (N'Shrinkfile_Test', 3, 0, 3);
There's a field called m_flagBits
that has a value of 0x208
.
If I empty this file:
DBCC SHRINKFILE (N'ShrinkFile_Test_Secondary' , EMPTYFILE);
That m_flagbits
field stays the same (0x208
). Not that interesting, but now I'm in the situation you reported: if I try to empty the file again, I get this error:
File ID 3 of database ID 19 cannot be shrunk as it is either being shrunk by another process or is empty.
I'll try growing the file (the solution that worked for you):
ALTER DATABASE ShrinkFile_Test
MODIFY FILE
(
NAME = ShrinkFile_Test_Secondary,
SIZE = 1025KB
);
GO
Now m_flagbits
is 0x8
!
At this point, emptying the file again is successful returns the value to 0x208
as you might expect.
The thing that I find interesting is that if I do this after growing the file back out (AKA flagbits value is 0x8
):
USE [master]
GO
ALTER DATABASE [Shrinkfile_Test] MODIFY FILEGROUP [SECONDARY] READONLY
GO
The file is marked as is_read_only
in the sys.databases
table, and m_flagbits
is set back to 0x208
. So it appears there is some similar file-level flag set when shrinking a file and when setting it to read only.
My best guess is that this value is used along with some other (internal) flag to indicate that a file is eligible to be shrunk. Growing the file appears to un-set that flag (at least the one visible in m_flagbits
).